ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
class.DBUpdateTestResultCalculator.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4define("SCORE_LAST_PASS", 0);
5define("SCORE_BEST_PASS", 1);
6
14{
18 const QUESTION_SET_TYPE_FIXED = 'FIXED_QUEST_SET';
19
23 const QUESTION_SET_TYPE_RANDOM = 'RANDOM_QUEST_SET';
24
28 const QUESTION_SET_TYPE_DYNAMIC = 'DYNAMIC_QUEST_SET';
29
30 public static function _updateTestPassResults($active_id, $pass, $obligationsEnabled, $questionSetType, $objId)
31 {
32 global $ilDB;
33
36
37 // update test pass results
38
39 $result = $ilDB->queryF(
40 "
41 SELECT SUM(points) reachedpoints,
42 SUM(hint_count) hint_count,
43 SUM(hint_points) hint_points,
44 COUNT(DISTINCT(question_fi)) answeredquestions
45 FROM tst_test_result
46 WHERE active_fi = %s
47 AND pass = %s
48 ",
49 array('integer','integer'),
50 array($active_id, $pass)
51 );
52
53 if ($result->numRows() > 0) {
54 if ($obligationsEnabled) {
55 $query = '
56 SELECT count(*) cnt,
57 min( answered ) answ
58 FROM tst_test_question
59 INNER JOIN tst_active
60 ON active_id = %s
61 AND tst_test_question.test_fi = tst_active.test_fi
62 LEFT JOIN tst_test_result
63 ON tst_test_result.active_fi = %s
64 AND tst_test_result.pass = %s
65 AND tst_test_question.question_fi = tst_test_result.question_fi
66 WHERE obligatory = 1';
67
68 $result_obligatory = $ilDB->queryF(
69 $query,
70 array('integer','integer','integer'),
71 array($active_id, $active_id, $pass)
72 );
73
74 $row_obligatory = $ilDB->fetchAssoc($result_obligatory);
75
76 if ($row_obligatory['cnt'] == 0) {
77 $obligations_answered = 1;
78 } else {
79 $obligations_answered = (int) $row_obligatory['answ'];
80 }
81 } else {
82 $obligations_answered = 1;
83 }
84
85 $row = $ilDB->fetchAssoc($result);
86
87 if ($row['hint_count'] === null) {
88 $row['hint_count'] = 0;
89 }
90 if ($row['hint_points'] === null) {
91 $row['hint_points'] = 0;
92 }
93
94 $exam_identifier = self::getExamId($active_id, $pass, $objId);
95
97 $ilDB->replace(
98 'tst_pass_result',
99 array(
100 'active_fi' => array('integer', $active_id),
101 'pass' => array('integer', strlen($pass) ? $pass : 0)),
102 array(
103 'points' => array('float', $row['reachedpoints'] ? $row['reachedpoints'] : 0),
104 'maxpoints' => array('float', $data['points']),
105 'questioncount' => array('integer', $data['count']),
106 'answeredquestions' => array('integer', $row['answeredquestions']),
107 'workingtime' => array('integer', $time),
108 'tstamp' => array('integer', time()),
109 'hint_count' => array('integer', $row['hint_count']),
110 'hint_points' => array('float', $row['hint_points']),
111 'obligations_answered' => array('integer', $obligations_answered),
112 'exam_id' => array('text', $exam_identifier)
113 )
114 );
115 }
116 }
117
118 private static function _getQuestionCountAndPointsForPassOfParticipant($active_id, $pass, $questionSetType)
119 {
120 global $ilDB;
121
122 switch ($questionSetType) {
124
125 $res = $ilDB->queryF(
126 "
127 SELECT COUNT(qpl_questions.question_id) qcount,
128 SUM(qpl_questions.points) qsum
129 FROM tst_active
130 INNER JOIN tst_tests
131 ON tst_tests.test_id = tst_active.test_fi
132 INNER JOIN tst_dyn_quest_set_cfg
133 ON tst_dyn_quest_set_cfg.test_fi = tst_tests.test_id
134 INNER JOIN qpl_questions
135 ON qpl_questions.obj_fi = tst_dyn_quest_set_cfg.source_qpl_fi
136 AND qpl_questions.original_id IS NULL
137 AND qpl_questions.complete = %s
138 WHERE tst_active.active_id = %s
139 ",
140 array('integer', 'integer'),
141 array(1, $active_id)
142 );
143
144 break;
145
147
148 $res = $ilDB->queryF(
149 "
150 SELECT tst_test_rnd_qst.pass,
151 COUNT(tst_test_rnd_qst.question_fi) qcount,
152 SUM(qpl_questions.points) qsum
153
154 FROM tst_test_rnd_qst,
155 qpl_questions
156
157 WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id
158 AND tst_test_rnd_qst.active_fi = %s
159 AND pass = %s
160
161 GROUP BY tst_test_rnd_qst.active_fi,
162 tst_test_rnd_qst.pass
163 ",
164 array('integer', 'integer'),
165 array($active_id, $pass)
166 );
167
168 break;
169
171
172 $res = $ilDB->queryF(
173 "
174 SELECT COUNT(tst_test_question.question_fi) qcount,
175 SUM(qpl_questions.points) qsum
176
177 FROM tst_test_question,
178 qpl_questions,
179 tst_active
180
181 WHERE tst_test_question.question_fi = qpl_questions.question_id
182 AND tst_test_question.test_fi = tst_active.test_fi
183 AND tst_active.active_id = %s
184
185 GROUP BY tst_test_question.test_fi
186 ",
187 array('integer'),
188 array($active_id)
189 );
190
191 break;
192
193 default:
194
195 throw new ilTestException("not supported question set type: $questionSetType");
196 }
197
198 $row = $ilDB->fetchAssoc($res);
199
200 if (is_array($row)) {
201 return array("count" => $row["qcount"], "points" => $row["qsum"]);
202 }
203
204 return array("count" => 0, "points" => 0);
205 }
206
207 private static function _getWorkingTimeOfParticipantForPass($active_id, $pass)
208 {
209 global $ilDB;
210
211 $result = $ilDB->queryF(
212 "SELECT * FROM tst_times WHERE active_fi = %s AND pass = %s ORDER BY started",
213 array('integer','integer'),
214 array($active_id, $pass)
215 );
216 $time = 0;
217 while ($row = $ilDB->fetchAssoc($result)) {
218 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["started"], $matches);
219 $epoch_1 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
220 preg_match("/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row["finished"], $matches);
221 $epoch_2 = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
222 $time += ($epoch_2 - $epoch_1);
223 }
224 return $time;
225 }
226
227 private static function getExamId($active_id, $pass, $obj_id)
228 {
230 global $ilDB;
231
232 $ilSetting = new ilSetting();
233
234 $exam_id_query = 'SELECT exam_id FROM tst_pass_result WHERE active_fi = %s AND pass = %s';
235 $exam_id_result = $ilDB->queryF($exam_id_query, array( 'integer', 'integer' ), array( $active_id, $pass ));
236 if ($ilDB->numRows($exam_id_result) == 1) {
237 $exam_id_row = $ilDB->fetchAssoc($exam_id_result);
238
239 if ($exam_id_row['exam_id'] != null) {
240 return $exam_id_row['exam_id'];
241 }
242 }
243
244 $inst_id = $ilSetting->get('inst_id', null);
245 return 'I' . $inst_id . '_T' . $obj_id . '_A' . $active_id . '_P' . $pass;
246 }
247
248 public static function _updateTestResultCache($active_id, $passScoring)
249 {
250 global $ilDB;
251
252 $pass = self::_getResultPass($active_id, $passScoring);
253
254 $query = "
255 SELECT tst_pass_result.*
256 FROM tst_pass_result
257 WHERE active_fi = %s
258 AND pass = %s
259 ";
260
261 $result = $ilDB->queryF(
262 $query,
263 array('integer','integer'),
264 array($active_id, $pass)
265 );
266
267 $row = $ilDB->fetchAssoc($result);
268
269 $max = $row['maxpoints'];
270 $reached = $row['points'];
271
272 $obligationsAnswered = (int) $row['obligations_answered'];
273
274 $percentage = (!$max) ? 0 : ($reached / $max) * 100.0;
275
276 $mark = self::_getMatchingMarkFromActiveId($active_id, $percentage);
277
278 $isPassed = ($mark["passed"] ? 1 : 0);
279 $isFailed = (!$mark["passed"] ? 1 : 0);
280
281 $query = "
282 DELETE FROM tst_result_cache
283 WHERE active_fi = %s
284 ";
285
286 $affectedRows = $ilDB->manipulateF(
287 $query,
288 array('integer'),
289 array($active_id)
290 );
291
292 $ilDB->insert('tst_result_cache', array(
293 'active_fi'=> array('integer', $active_id),
294 'pass'=> array('integer', strlen($pass) ? $pass : 0),
295 'max_points'=> array('float', strlen($max) ? $max : 0),
296 'reached_points'=> array('float', strlen($reached) ? $reached : 0),
297 'mark_short'=> array('text', strlen($mark["short_name"]) ? $mark["short_name"] : " "),
298 'mark_official'=> array('text', strlen($mark["official_name"]) ? $mark["official_name"] : " "),
299 'passed'=> array('integer', $isPassed),
300 'failed'=> array('integer', $isFailed),
301 'tstamp'=> array('integer', time()),
302 'hint_count'=> array('integer', $row['hint_count']),
303 'hint_points'=> array('float', $row['hint_points']),
304 'obligations_answered' => array('integer', $obligationsAnswered)
305 ));
306 }
307
308 private static function _getResultPass($active_id, $passScoring)
309 {
310 $counted_pass = null;
311 if ($passScoring == SCORE_BEST_PASS) {
312 $counted_pass = self::_getBestPass($active_id);
313 } else {
314 $counted_pass = self::_getMaxPass($active_id);
315 }
316 return $counted_pass;
317 }
318
319 private static function _getBestPass($active_id)
320 {
321 global $ilDB;
322
323 $result = $ilDB->queryF(
324 "SELECT * FROM tst_pass_result WHERE active_fi = %s",
325 array('integer'),
326 array($active_id)
327 );
328 if ($result->numRows()) {
329 $bestrow = null;
330 $bestfactor = 0;
331 while ($row = $ilDB->fetchAssoc($result)) {
332 if ($row["maxpoints"] > 0) {
333 $factor = $row["points"] / $row["maxpoints"];
334 } else {
335 $factor = 0;
336 }
337
338 if ($factor > $bestfactor) {
339 $bestrow = $row;
340 $bestfactor = $factor;
341 }
342 }
343 if (is_array($bestrow)) {
344 return $bestrow["pass"];
345 } else {
346 return 0;
347 }
348 } else {
349 return 0;
350 }
351 }
352
353 private static function _getMaxPass($active_id)
354 {
355 global $ilDB;
356 $result = $ilDB->queryF(
357 "SELECT MAX(pass) maxpass FROM tst_test_result WHERE active_fi = %s",
358 array('integer'),
359 array($active_id)
360 );
361 if ($result->numRows()) {
362 $row = $ilDB->fetchAssoc($result);
363 $max = $row["maxpass"];
364 } else {
365 $max = null;
366 }
367 return $max;
368 }
369
370 private static function _getMatchingMarkFromActiveId($active_id, $percentage)
371 {
373 global $ilDB;
374 $result = $ilDB->queryF(
375 "SELECT tst_mark.* FROM tst_active, tst_mark, tst_tests WHERE tst_mark.test_fi = tst_tests.test_id AND tst_tests.test_id = tst_active.test_fi AND tst_active.active_id = %s ORDER BY minimum_level DESC",
376 array('integer'),
377 array($active_id)
378 );
379
381 while ($row = $ilDB->fetchAssoc($result)) {
382 if ($percentage >= $row["minimum_level"]) {
383 return $row;
384 }
385 }
386 return false;
387 }
388}
$result
An exception for terminatinating execution or to throw for unit testing.
static _getResultPass($active_id, $passScoring)
static _updateTestResultCache($active_id, $passScoring)
const QUESTION_SET_TYPE_FIXED
type setting value for fixed question set
static getExamId($active_id, $pass, $obj_id)
static _getWorkingTimeOfParticipantForPass($active_id, $pass)
static _getQuestionCountAndPointsForPassOfParticipant($active_id, $pass, $questionSetType)
const QUESTION_SET_TYPE_RANDOM
type setting value for random question set
const QUESTION_SET_TYPE_DYNAMIC
type setting value for dynamic question set (continues testing mode)
ILIAS Setting Class.
Base Exception for all Exceptions relating to Modules/Test.
$time
Definition: cron.php:21
global $ilSetting
Definition: privfeed.php:17
$query
foreach($_POST as $key=> $value) $res
global $ilDB