ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilSoapTestAdministration.php
Go to the documentation of this file.
1<?php
2
21
30{
32 public function __construct(bool $use_nusoap = true)
33 {
34 $this->questionrepository = TestDIC::dic()['general_question_properties_repository'];
35 parent::__construct($use_nusoap);
36 }
37 private function hasWritePermissionForTest(int $active_id): bool
38 {
39 global $DIC;
40
41 $ilDB = $DIC['ilDB'];
42 global $DIC;
43
44 $ilAccess = $DIC['ilAccess'];
45
46 $permission_ok = false;
47 $result = $ilDB->queryF(
48 "SELECT tst_tests.obj_fi FROM tst_active, tst_tests WHERE tst_active.active_id = %s AND tst_active.test_fi = tst_tests.test_id",
49 array('integer'),
50 array($active_id)
51 );
52 $row = $ilDB->fetchAssoc($result);
53 if ($row['obj_fi']) {
54 $obj_id = $row['obj_fi'];
55 foreach ($ref_ids = ilObject::_getAllReferences($obj_id) as $ref_id) {
56 if ($ilAccess->checkAccess("write", "", $ref_id)) {
57 $permission_ok = true;
58 break;
59 }
60 }
61 }
62 return $permission_ok;
63 }
64
65 public function isAllowedCall(string $sid, int $active_id, bool $saveaction = true): bool
66 {
67 global $DIC;
68
69 $ilDB = $DIC['ilDB'];
70 global $DIC;
71
72 $ilUser = $DIC['ilUser'];
73
74 if ($this->hasWritePermissionForTest($active_id)) {
75 return true;
76 }
77
78 if ($saveaction) {
79 $result = $ilDB->queryF(
80 "SELECT * FROM tst_times WHERE active_fi = %s ORDER BY started DESC",
81 array('integer'),
82 array($active_id)
83 );
84 if ($result->numRows()) {
85 $row = $ilDB->fetchAssoc($result);
86 if (preg_match("/(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})/", $row["started"], $matches)) {
87 $time = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
88 $now = time();
89 $diff = $now - $time;
90 $client = explode("::", $sid);
91 global $DIC;
92
93 $ilClientIniFile = $DIC['ilClientIniFile'];
94 $expires = $ilClientIniFile->readVariable('session', 'expire');
95 return $diff <= $expires;
96 }
97
98 return false;
99 }
100
101 return false;
102 }
103
104 $result = $ilDB->queryF(
105 "SELECT user_fi FROM tst_active WHERE active_id = %s",
106 array('integer'),
107 array($active_id)
108 );
109 $row = $ilDB->fetchAssoc($result);
110
111 return (int) $row['user_fi'] === $ilUser->getId();
112 }
113
117 public function saveQuestion(string $sid, int $active_id, int $question_id, int $pass, array $solution)
118 {
119 $this->initAuth($sid);
120 $this->initIlias();
121
122 if (!$this->checkSession($sid)) {
123 return $this->raiseError($this->getMessage(), $this->getMessageCode());
124 }
125 if (!$this->isAllowedCall($sid, $active_id)) {
126 return $this->raiseError("The required user information is only available for active users.", "");
127 }
128
129 global $DIC;
130
131 $ilDB = $DIC['ilDB'];
132 $ilUser = $DIC['ilUser'];
133
134 $processLockerFactory = new ilAssQuestionProcessLockerFactory(new ilSetting('assessment'), $ilDB);
135 $processLockerFactory->setQuestionId($question_id);
136 $processLockerFactory->setUserId($ilUser->getId());
137 $processLocker = $processLockerFactory->getLocker();
138
139 $totalrows = 0;
140
141 $processLocker->executePersistWorkingStateLockOperation(function () use (
142 &$totalrows,
143 $processLocker,
144 $active_id,
145 $question_id,
146 $pass,
147 $solution
148 ) {
149 $processLocker->executeUserSolutionUpdateLockOperation(function () use (
150 &$totalrows,
151 $active_id,
152 $question_id,
153 $pass,
154 $solution
155 ) {
156 $ilDB = $GLOBALS['DIC']['ilDB'];
157 if (($active_id > 0) && ($question_id > 0) && ($pass > 0)) {
158 $affectedRows = $ilDB->manipulateF(
159 "DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
160 array('integer', 'integer', 'integer'),
161 array($active_id, $question_id, $pass)
162 );
163 }
164 for ($i = 0, $iMax = count($solution); $i < $iMax; $i += 3) {
165 $next_id = $ilDB->nextId('tst_solutions');
166 $affectedRows = $ilDB->insert("tst_solutions", array(
167 "solution_id" => array("integer", $next_id),
168 "active_fi" => array("integer", $active_id),
169 "question_fi" => array("integer", $question_id),
170 "value1" => array("clob", $solution[$i]),
171 "value2" => array("clob", $solution[$i + 1]),
172 "points" => array("float", $solution[$i + 2]),
173 "pass" => array("integer", $pass),
174 "tstamp" => array("integer", time())
175 ));
176 $totalrows += $affectedRows;
177 }
178 });
179
180 if ($totalrows !== 0) {
181 $question = assQuestion::instantiateQuestion($question_id);
182 $question->setProcessLocker($processLocker);
183 $question->calculateResultsFromSolution($active_id, $pass);
184 }
185 });
186
187 if ($totalrows === 0) {
188 return $this->raiseError(
189 "Wrong solution data. ILIAS did not execute any database queries: Solution data: " . print_r(
190 $solution,
191 true
192 ),
193 'No result'
194 );
195 }
196 return true;
197 }
198
202 public function saveQuestionSolution(string $sid, int $active_id, int $question_id, int $pass, int $solution)
203 {
204 $this->initAuth($sid);
205 $this->initIlias();
206
207 if (!$this->checkSession($sid)) {
208 return $this->raiseError($this->getMessage(), $this->getMessageCode());
209 }
210 if (!$this->isAllowedCall($sid, $active_id)) {
211 return $this->raiseError("The required user information is only available for active users.", "");
212 }
213
214 $solutions = [];
215 if (preg_match("/<values>(.*?)<\/values>/is", $solution, $matches)) {
216 if (preg_match_all(
217 "/<value>(.*?)<\/value><value>(.*?)<\/value><points>(.*?)<\/points>/is",
218 $solution,
219 $matches,
220 PREG_SET_ORDER
221 )) {
222 foreach ($matches as $match) {
223 if (count($match) === 4) {
224 for ($i = 1, $iMax = count($match); $i < $iMax; $i++) {
225 $solutions[] = trim($match[$i]);
226 }
227 }
228 }
229 }
230 }
231
232 if (count($solutions) === 0) {
233 return $this->raiseError(
234 "Wrong solution data. ILIAS did not find one or more solution triplets: $solution",
235 ""
236 );
237 }
238
239 $ilDB = $GLOBALS['DIC']['ilDB'];
240 if (($active_id > 0) && ($question_id > 0) && ($pass > 0)) {
241 $affectedRows = $ilDB->manipulateF(
242 "DELETE FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
243 array('integer', 'integer', 'integer'),
244 array($active_id, $question_id, $pass)
245 );
246 }
247 $totalrows = 0;
248 for ($i = 0, $iMax = count($solutions); $i < $iMax; $i += 3) {
249 $next_id = $ilDB->nextId('tst_solutions');
250 $affectedRows = $ilDB->insert("tst_solutions", array(
251 "solution_id" => array("integer", $next_id),
252 "active_fi" => array("integer", $active_id),
253 "question_fi" => array("integer", $question_id),
254 "value1" => array("clob", $solutions[$i]),
255 "value2" => array("clob", $solutions[$i + 1]),
256 "points" => array("float", $solutions[$i + 2]),
257 "pass" => array("integer", $pass),
258 "tstamp" => array("integer", time())
259 ));
260 $totalrows += $affectedRows;
261 }
262 if ($totalrows === 0) {
263 return $this->raiseError("Wrong solution data. ILIAS did not execute any database queries", '');
264 }
265
266 $question = assQuestion::instantiateQuestion($question_id);
267 $question->calculateResultsFromSolution($active_id, $pass);
268 return "TRUE";
269 }
270
274 public function getQuestionSolution(string $sid, int $active_id, int $question_id, int $pass)
275 {
276 $this->initAuth($sid);
277 $this->initIlias();
278
279 if (!$this->checkSession($sid)) {
280 return $this->raiseError($this->getMessage(), $this->getMessageCode());
281 }
282 if (!$this->isAllowedCall($sid, $active_id, false)) {
283 return $this->raiseError("The required user information is only available for active users.", "");
284 }
285 $solution = array();
286
287 global $DIC;
288
289 $ilDB = $DIC['ilDB'];
290
291 $use_previous_answers = 1;
292
293 $result = $ilDB->queryF(
294 "SELECT tst_tests.use_previous_answers FROM tst_tests, tst_active WHERE tst_tests.test_id = tst_active.test_fi AND tst_active.active_id = %s",
295 array('integer'),
296 array($active_id)
297 );
298 if ($result->numRows()) {
299 $row = $ilDB->fetchAssoc($result);
300 $use_previous_answers = $row["use_previous_answers"];
301 }
302 $lastpass = 0;
303 if ($use_previous_answers) {
304 $result = $ilDB->queryF(
305 "SELECT MAX(pass) maxpass FROM tst_test_result WHERE active_fi = %s AND question_fi = %s",
306 array('integer', 'integer'),
307 array($active_id, $question_id)
308 );
309 if ($result->numRows() === 1) {
310 $row = $ilDB->fetchAssoc($result);
311 $lastpass = (int) $row["maxpass"];
312 }
313 } else {
314 $lastpass = $pass;
315 }
316
317 if (($active_id > 0) && ($question_id > 0) && ($lastpass > 0)) {
318 $result = $ilDB->queryF(
319 "SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
320 array('integer', 'integer', 'integer'),
321 array($active_id, $question_id, $lastpass)
322 );
323 if ($result->numRows()) {
324 while ($row = $ilDB->fetchAssoc($result)) {
325 $solution[] = $row["value1"];
326 $solution[] = $row["value2"];
327 $solution[] = $row["points"];
328 }
329 }
330 }
331 return $solution;
332 }
333
337 public function getTestUserData(string $sid, int $active_id)
338 {
339 $this->initAuth($sid);
340 $this->initIlias();
341
342 if (!$this->checkSession($sid)) {
343 return $this->raiseError($this->getMessage(), $this->getMessageCode());
344 }
345 if (!$this->isAllowedCall($sid, $active_id, false)) {
346 return $this->raiseError("The required user information is only available for active users.", "");
347 }
348
349 global $DIC;
350
351 $lng = $DIC['lng'];
352 $ilDB = $DIC['ilDB'];
353
354 $result = $ilDB->queryF(
355 "SELECT user_fi, test_fi FROM tst_active WHERE active_id = %s",
356 array('integer'),
357 array($active_id)
358 );
359 $row = $ilDB->fetchAssoc($result);
360 $user_id = $row["user_fi"];
361 $test_id = $row["test_fi"];
362
363 $result = $ilDB->queryF(
364 "SELECT anonymity FROM tst_tests WHERE test_id = %s",
365 array('integer'),
366 array($test_id)
367 );
368 $row = $ilDB->fetchAssoc($result);
369 $anonymity = $row["anonymity"];
370
371 $result = $ilDB->queryF(
372 "SELECT firstname, lastname, title, login FROM usr_data WHERE usr_id = %s",
373 array('integer'),
374 array($user_id)
375 );
376
377 $userdata = array();
378 if ($result->numRows() === 0) {
379 $userdata["fullname"] = $lng->txt("deleted_user");
380 $userdata["title"] = "";
381 $userdata["firstname"] = "";
382 $userdata["lastname"] = $lng->txt("anonymous");
383 $userdata["login"] = "";
384 } else {
385 $data = $ilDB->fetchAssoc($result);
386 if ((int) $user_id === ANONYMOUS_USER_ID || $anonymity) {
387 $userdata["fullname"] = $lng->txt("anonymous");
388 $userdata["title"] = "";
389 $userdata["firstname"] = "";
390 $userdata["lastname"] = $lng->txt("anonymous");
391 $userdata["login"] = "";
392 } else {
393 $userdata["fullname"] = trim($data["title"] . " " . $data["firstname"] . " " . $data["lastname"]);
394 $userdata["title"] = $data["title"];
395 $userdata["firstname"] = $data["firstname"];
396 $userdata["lastname"] = $data["lastname"];
397 $userdata["login"] = $data["login"];
398 }
399 }
400 return array_values($userdata);
401 }
402
406 public function getPositionOfQuestion(string $sid, int $active_id, int $question_id, int $pass)
407 {
408 $this->initAuth($sid);
409 $this->initIlias();
410
411 if (!$this->checkSession($sid)) {
412 return $this->raiseError($this->getMessage(), $this->getMessageCode());
413 }
414 if (!$this->isAllowedCall($sid, $active_id, false)) {
415 return $this->raiseError("The required user information is only available for active users.", "");
416 }
417
418 global $DIC;
419
420 $lng = $DIC['lng'];
421 $ilDB = $DIC['ilDB'];
422
423 $result = $ilDB->queryF(
424 "SELECT tst_tests.random_test FROM tst_active, tst_tests WHERE tst_active.active_id = %s AND tst_tests.test_id = tst_active.test_fi",
425 array('integer'),
426 array($active_id)
427 );
428 if ($result->numRows() !== 1) {
429 return -1;
430 }
431 $row = $ilDB->fetchAssoc($result);
432 $is_random = $row["random_test"];
433
434 $sequence = new ilTestSequence($ilDB, $active_id, $pass, $this->questionrepository);
435 return $sequence->getSequenceForQuestion($question_id);
436 }
437
441 public function getPreviousReachedPoints(string $sid, int $active_id, int $question_id, int $pass)
442 {
443 $this->initAuth($sid);
444 $this->initIlias();
445
446 if (!$this->checkSession($sid)) {
447 return $this->raiseError($this->getMessage(), $this->getMessageCode());
448 }
449 if (!$this->isAllowedCall($sid, $active_id, false)) {
450 return $this->raiseError("The required user information is only available for active users.", "");
451 }
452
453 global $DIC;
454
455 $lng = $DIC['lng'];
456 $ilDB = $DIC['ilDB'];
457
458 $result = $ilDB->queryF(
459 "SELECT tst_tests.random_test FROM tst_active, tst_tests WHERE tst_active.active_id = %s AND tst_tests.test_id = tst_active.test_fi",
460 array('integer'),
461 array($active_id)
462 );
463 if ($result->numRows() !== 1) {
464 return -1;
465 }
466 $row = $ilDB->fetchAssoc($result);
467 $is_random = $row["random_test"];
468
469 $sequence = new ilTestSequence($ilDB, $active_id, $pass, $this->questionrepository);
470 $result = $ilDB->queryF(
471 "SELECT question_fi, points FROM tst_test_result WHERE active_fi = %s AND pass = %s",
472 array('integer', 'integer'),
473 array($active_id, $pass)
474 );
475 $reachedpoints = array();
476 while ($row = $ilDB->fetchAssoc($result)) {
477 $reachedpoints[$row["question_fi"]] = $row["points"];
478 }
479 $atposition = false;
480 $pointsforposition = array();
481 foreach ($sequence->getUserSequence() as $seq) {
482 if (!$atposition) {
483 $qid = $sequence->getQuestionForSequence($seq);
484 if ($qid == $question_id) {
485 $atposition = true;
486 } else {
487 $pointsforposition[] = $reachedpoints[$qid];
488 }
489 }
490 }
491 return $pointsforposition;
492 }
493
497 public function getNrOfQuestionsInPass(string $sid, int $active_id, int $pass)
498 {
499 $this->initAuth($sid);
500 $this->initIlias();
501
502 if (!$this->checkSession($sid)) {
503 return $this->raiseError($this->getMessage(), $this->getMessageCode());
504 }
505 if (!$this->isAllowedCall($sid, $active_id, false)) {
506 return $this->raiseError("The required user information is only available for active users.", "");
507 }
508
509 global $DIC;
510
511 $lng = $DIC['lng'];
512 $ilDB = $DIC['ilDB'];
513
514 $result = $ilDB->queryF(
515 "SELECT tst_tests.random_test FROM tst_active, tst_tests WHERE tst_active.active_id = %s AND tst_tests.test_id = tst_active.test_fi",
516 array('integer'),
517 array($active_id)
518 );
519 if ($result->numRows() !== 1) {
520 return 0;
521 }
522 $row = $ilDB->fetchAssoc($result);
523 $is_random = $row["random_test"];
524
525 $sequence = new ilTestSequence($ilDB, $active_id, $pass, $this->questionrepository);
526 return $sequence->getUserQuestionCount();
527 }
528
532 public function removeTestResults(string $sid, int $test_ref_id, array $a_user_ids)
533 {
534 $this->initAuth($sid);
535 $this->initIlias();
536
537 if (!$this->checkSession($sid)) {
538 return $this->raiseError($this->getMessage(), $this->getMessageCode());
539 }
540 if (!($test_ref_id > 0)) {
541 return $this->raiseError(
542 'No test id given. Aborting!',
543 'Client'
544 );
545 }
546 global $DIC;
547
548 $rbacsystem = $DIC['rbacsystem'];
549 $tree = $DIC['tree'];
550 $ilLog = $DIC['ilLog'];
551
552 if (!$this->checkManageParticipantsAccess($test_ref_id)) {
553 return $this->raiseError('no permission. Aborting!', 'Client');
554 }
555
556 if (ilObject::_isInTrash($test_ref_id)) {
557 return $this->raiseError(
558 'Test is trashed. Aborting!',
559 'Client'
560 );
561 }
562
563 if (!$tst = ilObjectFactory::getInstanceByRefId($test_ref_id, false)) {
564 return $this->raiseError('No test found for id: ' . $test_ref_id, 'Client');
565 }
566 if ($tst->getType() !== 'tst') {
567 return $this->raiseError(
568 'Object with ref_id ' . $test_ref_id . ' is not of type test. Aborting',
569 'Client'
570 );
571 }
572
573 // Dirty hack
574 if (isset($a_user_ids['item'])) {
575 $a_user_ids = $a_user_ids['item'];
576 }
577
578 $part = new ilTestParticipantData($GLOBALS['DIC']['ilDB'], $GLOBALS['DIC']['lng']);
579 $part->setParticipantAccessFilter(
580 ilTestParticipantAccessFilter::getManageParticipantsUserFilter($test_ref_id)
581 );
582 $part->setUserIdsFilter((array) $a_user_ids);
583 $part->load($tst->getTestId());
584 $tst->removeTestResults($part);
585
586 return true;
587 }
588
592 public function getTestResults(string $sid, int $test_ref_id, bool $sum_only)
593 {
594 $this->initAuth($sid);
595 $this->initIlias();
596
597 if (!$this->checkSession($sid)) {
598 return $this->raiseError($this->getMessage(), $this->getMessageCode());
599 }
600 if (!($test_ref_id > 0)) {
601 return $this->raiseError(
602 'No test id given. Aborting!',
603 'Client'
604 );
605 }
606 global $DIC;
607
608 $rbacsystem = $DIC['rbacsystem'];
609 $tree = $DIC['tree'];
610 $ilLog = $DIC['ilLog'];
611
612 if (ilObject::_isInTrash($test_ref_id)) {
613 return $this->raiseError(
614 'Test is trashed. Aborting!',
615 'Client'
616 );
617 }
618
619 if (!$obj_id = ilObject::_lookupObjectId($test_ref_id)) {
620 return $this->raiseError(
621 'No test found for id: ' . $test_ref_id,
622 'Client'
623 );
624 }
625
626 $permission_ok = false;
627 foreach ($ref_ids = ilObject::_getAllReferences($obj_id) as $ref_id) {
628 if ($rbacsystem->checkAccess('write', $ref_id)) {
629 $permission_ok = true;
630 break;
631 }
632 }
633 if (!$permission_ok && $this->checkParticipantsResultsAccess($test_ref_id)) {
634 $permission_ok = $this->checkParticipantsResultsAccess($test_ref_id);
635 }
636
637 if (!$permission_ok) {
638 return $this->raiseError(
639 'No permission to edit the object with id: ' . $test_ref_id,
640 'Server'
641 );
642 }
643
644 $xmlResultSet = new ilXMLResultSet();
645 $xmlResultSet->addColumn("user_id");
646 $xmlResultSet->addColumn("login");
647 $xmlResultSet->addColumn("firstname");
648 $xmlResultSet->addColumn("lastname");
649 $xmlResultSet->addColumn("matriculation");
650
651 $test_obj = new ilObjTest($obj_id, false);
652 $participants = $test_obj->getTestParticipants();
653
654 $accessFilter = ilTestParticipantAccessFilter::getAccessResultsUserFilter($test_ref_id);
655 $participantList = new ilTestParticipantList($test_obj);
656 $participantList->initializeFromDbRows($participants);
657 $participantList = $participantList->getAccessFilteredList($accessFilter);
658 $participantList = $participantList->getScoredParticipantList();
659 foreach ($participants as $activeId => $part) {
660 if ($participantList->isActiveIdInList($activeId)) {
661 $participants[$activeId]['passed'] = $participantList->getParticipantByActiveId($activeId)->getScoring()->isPassed();
662 continue;
663 }
664
665 unset($participants[$activeId]);
666 }
667
668 if ($sum_only) {
669 $data = $test_obj->getAllTestResults($participants);
670
671 $xmlResultSet->addColumn("maximum_points");
672 $xmlResultSet->addColumn("received_points");
673 $xmlResultSet->addColumn("passed");
674 // skip titles
675 $titles = array_shift($data);
676 foreach ($data as $row) {
677 $xmlRow = new ilXMLResultSetRow();
678 $xmlRow->setValue(0, $row["user_id"]);
679 $xmlRow->setValue(1, $row["login"]);
680 $xmlRow->setValue(2, $row["firstname"]);
681 $xmlRow->setValue(3, $row["lastname"]);
682 $xmlRow->setValue(4, $row["matriculation"]);
683 $xmlRow->setValue(5, $row["max_points"]);
684 $xmlRow->setValue(6, $row["reached_points"]);
685 $xmlRow->setValue(7, $row["passed"]);
686 $xmlResultSet->addRow($xmlRow);
687 }
688 } else {
689 $data = $test_obj->getDetailedTestResults($participants);
690
691 $xmlResultSet->addColumn("question_id");
692 $xmlResultSet->addColumn("question_title");
693 $xmlResultSet->addColumn("maximum_points");
694 $xmlResultSet->addColumn("received_points");
695 $xmlResultSet->addColumn("passed");
696 foreach ($data as $row) {
697 $xmlRow = new ilXMLResultSetRow();
698 $xmlRow->setValue(0, $row["user_id"]);
699 $xmlRow->setValue(1, $row["login"]);
700 $xmlRow->setValue(2, $row["firstname"]);
701 $xmlRow->setValue(3, $row["lastname"]);
702 $xmlRow->setValue(4, $row["matriculation"]);
703 $xmlRow->setValue(5, $row["question_id"]);
704 $xmlRow->setValue(6, $row["question_title"]);
705 $xmlRow->setValue(7, $row["max_points"]);
706 $xmlRow->setValue(8, $row["reached_points"]);
707 $xmlRow->setValue(9, $row["passed"]);
708 $xmlResultSet->addRow($xmlRow);
709 }
710 }
711
712 $xmlWriter = new ilXMLResultSetWriter($xmlResultSet);
713 $xmlWriter->start();
714 return $xmlWriter->getXML();
715 }
716
717 protected function checkManageParticipantsAccess(int $refId): bool
718 {
719 return $this->getTestAccess($refId)->checkManageParticipantsAccess();
720 }
721
722 protected function checkParticipantsResultsAccess(int $refId): bool
723 {
724 return $this->getTestAccess($refId)->checkParticipantsResultsAccess();
725 }
726
727 protected function getTestAccess(int $refId): ilTestAccess
728 {
729
731 return new ilTestAccess($refId, $testId);
732 }
733}
static instantiateQuestion(int $question_id)
static _getTestIDFromObjectID(int $object_id)
Returns the ILIAS test id for a given object id.
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
static _lookupObjectId(int $ref_id)
static _getAllReferences(int $id)
get all reference ids for object ID
static _isInTrash(int $ref_id)
ILIAS Setting Class.
raiseError(string $a_message, $a_code)
saveQuestionSolution(string $sid, int $active_id, int $question_id, int $pass, int $solution)
getPreviousReachedPoints(string $sid, int $active_id, int $question_id, int $pass)
isAllowedCall(string $sid, int $active_id, bool $saveaction=true)
saveQuestion(string $sid, int $active_id, int $question_id, int $pass, array $solution)
getQuestionSolution(string $sid, int $active_id, int $question_id, int $pass)
getPositionOfQuestion(string $sid, int $active_id, int $question_id, int $pass)
removeTestResults(string $sid, int $test_ref_id, array $a_user_ids)
getTestResults(string $sid, int $test_ref_id, bool $sum_only)
GeneralQuestionPropertiesRepository $questionrepository
getTestUserData(string $sid, int $active_id)
getNrOfQuestionsInPass(string $sid, int $active_id, int $pass)
Test sequence handler.
Row Class for XMLResultSet.
XML Writer for XMLResultSet.
const ANONYMOUS_USER_ID
Definition: constants.php:27
$client
$ref_id
Definition: ltiauth.php:66
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
global $lng
Definition: privfeed.php:31
global $DIC
Definition: shib_login.php:26
$GLOBALS["DIC"]
Definition: wac.php:54
$refId
Definition: xapitoken.php:58