1 | <?php |
||
2 | |||
3 | /* For licensing terms, see /license.txt */ |
||
4 | |||
5 | use Chamilo\CoreBundle\Entity\Course; |
||
6 | use Chamilo\CoreBundle\Entity\Session as SessionEntity; |
||
7 | use Chamilo\CourseBundle\Entity\CLpCategory; |
||
8 | use Chamilo\UserBundle\Entity\User; |
||
9 | use ChamiloSession as Session; |
||
10 | use CpChart\Cache as pCache; |
||
11 | use CpChart\Data as pData; |
||
12 | use CpChart\Image as pImage; |
||
13 | use ExtraField as ExtraFieldModel; |
||
14 | |||
15 | /** |
||
16 | * Class Tracking. |
||
17 | * |
||
18 | * @author Julio Montoya <[email protected]> |
||
19 | */ |
||
20 | class Tracking |
||
21 | { |
||
22 | /** |
||
23 | * Get group reporting. |
||
24 | * |
||
25 | * @param int $course_id |
||
26 | * @param int $sessionId |
||
27 | * @param int $group_id |
||
28 | * @param string $type |
||
29 | * @param int $start |
||
30 | * @param int $limit |
||
31 | * @param int $sidx |
||
32 | * @param string $sord |
||
33 | * @param array $where_condition |
||
34 | * |
||
35 | * @return array|null |
||
36 | */ |
||
37 | public static function get_group_reporting( |
||
38 | $course_id, |
||
39 | $sessionId = 0, |
||
40 | $group_id = 0, |
||
41 | $type = 'all', |
||
42 | $start = 0, |
||
43 | $limit = 1000, |
||
44 | $sidx = 1, |
||
45 | $sord = 'desc', |
||
46 | $where_condition = [] |
||
47 | ) { |
||
48 | $course_id = (int) $course_id; |
||
49 | $sessionId = (int) $sessionId; |
||
50 | |||
51 | if (empty($course_id)) { |
||
52 | return null; |
||
53 | } |
||
54 | $courseInfo = api_get_course_info_by_id($course_id); |
||
55 | if ('count' == $type) { |
||
56 | return GroupManager::get_group_list(null, $courseInfo, null, $sessionId, true); |
||
57 | } |
||
58 | |||
59 | $groupList = GroupManager::get_group_list(null, $courseInfo, null, $sessionId); |
||
60 | $parsedResult = []; |
||
61 | if (!empty($groupList)) { |
||
62 | foreach ($groupList as $group) { |
||
63 | $users = GroupManager::get_users($group['id'], true, null, null, false, $courseInfo['real_id']); |
||
64 | $time = 0; |
||
65 | $avg_student_score = 0; |
||
66 | $avg_student_progress = 0; |
||
67 | $work = 0; |
||
68 | $messages = 0; |
||
69 | |||
70 | foreach ($users as $user_data) { |
||
71 | $time += self::get_time_spent_on_the_course( |
||
72 | $user_data['user_id'], |
||
73 | $courseInfo['real_id'], |
||
74 | $sessionId |
||
75 | ); |
||
76 | $average = self::get_avg_student_score( |
||
77 | $user_data['user_id'], |
||
78 | $courseInfo['code'], |
||
79 | [], |
||
80 | $sessionId |
||
81 | ); |
||
82 | if (is_numeric($average)) { |
||
83 | $avg_student_score += $average; |
||
84 | } |
||
85 | $avg_student_progress += self::get_avg_student_progress( |
||
86 | $user_data['user_id'], |
||
87 | $courseInfo['code'], |
||
88 | [], |
||
89 | $sessionId |
||
90 | ); |
||
91 | $work += self::count_student_assignments( |
||
92 | $user_data['user_id'], |
||
93 | $courseInfo['code'], |
||
94 | $sessionId |
||
95 | ); |
||
96 | $messages += self::count_student_messages( |
||
97 | $user_data['user_id'], |
||
98 | $courseInfo['code'], |
||
99 | $sessionId |
||
100 | ); |
||
101 | } |
||
102 | |||
103 | $countUsers = count($users); |
||
104 | $averageProgress = empty($countUsers) ? 0 : round($avg_student_progress / $countUsers, 2); |
||
105 | $averageScore = empty($countUsers) ? 0 : round($avg_student_score / $countUsers, 2); |
||
106 | |||
107 | $groupItem = [ |
||
108 | 'id' => $group['id'], |
||
109 | 'name' => $group['name'], |
||
110 | 'time' => api_time_to_hms($time), |
||
111 | 'progress' => $averageProgress, |
||
112 | 'score' => $averageScore, |
||
113 | 'works' => $work, |
||
114 | 'messages' => $messages, |
||
115 | ]; |
||
116 | $parsedResult[] = $groupItem; |
||
117 | } |
||
118 | } |
||
119 | |||
120 | return $parsedResult; |
||
121 | } |
||
122 | |||
123 | /** |
||
124 | * Get the lp quizzes result as content for pdf export. |
||
125 | * |
||
126 | * @param $userId |
||
127 | * @param $sessionId |
||
128 | * |
||
129 | * @return string |
||
130 | */ |
||
131 | public static function getLpQuizContentToPdf( |
||
132 | $userId, |
||
133 | $sessionId |
||
134 | ) { |
||
135 | $tblLp = Database::get_course_table(TABLE_LP_MAIN); |
||
136 | $tblLpItem = Database::get_course_table(TABLE_LP_ITEM); |
||
137 | $tblLpItemView = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
138 | $tblLpView = Database::get_course_table(TABLE_LP_VIEW); |
||
139 | $tblUser = Database::get_main_table(TABLE_MAIN_USER); |
||
140 | $tblCourse = Database::get_main_table(TABLE_MAIN_COURSE); |
||
141 | |||
142 | $courses = Tracking::get_courses_list_from_session($sessionId); |
||
143 | |||
144 | // It creates lp quiz table html |
||
145 | $lpQuizTable = ''; |
||
146 | if (!empty($courses)) { |
||
147 | $lpQuizTable .= '<table class="data_table">'; |
||
148 | $lpQuizTable .= '<tbody>'; |
||
149 | $lpTitle = ''; |
||
150 | foreach ($courses as $course) { |
||
151 | $courseId = $course['c_id']; |
||
152 | $sql = 'SELECT DISTINCT c_lp_item.title AS quiz_name, |
||
153 | c_lp.name AS lp_name, |
||
154 | CASE WHEN c_lp_item_view.max_score>0 THEN CONCAT(ROUND((SUM(c_lp_item_view.score)/c_lp_item_view.max_score)*100),\'%\') ELSE 0 END AS score, |
||
155 | SUM(c_lp_view.view_count) AS attempts |
||
156 | FROM '.$tblLpView.' AS c_lp_view |
||
157 | JOIN '.$tblUser.' AS user ON (user.user_id = c_lp_view.user_id) |
||
158 | JOIN '.$tblCourse.' AS course ON (course.id = c_lp_view.c_id) |
||
159 | JOIN '.$tblLp.' AS c_lp ON (c_lp.id = c_lp_view.lp_id AND c_lp.c_id = c_lp_view.c_id) |
||
160 | JOIN '.$tblLpItem.' AS c_lp_item ON (c_lp_item.c_id = c_lp_view.c_id AND c_lp_item.lp_id = c_lp_view.lp_id) |
||
161 | LEFT JOIN '.$tblLpItemView.' AS c_lp_item_view ON (c_lp_item_view.lp_item_id = c_lp_item.id AND c_lp_item_view.lp_view_id = c_lp_view.id AND c_lp_item_view.c_id = c_lp_view.c_id) |
||
162 | WHERE |
||
163 | user.id = '.$userId.' AND |
||
164 | course.id = '.$courseId.' AND |
||
165 | c_lp_item.item_type = \'quiz\' AND |
||
166 | c_lp_view.session_id = '.$sessionId.' |
||
167 | GROUP BY quiz_name, lp_name |
||
168 | ORDER BY c_lp_item.display_order'; |
||
169 | $result = Database::query($sql); |
||
170 | while ($row = Database::fetch_array($result)) { |
||
171 | if ($lpTitle != $row['lp_name']) { |
||
172 | $lpTitle = $row['lp_name']; |
||
173 | $lpQuizTable .= '<tr> |
||
174 | <th>'.stripslashes($lpTitle).'</th> |
||
175 | <th>'.get_lang('Score').'</th> |
||
176 | <th>'.get_lang('Attempts').'</th> |
||
177 | </tr>'; |
||
178 | } |
||
179 | $lpQuizTable .= '<tr> |
||
180 | <td>'.$row['quiz_name'].'</td> |
||
181 | <td>'.$row['score'].'</td> |
||
182 | <td>'.$row['attempts'].'</td> |
||
183 | </tr>'; |
||
184 | } |
||
185 | } |
||
186 | $lpQuizTable .= '</tbody></table>'; |
||
187 | } |
||
188 | |||
189 | return $lpQuizTable; |
||
190 | } |
||
191 | |||
192 | /** |
||
193 | * Get the tables html as contents to export lp certificate pdf . |
||
194 | * |
||
195 | * @return array |
||
196 | */ |
||
197 | public static function getLpCertificateTablesToPdf( |
||
198 | $userId, |
||
199 | $sessionId |
||
200 | ) { |
||
201 | $tblTrackCourseAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
202 | $tblLp = Database::get_course_table(TABLE_LP_MAIN); |
||
203 | $tblLpItem = Database::get_course_table(TABLE_LP_ITEM); |
||
204 | $tblLpItemView = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
205 | $tblLpView = Database::get_course_table(TABLE_LP_VIEW); |
||
206 | $tblUser = Database::get_main_table(TABLE_MAIN_USER); |
||
207 | $tblCourse = Database::get_main_table(TABLE_MAIN_COURSE); |
||
208 | |||
209 | $courses = Tracking::get_courses_list_from_session($sessionId); |
||
210 | |||
211 | // It creates the progress table html |
||
212 | $progressTable = ''; |
||
213 | if (!empty($courses)) { |
||
214 | $timeSpent = 0; |
||
215 | $numberVisits = 0; |
||
216 | $progress = 0; |
||
217 | foreach ($courses as $course) { |
||
218 | $courseId = $course['c_id']; |
||
219 | $timeSpent += Tracking::get_time_spent_on_the_course($userId, $courseId, $sessionId); |
||
220 | $sql = 'SELECT DISTINCT count(course_access_id) as count |
||
221 | FROM '.$tblTrackCourseAccess.' |
||
222 | WHERE |
||
223 | user_id = '.$userId.' AND |
||
224 | c_id = '.$courseId.' AND |
||
225 | session_id = '.$sessionId.' |
||
226 | ORDER BY login_course_date ASC'; |
||
227 | $result = Database::query($sql); |
||
228 | $row = Database::fetch_array($result); |
||
229 | $numberVisits += $row['count']; |
||
230 | $progress += Tracking::get_avg_student_progress($userId, $course['code'], [], $sessionId); |
||
231 | } |
||
232 | $average = round($progress / count($courses), 1); |
||
233 | $average = empty($average) ? '0%' : $average.'%'; |
||
234 | $first = Tracking::get_first_connection_date($userId); |
||
235 | $last = Tracking::get_last_connection_date($userId); |
||
236 | |||
237 | $table = new HTML_Table(['class' => 'data_table']); |
||
238 | $column = 0; |
||
239 | $row = 0; |
||
240 | $headers = [ |
||
241 | get_lang('TimeSpent'), |
||
242 | get_lang('NumberOfVisits'), |
||
243 | get_lang('GlobalProgress'), |
||
244 | get_lang('FirstLogin'), |
||
245 | get_lang('LastConnexionDate'), |
||
246 | ]; |
||
247 | |||
248 | foreach ($headers as $header) { |
||
249 | $table->setHeaderContents($row, $column, $header); |
||
250 | $column++; |
||
251 | } |
||
252 | $table->setCellContents(1, 0, api_time_to_hms($timeSpent)); |
||
253 | $table->setCellContents(1, 1, $numberVisits); |
||
254 | $table->setCellContents(1, 2, $average); |
||
255 | $table->setCellContents(1, 3, $first); |
||
256 | $table->setCellContents(1, 4, $last); |
||
257 | $progressTable = $table->toHtml(); |
||
258 | } |
||
259 | |||
260 | // It creates the course table html |
||
261 | $courseTable = ''; |
||
262 | if (!empty($courses)) { |
||
263 | $totalCourseTime = 0; |
||
264 | $totalAttendance = [0, 0]; |
||
265 | $totalScore = 0; |
||
266 | $totalProgress = 0; |
||
267 | $gradeBookTotal = [0, 0]; |
||
268 | $totalEvaluations = '0/0 (0%)'; |
||
269 | $totalCourses = count($courses); |
||
270 | $scoreDisplay = ScoreDisplay::instance(); |
||
271 | |||
272 | $courseTable .= '<table class="data_table">'; |
||
273 | $courseTable .= '<thead>'; |
||
274 | $courseTable .= '<tr> |
||
275 | <th>'.get_lang('ToolLearnpath').'</th> |
||
276 | <th>'.get_lang('ConnectionTime').'</th> |
||
277 | <th>'.get_lang('NumberOfVisits').'</th> |
||
278 | <th>'.get_lang('Progress').'</th> |
||
279 | <th>'.get_lang('FirstLogin').'</th> |
||
280 | <th>'.get_lang('LastConnexion').'</th> |
||
281 | </tr>'; |
||
282 | $courseTable .= '</thead>'; |
||
283 | $courseTable .= '<tbody>'; |
||
284 | foreach ($courses as $course) { |
||
285 | $courseId = $course['c_id']; |
||
286 | $courseInfoItem = api_get_course_info_by_id($courseId); |
||
287 | $courseId = $courseInfoItem['real_id']; |
||
288 | $courseCodeItem = $courseInfoItem['code']; |
||
289 | |||
290 | $isSubscribed = CourseManager::is_user_subscribed_in_course( |
||
291 | $userId, |
||
292 | $courseCodeItem, |
||
293 | true, |
||
294 | $sessionId |
||
295 | ); |
||
296 | |||
297 | if ($isSubscribed) { |
||
298 | $timeInSeconds = Tracking::get_time_spent_on_the_course( |
||
299 | $userId, |
||
300 | $courseId, |
||
301 | $sessionId |
||
302 | ); |
||
303 | $totalCourseTime += $timeInSeconds; |
||
304 | $time_spent_on_course = api_time_to_hms($timeInSeconds); |
||
305 | $progress = Tracking::get_avg_student_progress( |
||
306 | $userId, |
||
307 | $courseCodeItem, |
||
308 | [], |
||
309 | $sessionId |
||
310 | ); |
||
311 | $totalProgress += $progress; |
||
312 | $bestScore = Tracking::get_avg_student_score( |
||
313 | $userId, |
||
314 | $courseCodeItem, |
||
315 | [], |
||
316 | $sessionId, |
||
317 | false, |
||
318 | false, |
||
319 | true |
||
320 | ); |
||
321 | if (is_numeric($bestScore)) { |
||
322 | $totalScore += $bestScore; |
||
323 | } |
||
324 | if ($progress > 0) { |
||
325 | $progress = empty($progress) ? '0%' : $progress.'%'; |
||
326 | $score = empty($bestScore) ? '0%' : $bestScore.'%'; |
||
327 | $sql = 'SELECT |
||
328 | DISTINCT count(course_access_id) as count, |
||
329 | date_format(min(login_course_date),\'%d/%m/%Y\') as first, |
||
330 | date_format(max(logout_course_date),\'%d/%m/%Y\') as last |
||
331 | FROM |
||
332 | '.$tblTrackCourseAccess.' |
||
333 | WHERE |
||
334 | user_id = '.$userId.' AND |
||
335 | c_id = '.$courseId.' AND |
||
336 | session_id = '.$sessionId; |
||
337 | $result = Database::query($sql); |
||
338 | $row = Database::fetch_array($result); |
||
339 | $numberVisitsByCourse = $row['count']; |
||
340 | $firstByCourse = $row['first']; |
||
341 | $lastByCourse = $row['last']; |
||
342 | $courseTable .= '<tr> |
||
343 | <td ><a href="'.$courseInfoItem['course_public_url'].'?id_session='.$sessionId.'">'.$courseInfoItem['title'].'</a></td> |
||
344 | <td >'.$time_spent_on_course.'</td> |
||
345 | <td >'.$numberVisitsByCourse.'</td> |
||
346 | <td >'.$progress.'</td> |
||
347 | <td >'.$firstByCourse.'</td> |
||
348 | <td >'.$lastByCourse.'</td>'; |
||
349 | $courseTable .= '</tr>'; |
||
350 | } |
||
351 | } |
||
352 | } |
||
353 | $totalAttendanceFormatted = $scoreDisplay->display_score($totalAttendance); |
||
354 | $totalScoreFormatted = $scoreDisplay->display_score([$totalScore / $totalCourses, 100], SCORE_AVERAGE); |
||
355 | $totalProgressFormatted = $scoreDisplay->display_score( |
||
356 | [$totalProgress / $totalCourses, 100], |
||
357 | SCORE_AVERAGE |
||
358 | ); |
||
359 | $totalEvaluations = $scoreDisplay->display_score($gradeBookTotal); |
||
360 | $totalTimeFormatted = api_time_to_hms($totalCourseTime); |
||
361 | $courseTable .= '<tr> |
||
362 | <th>'.get_lang('Total').'</th> |
||
363 | <th>'.$totalTimeFormatted.'</th> |
||
364 | <th>'.$numberVisits.'</th> |
||
365 | <th>'.$totalProgressFormatted.'</th> |
||
366 | <th>'.$first.'</th> |
||
367 | <th>'.$last.'</th> |
||
368 | </tr>'; |
||
369 | $courseTable .= '</tbody></table>'; |
||
370 | } |
||
371 | |||
372 | // It creates the lps table html |
||
373 | $lpTable = ''; |
||
374 | if (!empty($courses)) { |
||
375 | $lpTable = '<table class="data_table">'; |
||
376 | $lpTable .= '<tbody>'; |
||
377 | $lpTitle = ''; |
||
378 | foreach ($courses as $course) { |
||
379 | $courseId = $course['c_id']; |
||
380 | $sql = 'SELECT DISTINCT c_lp.name AS lp_name, |
||
381 | c_lp_item.title AS chapter, |
||
382 | SEC_TO_TIME(c_lp_item_view.total_time) AS temps, |
||
383 | c_lp_item_view.status AS etat, |
||
384 | SUM(c_lp_view.view_count) AS tentatives, |
||
385 | c_lp_item_2.title AS chapter2, |
||
386 | SEC_TO_TIME(c_lp_item_view_2.total_time) AS temps2, |
||
387 | c_lp_item_view_2.status AS etat2 |
||
388 | FROM '.$tblLpView.' AS c_lp_view |
||
389 | JOIN '.$tblUser.' AS user ON user.user_id = c_lp_view.user_id |
||
390 | JOIN '.$tblCourse.' AS course ON course.id = c_lp_view.c_id |
||
391 | JOIN '.$tblLp.' AS c_lp ON (c_lp.id = c_lp_view.lp_id AND c_lp.c_id = c_lp_view.c_id) |
||
392 | JOIN '.$tblLpItem.' AS c_lp_item ON (c_lp_item.c_id = c_lp_view.c_id AND c_lp_item.lp_id = c_lp_view.lp_id) |
||
393 | LEFT JOIN '.$tblLpItemView.' AS c_lp_item_view ON (c_lp_item_view.lp_item_id = c_lp_item.id AND c_lp_item_view.lp_view_id = c_lp_view.id AND c_lp_item_view.c_id = c_lp_view.c_id) |
||
394 | LEFT JOIN '.$tblLpItem.' AS c_lp_item_2 ON (c_lp_item_2.parent_item_id > 0 AND c_lp_item_2.parent_item_id = c_lp_item.id) |
||
395 | LEFT JOIN '.$tblLpItemView.' AS c_lp_item_view_2 ON (c_lp_item_view_2.lp_item_id = c_lp_item_2.id AND c_lp_item_view_2.lp_view_id = c_lp_view.id AND c_lp_item_view_2.c_id = c_lp_view.c_id) |
||
396 | WHERE |
||
397 | user.id = '.$userId.' AND |
||
398 | course.id = '.$courseId.' AND |
||
399 | c_lp_view.session_id = '.$sessionId.' AND |
||
400 | c_lp_item.parent_item_id = 0 |
||
401 | GROUP BY |
||
402 | lp_name, chapter, chapter2 |
||
403 | ORDER BY |
||
404 | lp_name, c_lp_item.display_order'; |
||
405 | $result = Database::query($sql); |
||
406 | $chapterTitle = false; |
||
407 | while ($row = Database::fetch_array($result)) { |
||
408 | if ($lpTitle != $row['lp_name']) { |
||
409 | $lpTitle = $row['lp_name']; |
||
410 | $lpTable .= '<tr> |
||
411 | <th>'.stripslashes($lpTitle).'</th> |
||
412 | <th>'.get_lang('Duration').'</th> |
||
413 | <th>'.get_lang('Progress').'</th> |
||
414 | </tr>'; |
||
415 | } |
||
416 | if ('' == $row['chapter2']) { |
||
417 | $progression = $row['etat']; |
||
418 | if (('completed' === $progression) || ('passed' === $progression)) { |
||
419 | $progression = get_lang('Done'); |
||
420 | } else { |
||
421 | $progression = get_lang('Incomplete'); |
||
422 | } |
||
423 | $lpTable .= '<tr> |
||
424 | <td>'.$row['chapter'].'</td> |
||
425 | <td>'.$row['temps'].'</td> |
||
426 | <td>'.$progression.'</td> |
||
427 | </tr>'; |
||
428 | $chapterTitle = false; |
||
429 | } else { |
||
430 | if (false == $chapterTitle) { |
||
431 | $lpTable .= '<tr> |
||
432 | <td>'.$row['chapter'].'</td> |
||
433 | <td></td> |
||
434 | <td></td> |
||
435 | </tr>'; |
||
436 | $chapterTitle = true; |
||
437 | } |
||
438 | $progression = $row['etat2']; |
||
439 | if ('completed' == $progression) { |
||
440 | $progression = get_lang('Done'); |
||
441 | } else { |
||
442 | $progression = get_lang('Incomplete'); |
||
443 | } |
||
444 | $lpTable .= '<tr> |
||
445 | <td> - '.$row['chapter2'].'</td> |
||
446 | <td>'.$row['temps2'].'</td> |
||
447 | <td>'.$progression.'</td> |
||
448 | </tr>'; |
||
449 | } |
||
450 | } |
||
451 | } |
||
452 | $lpTable .= '</tbody></table>'; |
||
453 | } |
||
454 | |||
455 | return ['progress_table' => $progressTable, 'course_table' => $courseTable, 'lp_table' => $lpTable]; |
||
456 | } |
||
457 | |||
458 | /** |
||
459 | * It gets table html of Lp stats used to export in pdf. |
||
460 | * |
||
461 | * @return string |
||
462 | */ |
||
463 | public static function getLpStatsContentToPdf( |
||
464 | $userId, |
||
465 | $courseInfo, |
||
466 | $sessionId, |
||
467 | $lpId, |
||
468 | $lpName |
||
469 | ) { |
||
470 | $hideTime = api_get_configuration_value('hide_lp_time'); |
||
471 | $lpId = (int) $lpId; |
||
472 | $userId = (int) $userId; |
||
473 | $sessionId = (int) $sessionId; |
||
474 | $courseId = $courseInfo['real_id']; |
||
475 | $isAllowedToEdit = api_is_allowed_to_edit(null, true); |
||
476 | $sessionCondition = api_get_session_condition($sessionId); |
||
477 | $counter = 0; |
||
478 | $totalTime = 0; |
||
479 | $h = get_lang('h'); |
||
480 | $resultDisabledExtAll = true; |
||
481 | $timeHeader = '<th>'.get_lang('ScormTime').'</th>'; |
||
482 | if ($hideTime) { |
||
483 | $timeHeader = ''; |
||
484 | } |
||
485 | $output = '<h2 class="clearfix text-center">'.$lpName.'</h2>'; |
||
486 | $output .= '<table class="table table-hover table-striped data_table"> |
||
487 | <thead> |
||
488 | <tr> |
||
489 | <th>'.get_lang('ScormLessonTitle').'</th> |
||
490 | <th>'.get_lang('ScormStatus').'</th> |
||
491 | <th>'.get_lang('ScormScore').'</th> |
||
492 | '.$timeHeader.' |
||
493 | </tr> |
||
494 | </thead> |
||
495 | <tbody> |
||
496 | '; |
||
497 | |||
498 | $tblLpItem = Database::get_course_table(TABLE_LP_ITEM); |
||
499 | $tblLpItemView = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
500 | $tblLpView = Database::get_course_table(TABLE_LP_VIEW); |
||
501 | $tblQuizQuestions = Database::get_course_table(TABLE_QUIZ_QUESTION); |
||
502 | $tblQuiz = Database::get_course_table(TABLE_QUIZ_TEST); |
||
503 | $tblStatsExercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
504 | $tblStatsAttempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
505 | |||
506 | // it gets the max view |
||
507 | $sql = "SELECT max(view_count) FROM $tblLpView WHERE c_id = $courseId AND lp_id = $lpId AND user_id = $userId $sessionCondition"; |
||
508 | $res = Database::query($sql); |
||
509 | $view = 0; |
||
510 | $viewCondition = ""; |
||
511 | if (Database::num_rows($res) > 0) { |
||
512 | $view = Database::result($res, 0, 0); |
||
513 | $viewCondition = " AND v.view_count = ".(int) $view; |
||
514 | } |
||
515 | |||
516 | $chapterTypes = learnpath::getChapterTypes(); |
||
517 | $minimumAvailable = self::minimumTimeAvailable($sessionId, $courseId); |
||
518 | $list = learnpath::get_flat_ordered_items_list($lpId, 0, $courseId); |
||
519 | if (is_array($list) && count($list) > 0) { |
||
520 | foreach ($list as $myItemId) { |
||
521 | $sql = "SELECT |
||
522 | iv.status as mystatus, |
||
523 | v.view_count as mycount, |
||
524 | iv.score as myscore, |
||
525 | iv.total_time as mytime, |
||
526 | i.iid as myid, |
||
527 | i.lp_id as mylpid, |
||
528 | iv.lp_view_id as mylpviewid, |
||
529 | i.title as mytitle, |
||
530 | i.max_score as mymaxscore, |
||
531 | iv.max_score as myviewmaxscore, |
||
532 | i.item_type as item_type, |
||
533 | iv.view_count as iv_view_count, |
||
534 | iv.id as iv_id, |
||
535 | path |
||
536 | FROM $tblLpItem as i |
||
537 | INNER JOIN $tblLpItemView as iv |
||
538 | ON (i.iid = iv.lp_item_id AND i.c_id = iv.c_id) |
||
539 | INNER JOIN $tblLpView as v |
||
540 | ON (iv.lp_view_id = v.id AND v.c_id = iv.c_id) |
||
541 | WHERE |
||
542 | v.c_id = $courseId AND |
||
543 | i.iid = $myItemId AND |
||
544 | i.lp_id = $lpId AND |
||
545 | v.user_id = $userId AND |
||
546 | v.session_id = $sessionId |
||
547 | $viewCondition |
||
548 | ORDER BY iv.view_count"; |
||
549 | $result = Database::query($sql); |
||
550 | $num = Database::num_rows($result); |
||
551 | $timeForTotal = 0; |
||
552 | |||
553 | if ($num > 0) { |
||
554 | // Not extended. |
||
555 | $row = Database::fetch_array($result, 'ASSOC'); |
||
556 | $myId = $row['myid']; |
||
557 | $myLpId = $row['mylpid']; |
||
558 | $myLpViewId = $row['mylpviewid']; |
||
559 | $lpItemPath = (int) $row['path']; |
||
560 | $resultDisabledExtAll = false; |
||
561 | if ($row['item_type'] === 'quiz') { |
||
562 | // Check results_disabled in quiz table. |
||
563 | $sql = "SELECT results_disabled |
||
564 | FROM $tblQuiz |
||
565 | WHERE iid = $lpItemPath"; |
||
566 | $resResultDisabled = Database::query($sql); |
||
567 | $rowResultDisabled = Database::fetch_row($resResultDisabled); |
||
568 | if (Database::num_rows($resResultDisabled) > 0 && 1 === (int) $rowResultDisabled[0]) { |
||
569 | $resultDisabledExtAll = true; |
||
570 | } |
||
571 | } |
||
572 | |||
573 | // Check if there are interactions below |
||
574 | $extendThisAttempt = 0; |
||
575 | $interNum = learnpath::get_interactions_count_from_db($row['iv_id'], $courseId); |
||
576 | $objecNum = learnpath::get_objectives_count_from_db($row['iv_id'], $courseId); |
||
577 | if ($interNum > 0 || $objecNum > 0) { |
||
578 | $extendThisAttempt = 1; |
||
579 | } |
||
580 | $lesson_status = $row['mystatus']; |
||
581 | $score = $row['myscore']; |
||
582 | $subtotalTime = $row['mytime']; |
||
583 | while ($tmp_row = Database::fetch_array($result)) { |
||
584 | $subtotalTime += $tmp_row['mytime']; |
||
585 | } |
||
586 | |||
587 | $title = $row['mytitle']; |
||
588 | // Selecting the exe_id from stats attempts tables in order to look the max score value. |
||
589 | $sql = 'SELECT * FROM '.$tblStatsExercises.' |
||
590 | WHERE |
||
591 | exe_exo_id="'.$row['path'].'" AND |
||
592 | exe_user_id="'.$userId.'" AND |
||
593 | orig_lp_id = "'.$lpId.'" AND |
||
594 | orig_lp_item_id = "'.$row['myid'].'" AND |
||
595 | c_id = '.$courseId.' AND |
||
596 | status <> "incomplete" AND |
||
597 | session_id = '.$sessionId.' |
||
598 | ORDER BY exe_date DESC |
||
599 | LIMIT 1'; |
||
600 | |||
601 | $resultLastAttempt = Database::query($sql); |
||
602 | $num = Database::num_rows($resultLastAttempt); |
||
603 | $idLastAttempt = null; |
||
604 | if ($num > 0) { |
||
605 | while ($rowLA = Database::fetch_array($resultLastAttempt)) { |
||
606 | $idLastAttempt = $rowLA['exe_id']; |
||
607 | } |
||
608 | } |
||
609 | |||
610 | switch ($row['item_type']) { |
||
611 | case 'sco': |
||
612 | if (!empty($row['myviewmaxscore']) && $row['myviewmaxscore'] > 0) { |
||
613 | $maxscore = $row['myviewmaxscore']; |
||
614 | } elseif ($row['myviewmaxscore'] === '') { |
||
615 | $maxscore = 0; |
||
616 | } else { |
||
617 | $maxscore = $row['mymaxscore']; |
||
618 | } |
||
619 | break; |
||
620 | case 'quiz': |
||
621 | // Get score and total time from last attempt of an exercise en lp. |
||
622 | $sql = "SELECT iid, score |
||
623 | FROM $tblLpItemView |
||
624 | WHERE |
||
625 | c_id = $courseId AND |
||
626 | lp_item_id = '".(int) $myId."' AND |
||
627 | lp_view_id = '".(int) $myLpViewId."' |
||
628 | ORDER BY view_count DESC |
||
629 | LIMIT 1"; |
||
630 | $resScore = Database::query($sql); |
||
631 | $rowScore = Database::fetch_array($resScore); |
||
632 | |||
633 | $sql = "SELECT SUM(total_time) as total_time |
||
634 | FROM $tblLpItemView |
||
635 | WHERE |
||
636 | c_id = $courseId AND |
||
637 | lp_item_id = '".(int) $myId."' AND |
||
638 | lp_view_id = '".(int) $myLpViewId."'"; |
||
639 | $resTime = Database::query($sql); |
||
640 | $rowTime = Database::fetch_array($resTime); |
||
641 | |||
642 | $score = 0; |
||
643 | $subtotalTime = 0; |
||
644 | if (Database::num_rows($resScore) > 0 && Database::num_rows($resTime) > 0) { |
||
645 | $score = (float) $rowScore['score']; |
||
646 | $subtotalTime = (int) $rowTime['total_time']; |
||
647 | } |
||
648 | // Selecting the max score from an attempt. |
||
649 | $sql = "SELECT SUM(t.ponderation) as maxscore |
||
650 | FROM ( |
||
651 | SELECT DISTINCT |
||
652 | question_id, marks, ponderation |
||
653 | FROM $tblStatsAttempts as at |
||
654 | INNER JOIN $tblQuizQuestions as q |
||
655 | ON q.iid = at.question_id |
||
656 | WHERE exe_id ='$idLastAttempt' |
||
657 | ) as t"; |
||
658 | |||
659 | $result = Database::query($sql); |
||
660 | $rowMaxScore = Database::fetch_array($result); |
||
661 | $maxscore = $rowMaxScore['maxscore']; |
||
662 | |||
663 | // Get duration time from track_e_exercises.exe_duration instead of lp_view_item.total_time |
||
664 | $sql = 'SELECT SUM(exe_duration) exe_duration |
||
665 | FROM '.$tblStatsExercises.' |
||
666 | WHERE |
||
667 | exe_exo_id="'.$row['path'].'" AND |
||
668 | exe_user_id="'.$userId.'" AND |
||
669 | orig_lp_id = "'.$lpId.'" AND |
||
670 | orig_lp_item_id = "'.$row['myid'].'" AND |
||
671 | c_id = '.$courseId.' AND |
||
672 | status <> "incomplete" AND |
||
673 | session_id = '.$sessionId.' |
||
674 | ORDER BY exe_date DESC '; |
||
675 | $sumScoreResult = Database::query($sql); |
||
676 | $durationRow = Database::fetch_array($sumScoreResult, 'ASSOC'); |
||
677 | if (!empty($durationRow['exe_duration'])) { |
||
678 | $exeDuration = $durationRow['exe_duration']; |
||
679 | if ($exeDuration != $subtotalTime && !empty($rowScore['iid']) && !empty($exeDuration)) { |
||
680 | $subtotalTime = $exeDuration; |
||
681 | // Update c_lp_item_view.total_time |
||
682 | $sqlUpdate = "UPDATE $tblLpItemView SET total_time = '$exeDuration' WHERE iid = ".$rowScore['iid']; |
||
683 | Database::query($sqlUpdate); |
||
684 | } |
||
685 | } |
||
686 | break; |
||
687 | default: |
||
688 | $maxscore = $row['mymaxscore']; |
||
689 | break; |
||
690 | } |
||
691 | |||
692 | $timeForTotal = $subtotalTime; |
||
693 | $time = learnpathItem::getScormTimeFromParameter('js', $subtotalTime); |
||
694 | if (empty($title)) { |
||
695 | $title = learnpath::rl_get_resource_name( |
||
696 | $courseInfo['code'], |
||
697 | $lpId, |
||
698 | $row['myid'] |
||
699 | ); |
||
700 | } |
||
701 | |||
702 | if (in_array($row['item_type'], $chapterTypes)) { |
||
703 | $title = Security::remove_XSS($title); |
||
704 | $output .= '<tr> |
||
705 | <td colspan="4"><h4>'.$title.'</h4></td> |
||
706 | </tr>'; |
||
707 | } else { |
||
708 | if ('quiz' === $row['item_type']) { |
||
709 | $sql = 'SELECT * FROM '.$tblStatsExercises.' |
||
710 | WHERE |
||
711 | exe_exo_id="'.$row['path'].'" AND |
||
712 | exe_user_id="'.$userId.'" AND |
||
713 | orig_lp_id = "'.$lpId.'" AND |
||
714 | orig_lp_item_id = "'.$row['myid'].'" AND |
||
715 | c_id = '.$courseId.' AND |
||
716 | status <> "incomplete" AND |
||
717 | session_id = '.$sessionId.' |
||
718 | ORDER BY exe_date DESC '; |
||
719 | $resultLastAttempt = Database::query($sql); |
||
720 | $num = Database::num_rows($resultLastAttempt); |
||
721 | } |
||
722 | |||
723 | $title = Security::remove_XSS($title); |
||
724 | if ($lpId == $myLpId && false) { |
||
725 | $output .= '<tr> |
||
726 | <td>'.$title.'</td> |
||
727 | <td> </td> |
||
728 | <td> </td> |
||
729 | <td> </td> |
||
730 | </tr>'; |
||
731 | } else { |
||
732 | $output .= "<tr>"; |
||
733 | $scoreItem = null; |
||
734 | if ($row['item_type'] === 'quiz') { |
||
735 | $scoreItem .= ExerciseLib::show_score($score, $maxscore, false); |
||
736 | } else { |
||
737 | $scoreItem .= $score == 0 ? '/' : ($maxscore == 0 ? $score : $score.'/'.$maxscore); |
||
738 | } |
||
739 | $timeRow = '<td style="width:20%;text-align:center;">'.$time.'</td>'; |
||
740 | if ($hideTime) { |
||
741 | $timeRow = ''; |
||
742 | } |
||
743 | $output .= ' |
||
744 | <td style="width:35%;font-weight:bold;">'.$title.'</td> |
||
745 | <td style="width:25%;text-align:center;"><div class="btn btn-primary boldTitle">'.learnpathitem::humanize_status($lesson_status, false).'</div></td> |
||
746 | <td style="width:20%;text-align:center;">'.$scoreItem.'</td> |
||
747 | '.$timeRow.' |
||
748 | '; |
||
749 | $output .= '</tr>'; |
||
750 | } |
||
751 | } |
||
752 | |||
753 | $counter++; |
||
754 | if ($extendThisAttempt) { |
||
755 | $list1 = learnpath::get_iv_interactions_array($row['iv_id'], $courseId); |
||
756 | foreach ($list1 as $id => $interaction) { |
||
757 | $timeRow = '<td>'.$interaction['time'].'</td>'; |
||
758 | if ($hideTime) { |
||
759 | $timeRow = ''; |
||
760 | } |
||
761 | |||
762 | $output .= '<tr> |
||
763 | <td>'.$interaction['order_id'].'</td> |
||
764 | <td>'.$interaction['id'].'</td> |
||
765 | <td>'.$interaction['type'].'</td> |
||
766 | <td>'.urldecode($interaction['student_response']).'</td> |
||
767 | <td>'.$interaction['result'].'</td> |
||
768 | <td>'.$interaction['latency'].'</td> |
||
769 | '.$timeRow.' |
||
770 | </tr>'; |
||
771 | $counter++; |
||
772 | } |
||
773 | |||
774 | $list2 = learnpath::get_iv_objectives_array($row['iv_id'], $courseId); |
||
775 | foreach ($list2 as $id => $interaction) { |
||
776 | $output .= '<tr> |
||
777 | <td>'.$interaction['order_id'].'</td> |
||
778 | <td>'.$interaction['objective_id'].'</td> |
||
779 | <td>'.$interaction['status'].'</td> |
||
780 | <td>'.$interaction['score_raw'].'</td> |
||
781 | <td>'.$interaction['score_max'].'</td> |
||
782 | <td>'.$interaction['score_min'].'</td> |
||
783 | </tr>'; |
||
784 | $counter++; |
||
785 | } |
||
786 | } |
||
787 | |||
788 | // Attempts listing by exercise. |
||
789 | if ($lpId == $myLpId) { |
||
790 | // Get attempts of a exercise. |
||
791 | if (!empty($lpId) && 'quiz' === $row['item_type']) { |
||
792 | $sql = "SELECT path FROM $tblLpItem |
||
793 | WHERE |
||
794 | c_id = $courseId AND |
||
795 | lp_id = '$lpId'"; |
||
796 | $resPath = Database::query($sql); |
||
797 | if (Database::num_rows($resPath) > 0) { |
||
798 | while ($rowPath = Database::fetch_array($resPath)) { |
||
799 | $sql = 'SELECT * FROM '.$tblStatsExercises.' |
||
800 | WHERE |
||
801 | exe_exo_id="'.(int) $rowPath['path'].'" AND |
||
802 | status <> "incomplete" AND |
||
803 | exe_user_id="'.$userId.'" AND |
||
804 | orig_lp_id = "'.$lpId.'" AND |
||
805 | orig_lp_item_id = "'.$myItemId.'" AND |
||
806 | c_id = '.$courseId.' AND |
||
807 | session_id = '.$sessionId.' |
||
808 | ORDER BY exe_date'; |
||
809 | $resAttempts = Database::query($sql); |
||
810 | if (Database::num_rows($resAttempts) > 0) { |
||
811 | $n = 1; |
||
812 | while ($rowAttempts = Database::fetch_array($resAttempts)) { |
||
813 | $myScore = $rowAttempts['exe_result']; |
||
814 | $myMaxscore = $rowAttempts['exe_weighting']; |
||
815 | $mktimeStartDate = api_strtotime($rowAttempts['start_date'], 'UTC'); |
||
816 | $mktimeExeDate = api_strtotime($rowAttempts['exe_date'], 'UTC'); |
||
817 | $timeAttempt = ' - '; |
||
818 | if ($mktimeStartDate && $mktimeExeDate) { |
||
819 | $timeAttempt = api_format_time($rowAttempts['exe_duration'], 'js'); |
||
820 | } |
||
821 | // Show only float when need it |
||
822 | if ($myScore == 0) { |
||
823 | $viewScore = ExerciseLib::show_score( |
||
824 | 0, |
||
825 | $myMaxscore, |
||
826 | false |
||
827 | ); |
||
828 | } else { |
||
829 | if ($myMaxscore == 0) { |
||
830 | $viewScore = $myScore; |
||
831 | } else { |
||
832 | $viewScore = ExerciseLib::show_score( |
||
833 | $myScore, |
||
834 | $myMaxscore, |
||
835 | false |
||
836 | ); |
||
837 | } |
||
838 | } |
||
839 | $myLessonStatus = $rowAttempts['status']; |
||
840 | if ($myLessonStatus == '') { |
||
841 | $myLessonStatus = learnpathitem::humanize_status('completed', false); |
||
842 | } elseif ($myLessonStatus == 'incomplete') { |
||
843 | $myLessonStatus = learnpathitem::humanize_status('incomplete', false); |
||
844 | } |
||
845 | $timeRow = '<td style="text-align:center;">'.$timeAttempt.'</td>'; |
||
846 | if ($hideTime) { |
||
847 | $timeRow = ''; |
||
848 | } |
||
849 | $output .= '<tr> |
||
850 | <td>— <em>'.get_lang('Attempt').' '.$n.'</em></td> |
||
851 | <td style="text-align:center;"><div class="btn btn-primary boldTitle">'.$myLessonStatus.'</div></td> |
||
852 | <td style="text-align:center;">'.$viewScore.'</td> |
||
853 | '.$timeRow; |
||
854 | $output .= '</tr>'; |
||
855 | |||
856 | // It displays categories questions by attempts |
||
857 | $categoriesQuestions = TestCategory::getQuestionsByCat($rowAttempts['exe_exo_id'], [], [], false, $courseId); |
||
858 | $categories = TestCategory::getListOfCategoriesIDForTest($rowAttempts['exe_exo_id'], $courseId); |
||
859 | $objExercise = new Exercise($courseId); |
||
860 | $objExercise->read($rowAttempts['exe_exo_id']); |
||
861 | if (!empty($categoriesQuestions)) { |
||
862 | foreach ($categoriesQuestions as $catId => $questions) { |
||
863 | $catScore = 0; |
||
864 | $catWeight = 0; |
||
865 | if (!empty($questions)) { |
||
866 | foreach ($questions as $questionId) { |
||
867 | $questionResult = $objExercise->manage_answer( |
||
868 | $rowAttempts['exe_id'], |
||
869 | $questionId, |
||
870 | '', |
||
871 | 'exercise_show', |
||
872 | [], |
||
873 | false, |
||
874 | true, |
||
875 | false, |
||
876 | $objExercise->selectPropagateNeg() |
||
877 | ); |
||
878 | $catScore += $questionResult['score']; |
||
879 | $catWeight += $questionResult['weight']; |
||
880 | } |
||
881 | } |
||
882 | $timeCatRow = ''; |
||
883 | if (!$hideTime) { |
||
884 | $timeCatRow = '<td></td>'; |
||
885 | } |
||
886 | $catTitle = $categories[$catId]['title']; |
||
887 | $catScoreDisplay = ($catWeight > 0) ? round(($catScore * 100) / $catWeight).'% ('.$catScore.'/'.$catWeight.')' : ''; |
||
888 | $output .= "<tr>"; |
||
889 | $output .= ' |
||
890 | <td style="width:35%">—— '.$catTitle.'</td> |
||
891 | <td style="width:25%;"></td> |
||
892 | <td style="width:20%;text-align:center;">'.$catScoreDisplay.'</td> |
||
893 | '.$timeCatRow.' |
||
894 | '; |
||
895 | $output .= '</tr>'; |
||
896 | } |
||
897 | } |
||
898 | $n++; |
||
899 | } |
||
900 | } |
||
901 | } |
||
902 | } |
||
903 | } |
||
904 | } |
||
905 | } |
||
906 | $totalTime += $timeForTotal; |
||
907 | } |
||
908 | } |
||
909 | |||
910 | $totalScore = self::get_avg_student_score( |
||
911 | $userId, |
||
912 | $courseInfo['code'], |
||
913 | [$lpId], |
||
914 | $sessionId, |
||
915 | false, |
||
916 | false |
||
917 | ); |
||
918 | |||
919 | $totalTime = learnpathItem::getScormTimeFromParameter('js', $totalTime); |
||
920 | $totalTime = str_replace('NaN', '00'.$h.'00\'00"', $totalTime); |
||
921 | |||
922 | if (!$isAllowedToEdit && $resultDisabledExtAll) { |
||
923 | $finalScore = Display::return_icon('invisible.png', get_lang('ResultsHiddenByExerciseSetting')); |
||
924 | } else { |
||
925 | if (is_numeric($totalScore)) { |
||
926 | $finalScore = $totalScore.'%'; |
||
927 | } else { |
||
928 | $finalScore = $totalScore; |
||
929 | } |
||
930 | } |
||
931 | $progress = learnpath::getProgress($lpId, $userId, $courseId, $sessionId); |
||
932 | $timeTotal = '<th style="text-align:center;">'.$totalTime.'</th>'; |
||
933 | if ($hideTime) { |
||
934 | $timeTotal = ''; |
||
935 | } |
||
936 | |||
937 | $output .= '<tr> |
||
938 | <th><i>'.get_lang('AccomplishedStepsTotal').'</i></th> |
||
939 | <th style="text-align:center;">'.$progress.'%</th> |
||
940 | <th style="text-align:center;">'.$finalScore.'</th> |
||
941 | '.$timeTotal.' |
||
942 | </tr></tbody></table>'; |
||
943 | |||
944 | return $output; |
||
945 | } |
||
946 | |||
947 | /** |
||
948 | * @param int $user_id |
||
949 | * @param array $courseInfo |
||
950 | * @param int $session_id |
||
951 | * @param string $origin |
||
952 | * @param bool $export_csv |
||
953 | * @param int $lp_id |
||
954 | * @param int $lp_item_id |
||
955 | * @param int $extendId |
||
956 | * @param int $extendAttemptId |
||
957 | * @param string $extendedAttempt |
||
958 | * @param string $extendedAll |
||
959 | * @param string $type classic or simple |
||
960 | * @param bool $allowExtend Optional. Allow or not extend te results |
||
961 | * |
||
962 | * @return string |
||
963 | */ |
||
964 | public static function getLpStats( |
||
965 | $user_id, |
||
966 | $courseInfo, |
||
967 | $session_id, |
||
968 | $origin, |
||
969 | $export_csv, |
||
970 | $lp_id, |
||
971 | $lp_item_id = null, |
||
972 | $extendId = null, |
||
973 | $extendAttemptId = null, |
||
974 | $extendedAttempt = null, |
||
975 | $extendedAll = null, |
||
976 | $type = 'classic', |
||
977 | $allowExtend = true |
||
978 | ) { |
||
979 | if (empty($courseInfo) || empty($lp_id)) { |
||
980 | return ''; |
||
981 | } |
||
982 | |||
983 | $hideTime = api_get_configuration_value('hide_lp_time'); |
||
984 | $lp_id = (int) $lp_id; |
||
985 | $lp_item_id = (int) $lp_item_id; |
||
986 | $user_id = (int) $user_id; |
||
987 | $session_id = (int) $session_id; |
||
988 | $origin = Security::remove_XSS($origin); |
||
989 | $list = learnpath::get_flat_ordered_items_list($lp_id, 0, $courseInfo['real_id']); |
||
990 | $is_allowed_to_edit = api_is_allowed_to_edit(null, true); |
||
991 | $course_id = $courseInfo['real_id']; |
||
992 | $courseCode = $courseInfo['code']; |
||
993 | $session_condition = api_get_session_condition($session_id); |
||
994 | |||
995 | // Extend all button |
||
996 | $output = ''; |
||
997 | |||
998 | $extra = '<script> |
||
999 | $(function() { |
||
1000 | $( "#dialog:ui-dialog" ).dialog( "destroy" ); |
||
1001 | $( "#dialog-confirm" ).dialog({ |
||
1002 | autoOpen: false, |
||
1003 | show: "blind", |
||
1004 | resizable: false, |
||
1005 | height:300, |
||
1006 | modal: true |
||
1007 | }); |
||
1008 | |||
1009 | $(".export").click(function() { |
||
1010 | var targetUrl = $(this).attr("href"); |
||
1011 | $( "#dialog-confirm" ).dialog({ |
||
1012 | width:400, |
||
1013 | height:300, |
||
1014 | buttons: { |
||
1015 | "'.addslashes(get_lang('Download')).'": function() { |
||
1016 | var option = $("input[name=add_logo]:checked").val(); |
||
1017 | location.href = targetUrl+"&add_logo="+option; |
||
1018 | $(this).dialog("close"); |
||
1019 | } |
||
1020 | } |
||
1021 | }); |
||
1022 | $("#dialog-confirm").dialog("open"); |
||
1023 | |||
1024 | return false; |
||
1025 | }); |
||
1026 | }); |
||
1027 | </script>'; |
||
1028 | |||
1029 | $extra .= '<div id="dialog-confirm" title="'.get_lang('ConfirmYourChoice').'">'; |
||
1030 | $form = new FormValidator('report', 'post', null, null, ['class' => 'form-vertical']); |
||
1031 | $form->addCheckBox('add_logo', '', get_lang('AddRightLogo'), ['id' => 'export_format_csv_label']); |
||
1032 | $extra .= $form->returnForm(); |
||
1033 | $extra .= '</div>'; |
||
1034 | |||
1035 | $output .= $extra; |
||
1036 | |||
1037 | $url_suffix = '&lp_id='.$lp_id; |
||
1038 | if ('tracking' === $origin) { |
||
1039 | $url_suffix = '&session_id='.$session_id.'&course='.$courseCode.'&student_id='.$user_id.'&lp_id='.$lp_id.'&origin='.$origin; |
||
1040 | } |
||
1041 | |||
1042 | $extend_all = 0; |
||
1043 | if (!empty($extendedAll)) { |
||
1044 | $extend_all_link = Display::url( |
||
1045 | Display::return_icon('view_less_stats.gif', get_lang('HideAllAttempts')), |
||
1046 | api_get_self().'?action=stats'.$url_suffix |
||
1047 | ); |
||
1048 | $extend_all = 1; |
||
1049 | } else { |
||
1050 | $extend_all_link = Display::url( |
||
1051 | Display::return_icon('view_more_stats.gif', get_lang('ShowAllAttempts')), |
||
1052 | api_get_self().'?action=stats&extend_all=1'.$url_suffix |
||
1053 | ); |
||
1054 | } |
||
1055 | |||
1056 | if ($origin != 'tracking') { |
||
1057 | $output .= '<div class="section-status">'; |
||
1058 | $output .= Display::page_header(get_lang('ScormMystatus')); |
||
1059 | $output .= '</div>'; |
||
1060 | } |
||
1061 | |||
1062 | $actionColumn = null; |
||
1063 | if ($type === 'classic') { |
||
1064 | $actionColumn = ' <th>'.get_lang('Actions').'</th>'; |
||
1065 | } |
||
1066 | |||
1067 | $timeHeader = '<th class="lp_time" colspan="2">'.get_lang('ScormTime').'</th>'; |
||
1068 | if ($hideTime) { |
||
1069 | $timeHeader = ''; |
||
1070 | } |
||
1071 | $output .= '<div class="table-responsive">'; |
||
1072 | $output .= '<table id="lp_tracking" class="table tracking"> |
||
1073 | <thead> |
||
1074 | <tr class="table-header"> |
||
1075 | <th width="16">'.($allowExtend == true ? $extend_all_link : ' ').'</th> |
||
1076 | <th colspan="4"> |
||
1077 | '.get_lang('ScormLessonTitle').' |
||
1078 | </th> |
||
1079 | <th colspan="2"> |
||
1080 | '.get_lang('ScormStatus').' |
||
1081 | </th> |
||
1082 | <th colspan="2"> |
||
1083 | '.get_lang('ScormScore').' |
||
1084 | </th> |
||
1085 | '.$timeHeader.' |
||
1086 | '.$actionColumn.' |
||
1087 | </tr> |
||
1088 | </thead> |
||
1089 | <tbody> |
||
1090 | '; |
||
1091 | |||
1092 | // Going through the items using the $items[] array instead of the database order ensures |
||
1093 | // we get them in the same order as in the imsmanifest file, which is rather random when using |
||
1094 | // the database table. |
||
1095 | $TBL_LP_ITEM = Database::get_course_table(TABLE_LP_ITEM); |
||
1096 | $TBL_LP_ITEM_VIEW = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
1097 | $TBL_LP_VIEW = Database::get_course_table(TABLE_LP_VIEW); |
||
1098 | $tbl_quiz_questions = Database::get_course_table(TABLE_QUIZ_QUESTION); |
||
1099 | $TBL_QUIZ = Database::get_course_table(TABLE_QUIZ_TEST); |
||
1100 | $tbl_stats_exercices = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1101 | $tbl_stats_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
1102 | |||
1103 | $sql = "SELECT max(view_count) |
||
1104 | FROM $TBL_LP_VIEW |
||
1105 | WHERE |
||
1106 | c_id = $course_id AND |
||
1107 | lp_id = $lp_id AND |
||
1108 | user_id = $user_id |
||
1109 | $session_condition"; |
||
1110 | $res = Database::query($sql); |
||
1111 | $view = 0; |
||
1112 | if (Database::num_rows($res) > 0) { |
||
1113 | $myrow = Database::fetch_array($res); |
||
1114 | $view = (int) $myrow[0]; |
||
1115 | } |
||
1116 | |||
1117 | $counter = 0; |
||
1118 | $total_time = 0; |
||
1119 | $h = get_lang('h'); |
||
1120 | |||
1121 | if (!empty($export_csv)) { |
||
1122 | $csvHeaders = [ |
||
1123 | get_lang('ScormLessonTitle'), |
||
1124 | get_lang('ScormStatus'), |
||
1125 | get_lang('ScormScore'), |
||
1126 | ]; |
||
1127 | |||
1128 | if ($hideTime === false) { |
||
1129 | $csvHeaders[] = get_lang('ScormTime'); |
||
1130 | } |
||
1131 | |||
1132 | $csv_content[] = $csvHeaders; |
||
1133 | } |
||
1134 | |||
1135 | $result_disabled_ext_all = true; |
||
1136 | $chapterTypes = learnpath::getChapterTypes(); |
||
1137 | $accessToPdfExport = api_is_allowed_to_edit(false, false, true); |
||
1138 | |||
1139 | $minimumAvailable = self::minimumTimeAvailable($session_id, $course_id); |
||
1140 | $timeCourse = []; |
||
1141 | if ($minimumAvailable) { |
||
1142 | $timeCourse = self::getCalculateTime($user_id, $course_id, $session_id); |
||
1143 | Session::write('trackTimeCourse', $timeCourse); |
||
1144 | } |
||
1145 | |||
1146 | // Show lp items |
||
1147 | if (is_array($list) && count($list) > 0) { |
||
1148 | foreach ($list as $my_item_id) { |
||
1149 | $extend_this = 0; |
||
1150 | $order = 'DESC'; |
||
1151 | if ((!empty($extendId) && $extendId == $my_item_id) || $extend_all) { |
||
1152 | $extend_this = 1; |
||
1153 | $order = 'ASC'; |
||
1154 | } |
||
1155 | |||
1156 | // Prepare statement to go through each attempt. |
||
1157 | $viewCondition = null; |
||
1158 | if (!empty($view)) { |
||
1159 | $viewCondition = " AND v.view_count = $view "; |
||
1160 | } |
||
1161 | |||
1162 | $sql = "SELECT |
||
1163 | iv.status as mystatus, |
||
1164 | v.view_count as mycount, |
||
1165 | iv.score as myscore, |
||
1166 | iv.total_time as mytime, |
||
1167 | i.iid as myid, |
||
1168 | i.lp_id as mylpid, |
||
1169 | iv.lp_view_id as mylpviewid, |
||
1170 | i.title as mytitle, |
||
1171 | i.max_score as mymaxscore, |
||
1172 | iv.max_score as myviewmaxscore, |
||
1173 | i.item_type as item_type, |
||
1174 | iv.view_count as iv_view_count, |
||
1175 | iv.id as iv_id, |
||
1176 | path |
||
1177 | FROM $TBL_LP_ITEM as i |
||
1178 | INNER JOIN $TBL_LP_ITEM_VIEW as iv |
||
1179 | ON (i.iid = iv.lp_item_id AND i.c_id = iv.c_id) |
||
1180 | INNER JOIN $TBL_LP_VIEW as v |
||
1181 | ON (iv.lp_view_id = v.id AND v.c_id = iv.c_id) |
||
1182 | WHERE |
||
1183 | v.c_id = $course_id AND |
||
1184 | i.iid = $my_item_id AND |
||
1185 | i.lp_id = $lp_id AND |
||
1186 | v.user_id = $user_id AND |
||
1187 | v.session_id = $session_id |
||
1188 | $viewCondition |
||
1189 | ORDER BY iv.view_count $order "; |
||
1190 | |||
1191 | $result = Database::query($sql); |
||
1192 | $num = Database::num_rows($result); |
||
1193 | $time_for_total = 0; |
||
1194 | |||
1195 | // Extend all |
||
1196 | if (($extend_this || $extend_all) && $num > 0) { |
||
1197 | $row = Database::fetch_array($result); |
||
1198 | $result_disabled_ext_all = false; |
||
1199 | if ('quiz' === $row['item_type']) { |
||
1200 | // Check results_disabled in quiz table. |
||
1201 | $lpItemPath = (int) $row['path']; |
||
1202 | $sql = "SELECT results_disabled |
||
1203 | FROM $TBL_QUIZ |
||
1204 | WHERE |
||
1205 | iid = $lpItemPath"; |
||
1206 | $res_result_disabled = Database::query($sql); |
||
1207 | $row_result_disabled = Database::fetch_row($res_result_disabled); |
||
1208 | |||
1209 | if (Database::num_rows($res_result_disabled) > 0 |
||
1210 | && 1 === (int) $row_result_disabled[0] |
||
1211 | ) { |
||
1212 | $result_disabled_ext_all = true; |
||
1213 | } |
||
1214 | } |
||
1215 | |||
1216 | // If there are several attempts, and the link to extend has been clicked, show each attempt... |
||
1217 | $oddclass = 'row_even'; |
||
1218 | if (($counter % 2) === 0) { |
||
1219 | $oddclass = 'row_odd'; |
||
1220 | } |
||
1221 | $extend_link = ''; |
||
1222 | if (!empty($inter_num)) { |
||
1223 | $extend_link = Display::url( |
||
1224 | Display::return_icon( |
||
1225 | 'visible.png', |
||
1226 | get_lang('HideAttemptView') |
||
1227 | ), |
||
1228 | api_get_self().'?action=stats&fold_id='.$my_item_id.$url_suffix |
||
1229 | ); |
||
1230 | } |
||
1231 | $title = $row['mytitle']; |
||
1232 | |||
1233 | if (empty($title)) { |
||
1234 | $title = learnpath::rl_get_resource_name($courseInfo['code'], $lp_id, $row['myid']); |
||
1235 | } |
||
1236 | |||
1237 | if (in_array($row['item_type'], $chapterTypes)) { |
||
1238 | $title = "<h4> $title </h4>"; |
||
1239 | } |
||
1240 | $lesson_status = $row['mystatus']; |
||
1241 | $title = Security::remove_XSS($title); |
||
1242 | $counter++; |
||
1243 | |||
1244 | $action = null; |
||
1245 | if ('classic' === $type) { |
||
1246 | $action = '<td></td>'; |
||
1247 | } |
||
1248 | |||
1249 | if (in_array($row['item_type'], $chapterTypes)) { |
||
1250 | $output .= '<tr class="'.$oddclass.'"> |
||
1251 | <td>'.$extend_link.'</td> |
||
1252 | <td colspan="4"> |
||
1253 | '.$title.' |
||
1254 | </td> |
||
1255 | <td colspan="2">'.learnpathItem::humanize_status($lesson_status, true, $type).'</td> |
||
1256 | <td colspan="2"></td> |
||
1257 | <td colspan="2"></td> |
||
1258 | '.$action.' |
||
1259 | </tr>'; |
||
1260 | continue; |
||
1261 | } else { |
||
1262 | $output .= '<tr class="'.$oddclass.'"> |
||
1263 | <td>'.$extend_link.'</td> |
||
1264 | <td colspan="4">'.$title.'</td> |
||
1265 | <td colspan="2"></td> |
||
1266 | <td colspan="2"></td> |
||
1267 | <td colspan="2"></td> |
||
1268 | '.$action.' |
||
1269 | </tr>'; |
||
1270 | } |
||
1271 | |||
1272 | $attemptCount = 1; |
||
1273 | do { |
||
1274 | // Check if there are interactions below. |
||
1275 | $extend_attempt_link = ''; |
||
1276 | $extend_this_attempt = 0; |
||
1277 | |||
1278 | if ($timeCourse) { |
||
1279 | // $attemptResult = 0; |
||
1280 | if (isset($timeCourse['learnpath_detailed']) |
||
1281 | && isset($timeCourse['learnpath_detailed'][$lp_id]) |
||
1282 | && isset($timeCourse['learnpath_detailed'][$lp_id][$my_item_id]) |
||
1283 | ) { |
||
1284 | $attemptResult = $timeCourse['learnpath_detailed'][$lp_id][$my_item_id][$row['iv_view_count']]; |
||
1285 | } |
||
1286 | } |
||
1287 | if (( |
||
1288 | learnpath::get_interactions_count_from_db($row['iv_id'], $course_id) > 0 |
||
1289 | || learnpath::get_objectives_count_from_db($row['iv_id'], $course_id) > 0 |
||
1290 | ) |
||
1291 | && !$extend_all |
||
1292 | ) { |
||
1293 | if ($extendAttemptId == $row['iv_id']) { |
||
1294 | // The extend button for this attempt has been clicked. |
||
1295 | $extend_this_attempt = 1; |
||
1296 | $extend_attempt_link = Display::url( |
||
1297 | Display::return_icon('visible.png', get_lang('HideAttemptView')), |
||
1298 | api_get_self().'?action=stats&extend_id='.$my_item_id.'&fold_attempt_id='.$row['iv_id'].$url_suffix |
||
1299 | ); |
||
1300 | if ($accessToPdfExport) { |
||
1301 | $extend_attempt_link .= ' '. |
||
1302 | Display::url( |
||
1303 | Display::return_icon('pdf.png', get_lang('ExportToPdf')), |
||
1304 | api_get_self().'?action=export_stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix, |
||
1305 | ['class' => 'export'] |
||
1306 | ); |
||
1307 | } |
||
1308 | } else { // Same case if fold_attempt_id is set, so not implemented explicitly. |
||
1309 | // The extend button for this attempt has not been clicked. |
||
1310 | $extend_attempt_link = Display::url( |
||
1311 | Display::return_icon('invisible.png', get_lang('ExtendAttemptView')), |
||
1312 | api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix |
||
1313 | ); |
||
1314 | if ($accessToPdfExport) { |
||
1315 | $extend_attempt_link .= ' '. |
||
1316 | Display::url( |
||
1317 | Display::return_icon('pdf.png', get_lang('ExportToPdf')), |
||
1318 | api_get_self().'?action=export_stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix, |
||
1319 | ['class' => 'export'] |
||
1320 | ); |
||
1321 | } |
||
1322 | } |
||
1323 | } |
||
1324 | |||
1325 | $oddclass = 'row_even'; |
||
1326 | if (($counter % 2) == 0) { |
||
1327 | $oddclass = 'row_odd'; |
||
1328 | } |
||
1329 | |||
1330 | $lesson_status = $row['mystatus']; |
||
1331 | $score = $row['myscore']; |
||
1332 | $time_for_total += $row['mytime']; |
||
1333 | $attemptTime = $row['mytime']; |
||
1334 | |||
1335 | if ($minimumAvailable) { |
||
1336 | /*$lp_time = $timeCourse[TOOL_LEARNPATH]; |
||
1337 | $lpTime = null; |
||
1338 | if (isset($lp_time[$lp_id])) { |
||
1339 | $lpTime = (int) $lp_time[$lp_id]; |
||
1340 | } |
||
1341 | $time_for_total = $lpTime;*/ |
||
1342 | $time_for_total = (int) $attemptResult; |
||
1343 | $attemptTime = (int) $attemptResult; |
||
1344 | } |
||
1345 | |||
1346 | $time = learnpathItem::getScormTimeFromParameter('js', $attemptTime); |
||
1347 | |||
1348 | if ($score == 0) { |
||
1349 | $maxscore = $row['mymaxscore']; |
||
1350 | } else { |
||
1351 | if ($row['item_type'] === 'sco') { |
||
1352 | if (!empty($row['myviewmaxscore']) && $row['myviewmaxscore'] > 0) { |
||
1353 | $maxscore = $row['myviewmaxscore']; |
||
1354 | } elseif ($row['myviewmaxscore'] === '') { |
||
1355 | $maxscore = 0; |
||
1356 | } else { |
||
1357 | $maxscore = $row['mymaxscore']; |
||
1358 | } |
||
1359 | } else { |
||
1360 | $maxscore = $row['mymaxscore']; |
||
1361 | } |
||
1362 | } |
||
1363 | |||
1364 | // Remove "NaN" if any (@todo: locate the source of these NaN) |
||
1365 | $time = str_replace('NaN', '00'.$h.'00\'00"', $time); |
||
1366 | if ($row['item_type'] !== 'dir') { |
||
1367 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
1368 | $view_score = Display::return_icon( |
||
1369 | 'invisible.png', |
||
1370 | get_lang('ResultsHiddenByExerciseSetting') |
||
1371 | ); |
||
1372 | } else { |
||
1373 | switch ($row['item_type']) { |
||
1374 | case 'sco': |
||
1375 | if ($maxscore == 0) { |
||
1376 | $view_score = $score; |
||
1377 | } else { |
||
1378 | $view_score = ExerciseLib::show_score( |
||
1379 | $score, |
||
1380 | $maxscore, |
||
1381 | false |
||
1382 | ); |
||
1383 | } |
||
1384 | break; |
||
1385 | case 'document': |
||
1386 | $view_score = ($score == 0 ? '/' : ExerciseLib::show_score($score, $maxscore, false)); |
||
1387 | break; |
||
1388 | default: |
||
1389 | $view_score = ExerciseLib::show_score( |
||
1390 | $score, |
||
1391 | $maxscore, |
||
1392 | false |
||
1393 | ); |
||
1394 | break; |
||
1395 | } |
||
1396 | } |
||
1397 | |||
1398 | $action = null; |
||
1399 | if ($type === 'classic') { |
||
1400 | $action = '<td></td>'; |
||
1401 | } |
||
1402 | $timeRow = '<td class="lp_time" colspan="2">'.$time.'</td>'; |
||
1403 | if ($hideTime) { |
||
1404 | $timeRow = ''; |
||
1405 | } |
||
1406 | $output .= '<tr class="'.$oddclass.'"> |
||
1407 | <td></td> |
||
1408 | <td style="width:70px;float:left;">'.$extend_attempt_link.'</td> |
||
1409 | <td colspan="3">'.get_lang('Attempt').' '.$attemptCount.'</td> |
||
1410 | <td colspan="2">'.learnpathItem::humanize_status($lesson_status, true, $type).'</td> |
||
1411 | <td colspan="2">'.$view_score.'</td> |
||
1412 | '.$timeRow.' |
||
1413 | '.$action.' |
||
1414 | </tr>'; |
||
1415 | $attemptCount++; |
||
1416 | if (!empty($export_csv)) { |
||
1417 | $temp = []; |
||
1418 | $temp[] = $title = Security::remove_XSS($title); |
||
1419 | $temp[] = Security::remove_XSS( |
||
1420 | learnpathItem::humanize_status($lesson_status, false, $type) |
||
1421 | ); |
||
1422 | |||
1423 | if ($row['item_type'] === 'quiz') { |
||
1424 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
1425 | $temp[] = '/'; |
||
1426 | } else { |
||
1427 | $temp[] = ($score == 0 ? '0/'.$maxscore : ($maxscore == 0 ? $score : $score.'/'.float_format($maxscore, 1))); |
||
1428 | } |
||
1429 | } else { |
||
1430 | $temp[] = ($score == 0 ? '/' : ($maxscore == 0 ? $score : $score.'/'.float_format($maxscore, 1))); |
||
1431 | } |
||
1432 | |||
1433 | if ($hideTime === false) { |
||
1434 | $temp[] = $time; |
||
1435 | } |
||
1436 | $csv_content[] = $temp; |
||
1437 | } |
||
1438 | } |
||
1439 | |||
1440 | $counter++; |
||
1441 | $action = null; |
||
1442 | if ($type === 'classic') { |
||
1443 | $action = '<td></td>'; |
||
1444 | } |
||
1445 | |||
1446 | if ($extend_this_attempt || $extend_all) { |
||
1447 | $list1 = learnpath::get_iv_interactions_array($row['iv_id'], $course_id); |
||
1448 | foreach ($list1 as $id => $interaction) { |
||
1449 | $oddclass = 'row_even'; |
||
1450 | if (($counter % 2) == 0) { |
||
1451 | $oddclass = 'row_odd'; |
||
1452 | } |
||
1453 | $timeRow = '<td class="lp_time">'.$interaction['time'].'</td>'; |
||
1454 | if ($hideTime) { |
||
1455 | $timeRow = ''; |
||
1456 | } |
||
1457 | |||
1458 | $output .= '<tr class="'.$oddclass.'"> |
||
1459 | <td></td> |
||
1460 | <td></td> |
||
1461 | <td></td> |
||
1462 | <td>'.$interaction['order_id'].'</td> |
||
1463 | <td>'.$interaction['id'].'</td>'; |
||
1464 | |||
1465 | $output .= ' |
||
1466 | <td colspan="2">'.$interaction['type'].'</td> |
||
1467 | <td>'.$interaction['student_response_formatted'].'</td> |
||
1468 | <td>'.$interaction['result'].'</td> |
||
1469 | <td>'.$interaction['latency'].'</td> |
||
1470 | '.$timeRow.' |
||
1471 | '.$action.' |
||
1472 | </tr>'; |
||
1473 | $counter++; |
||
1474 | } |
||
1475 | $list2 = learnpath::get_iv_objectives_array($row['iv_id'], $course_id); |
||
1476 | foreach ($list2 as $id => $interaction) { |
||
1477 | $oddclass = 'row_even'; |
||
1478 | if (($counter % 2) === 0) { |
||
1479 | $oddclass = 'row_odd'; |
||
1480 | } |
||
1481 | $output .= '<tr class="'.$oddclass.'"> |
||
1482 | <td></td> |
||
1483 | <td></td> |
||
1484 | <td></td> |
||
1485 | <td>'.$interaction['order_id'].'</td> |
||
1486 | <td colspan="2">'.$interaction['objective_id'].'</td> |
||
1487 | <td colspan="2">'.$interaction['status'].'</td> |
||
1488 | <td>'.$interaction['score_raw'].'</td> |
||
1489 | <td>'.$interaction['score_max'].'</td> |
||
1490 | <td>'.$interaction['score_min'].'</td> |
||
1491 | '.$action.' |
||
1492 | </tr>'; |
||
1493 | $counter++; |
||
1494 | } |
||
1495 | } |
||
1496 | } while ($row = Database::fetch_array($result)); |
||
1497 | } elseif ($num > 0) { |
||
1498 | // Not extended. |
||
1499 | $row = Database::fetch_array($result, 'ASSOC'); |
||
1500 | $my_id = $row['myid']; |
||
1501 | $my_lp_id = $row['mylpid']; |
||
1502 | $my_lp_view_id = $row['mylpviewid']; |
||
1503 | $lpItemPath = (int) $row['path']; |
||
1504 | $result_disabled_ext_all = false; |
||
1505 | if ($row['item_type'] === 'quiz') { |
||
1506 | // Check results_disabled in quiz table. |
||
1507 | $sql = "SELECT results_disabled |
||
1508 | FROM $TBL_QUIZ |
||
1509 | WHERE iid = $lpItemPath"; |
||
1510 | $res_result_disabled = Database::query($sql); |
||
1511 | $row_result_disabled = Database::fetch_row($res_result_disabled); |
||
1512 | |||
1513 | if (Database::num_rows($res_result_disabled) > 0 |
||
1514 | && (int) $row_result_disabled[0] === 1 |
||
1515 | ) { |
||
1516 | $result_disabled_ext_all = true; |
||
1517 | } |
||
1518 | } |
||
1519 | |||
1520 | // Check if there are interactions below |
||
1521 | $extend_this_attempt = 0; |
||
1522 | $inter_num = learnpath::get_interactions_count_from_db($row['iv_id'], $course_id); |
||
1523 | $objec_num = learnpath::get_objectives_count_from_db($row['iv_id'], $course_id); |
||
1524 | $extend_attempt_link = ''; |
||
1525 | if ($inter_num > 0 || $objec_num > 0) { |
||
1526 | if (!empty($extendAttemptId) && $extendAttemptId == $row['iv_id']) { |
||
1527 | // The extend button for this attempt has been clicked. |
||
1528 | $extend_this_attempt = 1; |
||
1529 | $extend_attempt_link = Display::url( |
||
1530 | Display::return_icon('visible.png', get_lang('HideAttemptView')), |
||
1531 | api_get_self().'?action=stats&extend_id='.$my_item_id.'&fold_attempt_id='.$row['iv_id'].$url_suffix |
||
1532 | ); |
||
1533 | } else { |
||
1534 | // Same case if fold_attempt_id is set, so not implemented explicitly. |
||
1535 | // The extend button for this attempt has not been clicked. |
||
1536 | $extend_attempt_link = Display::url( |
||
1537 | Display::return_icon('invisible.png', get_lang('ExtendAttemptView')), |
||
1538 | api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix |
||
1539 | ); |
||
1540 | } |
||
1541 | } |
||
1542 | |||
1543 | $oddclass = 'row_even'; |
||
1544 | if (($counter % 2) == 0) { |
||
1545 | $oddclass = 'row_odd'; |
||
1546 | } |
||
1547 | |||
1548 | $extend_link = ''; |
||
1549 | if ($inter_num > 1) { |
||
1550 | $extend_link = Display::url( |
||
1551 | Display::return_icon('invisible.png', get_lang('ExtendAttemptView')), |
||
1552 | api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix |
||
1553 | ); |
||
1554 | } |
||
1555 | $lesson_status = $row['mystatus']; |
||
1556 | $score = $row['myscore']; |
||
1557 | $subtotal_time = $row['mytime']; |
||
1558 | |||
1559 | // This is necessary for fix the total time |
||
1560 | $h5pImportEnable = api_get_plugin_setting('h5pimport', 'tool_enable'); |
||
1561 | if ($row['item_type'] === 'h5p' && 'true' === $h5pImportEnable) { |
||
1562 | $subtotal_time = H5pImportPlugin::fixTotalTimeInLpItemView( |
||
1563 | $row['iv_id'], |
||
1564 | $user_id |
||
1565 | ); |
||
1566 | } |
||
1567 | while ($tmp_row = Database::fetch_array($result)) { |
||
1568 | $subtotal_time += $tmp_row['mytime']; |
||
1569 | } |
||
1570 | |||
1571 | $title = $row['mytitle']; |
||
1572 | // Selecting the exe_id from stats attempts tables in order to look the max score value. |
||
1573 | $sql = 'SELECT * FROM '.$tbl_stats_exercices.' |
||
1574 | WHERE |
||
1575 | exe_exo_id="'.$row['path'].'" AND |
||
1576 | exe_user_id="'.$user_id.'" AND |
||
1577 | orig_lp_id = "'.$lp_id.'" AND |
||
1578 | orig_lp_item_id = "'.$row['myid'].'" AND |
||
1579 | c_id = '.$course_id.' AND |
||
1580 | status <> "incomplete" AND |
||
1581 | session_id = '.$session_id.' |
||
1582 | ORDER BY exe_date DESC |
||
1583 | LIMIT 1'; |
||
1584 | |||
1585 | $resultLastAttempt = Database::query($sql); |
||
1586 | $num = Database::num_rows($resultLastAttempt); |
||
1587 | $id_last_attempt = null; |
||
1588 | if ($num > 0) { |
||
1589 | while ($rowLA = Database::fetch_array($resultLastAttempt)) { |
||
1590 | $id_last_attempt = $rowLA['exe_id']; |
||
1591 | } |
||
1592 | } |
||
1593 | |||
1594 | switch ($row['item_type']) { |
||
1595 | case 'sco': |
||
1596 | if (!empty($row['myviewmaxscore']) && $row['myviewmaxscore'] > 0) { |
||
1597 | $maxscore = $row['myviewmaxscore']; |
||
1598 | } elseif ($row['myviewmaxscore'] === '') { |
||
1599 | $maxscore = 0; |
||
1600 | } else { |
||
1601 | $maxscore = $row['mymaxscore']; |
||
1602 | } |
||
1603 | break; |
||
1604 | case 'quiz': |
||
1605 | // Get score and total time from last attempt of a exercise en lp. |
||
1606 | $sql = "SELECT iid, score |
||
1607 | FROM $TBL_LP_ITEM_VIEW |
||
1608 | WHERE |
||
1609 | c_id = ".(int) $course_id." AND |
||
1610 | lp_item_id = ".(int) $my_id." AND |
||
1611 | lp_view_id = ".(int) $my_lp_view_id." |
||
1612 | ORDER BY view_count DESC |
||
1613 | LIMIT 1"; |
||
1614 | |||
1615 | $res_score = Database::query($sql); |
||
1616 | $row_score = Database::fetch_array($res_score); |
||
1617 | |||
1618 | $sql = "SELECT SUM(total_time) AS total_time |
||
1619 | FROM $TBL_LP_ITEM_VIEW |
||
1620 | WHERE |
||
1621 | c_id = ".(int) $course_id." AND |
||
1622 | lp_item_id = ".(int) $my_id." AND |
||
1623 | lp_view_id = ".(int) $my_lp_view_id; |
||
1624 | $res_time = Database::query($sql); |
||
1625 | $row_time = Database::fetch_array($res_time); |
||
1626 | |||
1627 | $score = 0; |
||
1628 | $subtotal_time = 0; |
||
1629 | if (Database::num_rows($res_score) > 0 |
||
1630 | && Database::num_rows($res_time) > 0 |
||
1631 | ) { |
||
1632 | $score = (float) $row_score['score']; |
||
1633 | $subtotal_time = (int) $row_time['total_time']; |
||
1634 | } |
||
1635 | // Selecting the max score from an attempt. |
||
1636 | $sql = "SELECT SUM(t.ponderation) as maxscore |
||
1637 | FROM ( |
||
1638 | SELECT DISTINCT |
||
1639 | question_id, marks, ponderation |
||
1640 | FROM $tbl_stats_attempts as at |
||
1641 | INNER JOIN $tbl_quiz_questions as q |
||
1642 | ON q.iid = at.question_id |
||
1643 | WHERE exe_id ='$id_last_attempt' |
||
1644 | ) as t"; |
||
1645 | |||
1646 | $result = Database::query($sql); |
||
1647 | $row_max_score = Database::fetch_array($result); |
||
1648 | $maxscore = $row_max_score['maxscore']; |
||
1649 | |||
1650 | // Get duration time from track_e_exercises.exe_duration instead of lp_view_item.total_time |
||
1651 | $sql = 'SELECT SUM(exe_duration) exe_duration |
||
1652 | FROM '.$tbl_stats_exercices.' |
||
1653 | WHERE |
||
1654 | exe_exo_id="'.$row['path'].'" AND |
||
1655 | exe_user_id="'.$user_id.'" AND |
||
1656 | orig_lp_id = "'.$lp_id.'" AND |
||
1657 | orig_lp_item_id = "'.$row['myid'].'" AND |
||
1658 | c_id = '.$course_id.' AND |
||
1659 | status <> "incomplete" AND |
||
1660 | session_id = '.$session_id.' |
||
1661 | ORDER BY exe_date DESC '; |
||
1662 | $sumScoreResult = Database::query($sql); |
||
1663 | $durationRow = Database::fetch_array($sumScoreResult, 'ASSOC'); |
||
1664 | if (!empty($durationRow['exe_duration'])) { |
||
1665 | $exeDuration = $durationRow['exe_duration']; |
||
1666 | if ($exeDuration != $subtotal_time |
||
1667 | && !empty($row_score['iid']) |
||
1668 | && !empty($exeDuration) |
||
1669 | ) { |
||
1670 | $subtotal_time = $exeDuration; |
||
1671 | // Update c_lp_item_view.total_time |
||
1672 | $sqlUpdate = "UPDATE $TBL_LP_ITEM_VIEW SET total_time = '$exeDuration' |
||
1673 | WHERE iid = ".$row_score['iid']; |
||
1674 | Database::query($sqlUpdate); |
||
1675 | } |
||
1676 | } |
||
1677 | break; |
||
1678 | case 'h5p': |
||
1679 | if ($row['item_type'] === 'h5p' && 'true' === $h5pImportEnable) { |
||
1680 | $sql = "SELECT iid, score |
||
1681 | FROM $TBL_LP_ITEM_VIEW |
||
1682 | WHERE |
||
1683 | c_id = ".(int) $course_id." AND |
||
1684 | lp_item_id = ".(int) $my_id." AND |
||
1685 | lp_view_id = ".(int) $my_lp_view_id." |
||
1686 | ORDER BY view_count DESC |
||
1687 | LIMIT 1"; |
||
1688 | $res_score = Database::query($sql); |
||
1689 | $row_score = Database::fetch_array($res_score); |
||
1690 | |||
1691 | H5pImportPlugin::fixTotalTimeInLpItemView($row_score['iid'], $user_id); |
||
1692 | } |
||
1693 | break; |
||
1694 | default: |
||
1695 | $maxscore = $row['mymaxscore']; |
||
1696 | break; |
||
1697 | } |
||
1698 | |||
1699 | $time_for_total = $subtotal_time; |
||
1700 | $time = learnpathItem::getScormTimeFromParameter('js', $subtotal_time); |
||
1701 | if (empty($title)) { |
||
1702 | $title = learnpath::rl_get_resource_name( |
||
1703 | $courseInfo['code'], |
||
1704 | $lp_id, |
||
1705 | $row['myid'] |
||
1706 | ); |
||
1707 | } |
||
1708 | |||
1709 | $action = null; |
||
1710 | if ($type === 'classic') { |
||
1711 | $action = '<td></td>'; |
||
1712 | } |
||
1713 | |||
1714 | if (in_array($row['item_type'], $chapterTypes)) { |
||
1715 | $title = Security::remove_XSS($title); |
||
1716 | $output .= '<tr class="'.$oddclass.'"> |
||
1717 | <td>'.$extend_link.'</td> |
||
1718 | <td colspan="10"> |
||
1719 | <h4>'.$title.'</h4> |
||
1720 | </td> |
||
1721 | '.$action.' |
||
1722 | </tr>'; |
||
1723 | } else { |
||
1724 | $correct_test_link = '-'; |
||
1725 | $showRowspan = false; |
||
1726 | $my_url_suffix = '&course='.$courseCode.'&student_id='.$user_id.'&lp_id='.intval($row['mylpid']).'&origin='.$origin; |
||
1727 | if ($row['item_type'] === 'quiz') { |
||
1728 | $sql = 'SELECT * FROM '.$tbl_stats_exercices.' |
||
1729 | WHERE |
||
1730 | exe_exo_id="'.$row['path'].'" AND |
||
1731 | exe_user_id="'.$user_id.'" AND |
||
1732 | orig_lp_id = "'.$lp_id.'" AND |
||
1733 | orig_lp_item_id = "'.$row['myid'].'" AND |
||
1734 | c_id = '.$course_id.' AND |
||
1735 | status <> "incomplete" AND |
||
1736 | session_id = '.$session_id.' |
||
1737 | ORDER BY exe_date DESC '; |
||
1738 | |||
1739 | $resultLastAttempt = Database::query($sql); |
||
1740 | $num = Database::num_rows($resultLastAttempt); |
||
1741 | $showRowspan = false; |
||
1742 | if ($num > 0) { |
||
1743 | $linkId = 'link_'.$my_id; |
||
1744 | if ($extendedAttempt == 1 |
||
1745 | && $lp_id == $my_lp_id |
||
1746 | && $lp_item_id == $my_id |
||
1747 | ) { |
||
1748 | $showRowspan = true; |
||
1749 | $correct_test_link = Display::url( |
||
1750 | Display::return_icon( |
||
1751 | 'view_less_stats.gif', |
||
1752 | get_lang('HideAllAttempts') |
||
1753 | ), |
||
1754 | api_get_self().'?action=stats'.$my_url_suffix.'&session_id='.$session_id.'&lp_item_id='.$my_id.'#'.$linkId, |
||
1755 | ['id' => $linkId] |
||
1756 | ); |
||
1757 | } else { |
||
1758 | $correct_test_link = Display::url( |
||
1759 | Display::return_icon( |
||
1760 | 'view_more_stats.gif', |
||
1761 | get_lang( |
||
1762 | 'ShowAllAttemptsByExercise' |
||
1763 | ) |
||
1764 | ), |
||
1765 | api_get_self().'?action=stats&extend_attempt=1'.$my_url_suffix.'&session_id='.$session_id.'&lp_item_id='.$my_id.'#'.$linkId, |
||
1766 | ['id' => $linkId] |
||
1767 | ); |
||
1768 | } |
||
1769 | } |
||
1770 | } |
||
1771 | if ($row['item_type'] === 'h5p' && 'true' === $h5pImportEnable) { |
||
1772 | $em = Database::getManager(); |
||
1773 | $cLpItemViewRepo = $em->getRepository('ChamiloPluginBundle:H5pImport\H5pImportResults'); |
||
1774 | $count = $cLpItemViewRepo->count(['user' => $user_id, 'cLpItemView' => $row['iv_id']]); |
||
1775 | |||
1776 | $showRowspan = false; |
||
1777 | if ($count > 0) { |
||
1778 | $linkId = 'link_'.$my_id; |
||
1779 | if ($extendedAttempt == 1 |
||
1780 | && $lp_id == $my_lp_id |
||
1781 | && $lp_item_id == $my_id |
||
1782 | ) { |
||
1783 | $showRowspan = true; |
||
1784 | $correct_test_link = Display::url( |
||
1785 | Display::return_icon( |
||
1786 | 'view_less_stats.gif', |
||
1787 | get_lang('HideAllAttempts') |
||
1788 | ), |
||
1789 | api_get_self().'?action=stats'.$my_url_suffix.'&session_id='.$session_id.'&lp_item_id='.$my_id.'#'.$linkId, |
||
1790 | ['id' => $linkId] |
||
1791 | ); |
||
1792 | } else { |
||
1793 | $correct_test_link = Display::url( |
||
1794 | Display::return_icon( |
||
1795 | 'view_more_stats.gif', |
||
1796 | get_lang( |
||
1797 | 'ShowAllAttemptsByExercise' |
||
1798 | ) |
||
1799 | ), |
||
1800 | api_get_self().'?action=stats&extend_attempt=1'.$my_url_suffix.'&session_id='.$session_id.'&lp_item_id='.$my_id.'#'.$linkId, |
||
1801 | ['id' => $linkId] |
||
1802 | ); |
||
1803 | } |
||
1804 | } |
||
1805 | } |
||
1806 | $title = Security::remove_XSS($title); |
||
1807 | $action = null; |
||
1808 | if ($type === 'classic') { |
||
1809 | $action = '<td '.($showRowspan ? 'rowspan="2"' : '').'>'.$correct_test_link.'</td>'; |
||
1810 | } |
||
1811 | |||
1812 | if ($lp_id == $my_lp_id && false) { |
||
1813 | $output .= '<tr class ='.$oddclass.'> |
||
1814 | <td>'.$extend_link.'</td> |
||
1815 | <td colspan="4">'.$title.'</td> |
||
1816 | <td colspan="2"> </td> |
||
1817 | <td colspan="2"> </td> |
||
1818 | <td colspan="2"> </td> |
||
1819 | '.$action.' |
||
1820 | </tr>'; |
||
1821 | $output .= '</tr>'; |
||
1822 | } else { |
||
1823 | if ($lp_id == $my_lp_id && $lp_item_id == $my_id) { |
||
1824 | $output .= "<tr class='$oddclass'>"; |
||
1825 | } else { |
||
1826 | $output .= "<tr class='$oddclass'>"; |
||
1827 | } |
||
1828 | |||
1829 | $scoreItem = null; |
||
1830 | if ($row['item_type'] === 'quiz') { |
||
1831 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
1832 | $scoreItem .= Display::return_icon( |
||
1833 | 'invisible.gif', |
||
1834 | get_lang('ResultsHiddenByExerciseSetting') |
||
1835 | ); |
||
1836 | } else { |
||
1837 | $scoreItem .= ExerciseLib::show_score($score, $maxscore, false); |
||
1838 | } |
||
1839 | } else { |
||
1840 | $scoreItem .= $score == 0 ? '/' : ($maxscore == 0 ? $score : $score.'/'.$maxscore); |
||
1841 | } |
||
1842 | |||
1843 | $timeRow = '<td class="lp_time" colspan="2">'.$time.'</td>'; |
||
1844 | if ($hideTime) { |
||
1845 | $timeRow = ''; |
||
1846 | } |
||
1847 | |||
1848 | $output .= ' |
||
1849 | <td>'.$extend_link.'</td> |
||
1850 | <td colspan="4">'.$title.'</td> |
||
1851 | <td colspan="2">'.learnpathitem::humanize_status($lesson_status).'</td> |
||
1852 | <td colspan="2">'.$scoreItem.'</td> |
||
1853 | '.$timeRow.' |
||
1854 | '.$action.' |
||
1855 | '; |
||
1856 | $output .= '</tr>'; |
||
1857 | } |
||
1858 | |||
1859 | if (!empty($export_csv)) { |
||
1860 | $temp = []; |
||
1861 | $temp[] = api_html_entity_decode($title, ENT_QUOTES); |
||
1862 | $temp[] = api_html_entity_decode($lesson_status, ENT_QUOTES); |
||
1863 | if ($row['item_type'] === 'quiz') { |
||
1864 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
1865 | $temp[] = '/'; |
||
1866 | } else { |
||
1867 | $temp[] = ($score == 0 ? '0/'.$maxscore : ($maxscore == 0 ? $score : $score.'/'.float_format($maxscore, 1))); |
||
1868 | } |
||
1869 | } else { |
||
1870 | $temp[] = ($score == 0 ? '/' : ($maxscore == 0 ? $score : $score.'/'.float_format($maxscore, 1))); |
||
1871 | } |
||
1872 | |||
1873 | if ($hideTime === false) { |
||
1874 | $temp[] = $time; |
||
1875 | } |
||
1876 | $csv_content[] = $temp; |
||
1877 | } |
||
1878 | } |
||
1879 | |||
1880 | $counter++; |
||
1881 | $action = null; |
||
1882 | if ($type === 'classic') { |
||
1883 | $action = '<td></td>'; |
||
1884 | } |
||
1885 | |||
1886 | if ($extend_this_attempt || $extend_all) { |
||
1887 | $list1 = learnpath::get_iv_interactions_array($row['iv_id'], $course_id); |
||
1888 | foreach ($list1 as $id => $interaction) { |
||
1889 | $oddclass = 'row_even'; |
||
1890 | if (($counter % 2) == 0) { |
||
1891 | $oddclass = 'row_odd'; |
||
1892 | } |
||
1893 | $timeRow = '<td class="lp_time">'.$interaction['time'].'</td>'; |
||
1894 | if ($hideTime) { |
||
1895 | $timeRow = ''; |
||
1896 | } |
||
1897 | |||
1898 | $output .= '<tr class="'.$oddclass.'"> |
||
1899 | <td></td> |
||
1900 | <td></td> |
||
1901 | <td></td> |
||
1902 | <td>'.$interaction['order_id'].'</td> |
||
1903 | <td>'.$interaction['id'].'</td> |
||
1904 | <td colspan="2">'.$interaction['type'].'</td> |
||
1905 | <td>'.urldecode($interaction['student_response']).'</td> |
||
1906 | <td>'.$interaction['result'].'</td> |
||
1907 | <td>'.$interaction['latency'].'</td> |
||
1908 | '.$timeRow.' |
||
1909 | '.$action.' |
||
1910 | </tr>'; |
||
1911 | $counter++; |
||
1912 | } |
||
1913 | |||
1914 | $list2 = learnpath::get_iv_objectives_array($row['iv_id'], $course_id); |
||
1915 | foreach ($list2 as $id => $interaction) { |
||
1916 | $oddclass = 'row_even'; |
||
1917 | if (($counter % 2) == 0) { |
||
1918 | $oddclass = 'row_odd'; |
||
1919 | } |
||
1920 | $output .= '<tr class="'.$oddclass.'"> |
||
1921 | <td></td> |
||
1922 | <td></td> |
||
1923 | <td></td> |
||
1924 | <td>'.$interaction['order_id'].'</td> |
||
1925 | <td colspan="2">'.$interaction['objective_id'].'</td> |
||
1926 | <td colspan="2">'.$interaction['status'].'</td> |
||
1927 | <td>'.$interaction['score_raw'].'</td> |
||
1928 | <td>'.$interaction['score_max'].'</td> |
||
1929 | <td>'.$interaction['score_min'].'</td> |
||
1930 | '.$action.' |
||
1931 | </tr>'; |
||
1932 | $counter++; |
||
1933 | } |
||
1934 | } |
||
1935 | |||
1936 | // Attempts listing by exercise. |
||
1937 | if ($lp_id == $my_lp_id && $lp_item_id == $my_id && $extendedAttempt) { |
||
1938 | // Get attempts of an exercise. |
||
1939 | if (!empty($lp_id) |
||
1940 | && !empty($lp_item_id) |
||
1941 | ) { |
||
1942 | $sql = "SELECT path FROM $TBL_LP_ITEM |
||
1943 | WHERE |
||
1944 | c_id = $course_id AND |
||
1945 | iid = '$lp_item_id' AND |
||
1946 | lp_id = '$lp_id'"; |
||
1947 | $res_path = Database::query($sql); |
||
1948 | $row_path = Database::fetch_array($res_path); |
||
1949 | |||
1950 | if (Database::num_rows($res_path) > 0) { |
||
1951 | if ('quiz' === $row['item_type']) { |
||
1952 | $sql = 'SELECT * FROM '.$tbl_stats_exercices.' |
||
1953 | WHERE |
||
1954 | exe_exo_id = '.(int) $row_path['path'].' AND |
||
1955 | status <> "incomplete" AND |
||
1956 | exe_user_id='.$user_id.' AND |
||
1957 | orig_lp_id = '.(int) $lp_id.' AND |
||
1958 | orig_lp_item_id = '.(int) $lp_item_id.' AND |
||
1959 | c_id = '.$course_id.' AND |
||
1960 | session_id = '.$session_id.' |
||
1961 | ORDER BY exe_date'; |
||
1962 | $res_attempts = Database::query($sql); |
||
1963 | $num_attempts = Database::num_rows($res_attempts); |
||
1964 | if ($num_attempts > 0) { |
||
1965 | $n = 1; |
||
1966 | while ($row_attempts = Database::fetch_array($res_attempts)) { |
||
1967 | $my_score = $row_attempts['exe_result']; |
||
1968 | $my_maxscore = $row_attempts['exe_weighting']; |
||
1969 | $my_exe_id = $row_attempts['exe_id']; |
||
1970 | $mktime_start_date = api_strtotime($row_attempts['start_date'], 'UTC'); |
||
1971 | $mktime_exe_date = api_strtotime($row_attempts['exe_date'], 'UTC'); |
||
1972 | $time_attemp = ' - '; |
||
1973 | if ($mktime_start_date && $mktime_exe_date) { |
||
1974 | $time_attemp = api_format_time($row_attempts['exe_duration'], 'js'); |
||
1975 | } |
||
1976 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
1977 | $view_score = Display::return_icon( |
||
1978 | 'invisible.png', |
||
1979 | get_lang( |
||
1980 | 'ResultsHiddenByExerciseSetting' |
||
1981 | ) |
||
1982 | ); |
||
1983 | } else { |
||
1984 | // Show only float when need it |
||
1985 | if ($my_score == 0) { |
||
1986 | $view_score = ExerciseLib::show_score( |
||
1987 | 0, |
||
1988 | $my_maxscore, |
||
1989 | false |
||
1990 | ); |
||
1991 | } else { |
||
1992 | if ($my_maxscore == 0) { |
||
1993 | $view_score = $my_score; |
||
1994 | } else { |
||
1995 | $view_score = ExerciseLib::show_score( |
||
1996 | $my_score, |
||
1997 | $my_maxscore, |
||
1998 | false |
||
1999 | ); |
||
2000 | } |
||
2001 | } |
||
2002 | } |
||
2003 | $my_lesson_status = $row_attempts['status']; |
||
2004 | if ($my_lesson_status == '') { |
||
2005 | $my_lesson_status = learnpathitem::humanize_status('completed'); |
||
2006 | } elseif ($my_lesson_status == 'incomplete') { |
||
2007 | $my_lesson_status = learnpathitem::humanize_status('incomplete'); |
||
2008 | } |
||
2009 | $timeRow = '<td class="lp_time" colspan="2">'.$time_attemp.'</td>'; |
||
2010 | if ($hideTime) { |
||
2011 | $timeRow = ''; |
||
2012 | } |
||
2013 | |||
2014 | $output .= '<tr class="'.$oddclass.'" > |
||
2015 | <td></td> |
||
2016 | <td>'.$extend_attempt_link.'</td> |
||
2017 | <td colspan="3">'.get_lang('Attempt').' '.$n.'</td> |
||
2018 | <td colspan="2">'.$my_lesson_status.'</td> |
||
2019 | <td colspan="2">'.$view_score.'</td> |
||
2020 | '.$timeRow; |
||
2021 | |||
2022 | if ($action == 'classic') { |
||
2023 | if ($origin != 'tracking') { |
||
2024 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
2025 | $output .= '<td> |
||
2026 | <img src="'.Display::returnIconPath('quiz_na.gif').'" alt="'.get_lang('ShowAttempt').'" title="'.get_lang('ShowAttempt').'"> |
||
2027 | </td>'; |
||
2028 | } else { |
||
2029 | $output .= '<td> |
||
2030 | <a href="../exercise/exercise_show.php?origin='.$origin.'&id='.$my_exe_id.'&cidReq='.$courseCode.'" target="_parent"> |
||
2031 | <img src="'.Display::returnIconPath('quiz.png').'" alt="'.get_lang('ShowAttempt').'" title="'.get_lang('ShowAttempt').'"> |
||
2032 | </a></td>'; |
||
2033 | } |
||
2034 | } else { |
||
2035 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
2036 | $output .= '<td> |
||
2037 | <img src="'.Display::returnIconPath('quiz_na.gif').'" alt="'.get_lang('ShowAndQualifyAttempt').'" title="'.get_lang('ShowAndQualifyAttempt').'"></td>'; |
||
2038 | } else { |
||
2039 | $output .= '<td> |
||
2040 | <a href="../exercise/exercise_show.php?cidReq='.$courseCode.'&origin=correct_exercise_in_lp&id='.$my_exe_id.'" target="_parent"> |
||
2041 | <img src="'.Display::returnIconPath('quiz.gif').'" alt="'.get_lang('ShowAndQualifyAttempt').'" title="'.get_lang('ShowAndQualifyAttempt').'"></a></td>'; |
||
2042 | } |
||
2043 | } |
||
2044 | } |
||
2045 | $output .= '</tr>'; |
||
2046 | $n++; |
||
2047 | } |
||
2048 | } |
||
2049 | } elseif ( |
||
2050 | 'h5p' === $row['item_type'] |
||
2051 | && 'true' === $h5pImportEnable |
||
2052 | ) { |
||
2053 | $em = Database::getManager(); |
||
2054 | $h5pImportResultsRepo = $em |
||
2055 | ->getRepository('ChamiloPluginBundle:H5pImport\H5pImportResults'); |
||
2056 | $h5pResults = $h5pImportResultsRepo |
||
2057 | ->findBy( |
||
2058 | [ |
||
2059 | 'user' => $user_id, 'cLpItemView' => $row['iv_id'], |
||
2060 | ] |
||
2061 | ); |
||
2062 | |||
2063 | if (count($h5pResults) > 0) { |
||
2064 | foreach ($h5pResults as $result) { |
||
2065 | $timeAttempt = ' - '; |
||
2066 | if ($result->getTotalTime()) { |
||
2067 | $timeAttempt = gmdate('H:i:s', $result->getTotalTime()); |
||
2068 | } |
||
2069 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
2070 | $view_score = Display::return_icon( |
||
2071 | 'invisible.png', |
||
2072 | get_lang( |
||
2073 | 'ResultsHiddenByExerciseSetting' |
||
2074 | ) |
||
2075 | ); |
||
2076 | } else { |
||
2077 | // Show only float when need it |
||
2078 | if ($result->getScore() == 0) { |
||
2079 | $view_score = ExerciseLib::show_score( |
||
2080 | 0, |
||
2081 | $result->getMaxScore(), |
||
2082 | false |
||
2083 | ); |
||
2084 | } else { |
||
2085 | if ($result->getMaxScore() == 0) { |
||
2086 | $view_score = $result->getScore(); |
||
2087 | } else { |
||
2088 | $view_score = ExerciseLib::show_score( |
||
2089 | $result->getScore(), |
||
2090 | $result->getMaxScore(), |
||
2091 | false |
||
2092 | ); |
||
2093 | } |
||
2094 | } |
||
2095 | } |
||
2096 | $my_lesson_status = learnpathitem::humanize_status($row['status']); |
||
2097 | $timeRow = '<td class="lp_time" colspan="2">'.$timeAttempt.'</td>'; |
||
2098 | if ($hideTime) { |
||
2099 | $timeRow = ''; |
||
2100 | } |
||
2101 | |||
2102 | $output .= '<tr class="'.$oddclass.'" > |
||
2103 | <td></td> |
||
2104 | <td>'.$extend_attempt_link.'</td> |
||
2105 | <td colspan="3">'.get_lang('Attempt').' '.$n.'</td> |
||
2106 | <td colspan="2">'.$my_lesson_status.'</td> |
||
2107 | <td colspan="2">'.$view_score.'</td>'.$timeRow; |
||
2108 | |||
2109 | if ($action == 'classic') { |
||
2110 | if ($origin != 'tracking') { |
||
2111 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
2112 | $output .= '<td> |
||
2113 | <img src="'.Display::returnIconPath('quiz_na.gif').'" alt="'.get_lang('ShowAttempt').'" title="'.get_lang('ShowAttempt').'"> |
||
2114 | </td>'; |
||
2115 | } else { |
||
2116 | $output .= '<td> |
||
2117 | <a href="../exercise/exercise_show.php?origin='.$origin.'&id='.$result->getIid().'&cidReq='.$courseCode.'" target="_parent"> |
||
2118 | <img src="'.Display::returnIconPath('quiz.png').'" alt="'.get_lang('ShowAttempt').'" title="'.get_lang('ShowAttempt').'"> |
||
2119 | </a></td>'; |
||
2120 | } |
||
2121 | } else { |
||
2122 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
2123 | $output .= '<td> |
||
2124 | <img src="'.Display::returnIconPath('quiz_na.gif').'" alt="'.get_lang('ShowAndQualifyAttempt').'" title="'.get_lang('ShowAndQualifyAttempt').'"></td>'; |
||
2125 | } else { |
||
2126 | $output .= '<td> |
||
2127 | <a href="../exercise/exercise_show.php?cidReq='.$courseCode.'&origin=correct_exercise_in_lp&id='.$result->getIid().'" target="_parent"> |
||
2128 | <img src="'.Display::returnIconPath('quiz.gif').'" alt="'.get_lang('ShowAndQualifyAttempt').'" title="'.get_lang('ShowAndQualifyAttempt').'"></a></td>'; |
||
2129 | } |
||
2130 | } |
||
2131 | } |
||
2132 | $output .= '</tr>'; |
||
2133 | $n++; |
||
2134 | } |
||
2135 | } |
||
2136 | } else { |
||
2137 | $output .= '<tr><td colspan="12"> </td></tr>'; |
||
2138 | } |
||
2139 | } |
||
2140 | } |
||
2141 | } |
||
2142 | } |
||
2143 | |||
2144 | $total_time += $time_for_total; |
||
2145 | // QUIZZ IN LP |
||
2146 | $a_my_id = []; |
||
2147 | if (!empty($my_lp_id)) { |
||
2148 | $a_my_id[] = $my_lp_id; |
||
2149 | } |
||
2150 | } |
||
2151 | } |
||
2152 | |||
2153 | // NOT Extend all "left green cross" |
||
2154 | if (!empty($a_my_id)) { |
||
2155 | if ($extendedAttempt) { |
||
2156 | // "Right green cross" extended |
||
2157 | $total_score = self::get_avg_student_score( |
||
2158 | $user_id, |
||
2159 | $course_id, |
||
2160 | $a_my_id, |
||
2161 | $session_id, |
||
2162 | false, |
||
2163 | false |
||
2164 | ); |
||
2165 | } else { |
||
2166 | // "Left green cross" extended |
||
2167 | $total_score = self::get_avg_student_score( |
||
2168 | $user_id, |
||
2169 | $course_id, |
||
2170 | $a_my_id, |
||
2171 | $session_id, |
||
2172 | false, |
||
2173 | true |
||
2174 | ); |
||
2175 | } |
||
2176 | } else { |
||
2177 | // Extend all "left green cross" |
||
2178 | $total_score = self::get_avg_student_score( |
||
2179 | $user_id, |
||
2180 | $course_id, |
||
2181 | [$lp_id], |
||
2182 | $session_id, |
||
2183 | false, |
||
2184 | false |
||
2185 | ); |
||
2186 | } |
||
2187 | |||
2188 | $total_time = learnpathItem::getScormTimeFromParameter('js', $total_time); |
||
2189 | $total_time = str_replace('NaN', '00'.$h.'00\'00"', $total_time); |
||
2190 | |||
2191 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
2192 | $final_score = Display::return_icon('invisible.png', get_lang('ResultsHiddenByExerciseSetting')); |
||
2193 | $finalScoreToCsv = get_lang('ResultsHiddenByExerciseSetting'); |
||
2194 | } else { |
||
2195 | if (is_numeric($total_score)) { |
||
2196 | $final_score = $total_score.'%'; |
||
2197 | } else { |
||
2198 | $final_score = $total_score; |
||
2199 | } |
||
2200 | $finalScoreToCsv = $final_score; |
||
2201 | } |
||
2202 | $progress = learnpath::getProgress($lp_id, $user_id, $course_id, $session_id); |
||
2203 | |||
2204 | $oddclass = 'row_even'; |
||
2205 | if (($counter % 2) == 0) { |
||
2206 | $oddclass = 'row_odd'; |
||
2207 | } |
||
2208 | |||
2209 | $action = null; |
||
2210 | if ('classic' === $type) { |
||
2211 | $action = '<td></td>'; |
||
2212 | } |
||
2213 | |||
2214 | $timeTotal = '<td class="lp_time" colspan="2">'.$total_time.'</div>'; |
||
2215 | if ($hideTime) { |
||
2216 | $timeTotal = ''; |
||
2217 | } |
||
2218 | |||
2219 | $output .= '<tr class="'.$oddclass.'"> |
||
2220 | <td></td> |
||
2221 | <td colspan="4"> |
||
2222 | <i>'.get_lang('AccomplishedStepsTotal').'</i> |
||
2223 | </td> |
||
2224 | <td colspan="2">'.$progress.'%</td> |
||
2225 | <td colspan="2">'.$final_score.'</td> |
||
2226 | '.$timeTotal.' |
||
2227 | '.$action.' |
||
2228 | </tr>'; |
||
2229 | |||
2230 | $output .= ' |
||
2231 | </tbody> |
||
2232 | </table> |
||
2233 | </div> |
||
2234 | '; |
||
2235 | |||
2236 | if (!empty($export_csv)) { |
||
2237 | $temp = [ |
||
2238 | '', |
||
2239 | '', |
||
2240 | '', |
||
2241 | '', |
||
2242 | ]; |
||
2243 | $csv_content[] = $temp; |
||
2244 | $temp = [ |
||
2245 | get_lang('AccomplishedStepsTotal'), |
||
2246 | '', |
||
2247 | $finalScoreToCsv, |
||
2248 | ]; |
||
2249 | |||
2250 | if ($hideTime === false) { |
||
2251 | $temp[] = $total_time; |
||
2252 | } |
||
2253 | |||
2254 | $csv_content[] = $temp; |
||
2255 | ob_end_clean(); |
||
2256 | Export::arrayToCsv($csv_content, 'reporting_learning_path_details'); |
||
2257 | exit; |
||
0 ignored issues
–
show
|
|||
2258 | } |
||
2259 | |||
2260 | return $output; |
||
2261 | } |
||
2262 | |||
2263 | /** |
||
2264 | * @param int $userId |
||
2265 | * @param bool $getCount |
||
2266 | * |
||
2267 | * @return array |
||
2268 | */ |
||
2269 | public static function getStats($userId, $getCount = false) |
||
2270 | { |
||
2271 | $courses = []; |
||
2272 | $students = []; |
||
2273 | $assignedCourses = []; |
||
2274 | $drhCount = 0; |
||
2275 | $teachersCount = 0; |
||
2276 | $studentBossCount = 0; |
||
2277 | $courseCount = 0; |
||
2278 | $assignedCourseCount = 0; |
||
2279 | $studentCount = 0; |
||
2280 | $checkSessionVisibility = api_get_configuration_value('show_users_in_active_sessions_in_tracking'); |
||
2281 | $allowDhrAccessToAllStudents = api_get_configuration_value('drh_allow_access_to_all_students'); |
||
2282 | |||
2283 | if (api_is_drh() && api_drh_can_access_all_session_content()) { |
||
2284 | $studentBossesList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus( |
||
2285 | 'drh_all', |
||
2286 | $userId, |
||
2287 | $getCount, |
||
2288 | null, |
||
2289 | null, |
||
2290 | null, |
||
2291 | null, |
||
2292 | null, |
||
2293 | null, |
||
2294 | null, |
||
2295 | [], |
||
2296 | [], |
||
2297 | STUDENT_BOSS |
||
2298 | ); |
||
2299 | |||
2300 | if ($getCount) { |
||
2301 | $studentBossCount = $studentBossesList; |
||
2302 | } else { |
||
2303 | $studentBosses = []; |
||
2304 | if (is_array($studentBossesList)) { |
||
2305 | foreach ($studentBossesList as $studentBossData) { |
||
2306 | $studentBosses[] = $studentBossData['user_id']; |
||
2307 | } |
||
2308 | } |
||
2309 | } |
||
2310 | |||
2311 | $teacherList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus( |
||
2312 | 'drh_all', |
||
2313 | $userId, |
||
2314 | $getCount, |
||
2315 | null, |
||
2316 | null, |
||
2317 | null, |
||
2318 | null, |
||
2319 | null, |
||
2320 | null, |
||
2321 | null, |
||
2322 | [], |
||
2323 | [], |
||
2324 | COURSEMANAGER |
||
2325 | ); |
||
2326 | |||
2327 | if ($getCount) { |
||
2328 | $teachersCount = $teacherList; |
||
2329 | } else { |
||
2330 | $teachers = []; |
||
2331 | foreach ($teacherList as $teacherData) { |
||
2332 | $teachers[] = $teacherData['user_id']; |
||
2333 | } |
||
2334 | } |
||
2335 | |||
2336 | $humanResources = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus( |
||
2337 | 'drh_all', |
||
2338 | $userId, |
||
2339 | $getCount, |
||
2340 | null, |
||
2341 | null, |
||
2342 | null, |
||
2343 | null, |
||
2344 | null, |
||
2345 | null, |
||
2346 | null, |
||
2347 | [], |
||
2348 | [], |
||
2349 | DRH |
||
2350 | ); |
||
2351 | |||
2352 | if ($getCount) { |
||
2353 | $drhCount = $humanResources; |
||
2354 | } else { |
||
2355 | $humanResourcesList = []; |
||
2356 | if (is_array($humanResources)) { |
||
2357 | foreach ($humanResources as $item) { |
||
2358 | $humanResourcesList[] = $item['user_id']; |
||
2359 | } |
||
2360 | } |
||
2361 | } |
||
2362 | |||
2363 | $platformCourses = SessionManager::getAllCoursesFollowedByUser( |
||
2364 | $userId, |
||
2365 | null, |
||
2366 | null, |
||
2367 | null, |
||
2368 | null, |
||
2369 | null, |
||
2370 | $getCount |
||
2371 | ); |
||
2372 | |||
2373 | if ($getCount) { |
||
2374 | $courseCount = $platformCourses; |
||
2375 | } else { |
||
2376 | foreach ($platformCourses as $course) { |
||
2377 | $courses[$course['code']] = $course['code']; |
||
2378 | } |
||
2379 | } |
||
2380 | |||
2381 | $sessions = SessionManager::get_sessions_followed_by_drh( |
||
2382 | $userId, |
||
2383 | null, |
||
2384 | null, |
||
2385 | false |
||
2386 | ); |
||
2387 | } else { |
||
2388 | if (api_is_drh() && $allowDhrAccessToAllStudents) { |
||
2389 | $studentList = UserManager::get_user_list( |
||
2390 | ['status' => STUDENT], |
||
2391 | [], |
||
2392 | false, |
||
2393 | false, |
||
2394 | null, |
||
2395 | null, |
||
2396 | null, |
||
2397 | false |
||
2398 | ); |
||
2399 | } else { |
||
2400 | $studentList = UserManager::getUsersFollowedByUser( |
||
2401 | $userId, |
||
2402 | STUDENT, |
||
2403 | false, |
||
2404 | false, |
||
2405 | false, |
||
2406 | null, |
||
2407 | null, |
||
2408 | null, |
||
2409 | null, |
||
2410 | null, |
||
2411 | null, |
||
2412 | COURSEMANAGER, |
||
2413 | null, |
||
2414 | $checkSessionVisibility |
||
2415 | ); |
||
2416 | } |
||
2417 | |||
2418 | $students = []; |
||
2419 | if (is_array($studentList)) { |
||
2420 | foreach ($studentList as $studentData) { |
||
2421 | $students[] = $studentData['user_id']; |
||
2422 | } |
||
2423 | } |
||
2424 | if ($getCount) { |
||
2425 | $studentCount = count($students); |
||
2426 | } |
||
2427 | |||
2428 | $studentBossesList = UserManager::getUsersFollowedByUser( |
||
2429 | $userId, |
||
2430 | STUDENT_BOSS, |
||
2431 | false, |
||
2432 | false, |
||
2433 | $getCount, |
||
2434 | null, |
||
2435 | null, |
||
2436 | null, |
||
2437 | null, |
||
2438 | null, |
||
2439 | null, |
||
2440 | COURSEMANAGER, |
||
2441 | null, |
||
2442 | $checkSessionVisibility |
||
2443 | ); |
||
2444 | |||
2445 | if ($getCount) { |
||
2446 | $studentBossCount = $studentBossesList; |
||
2447 | } else { |
||
2448 | $studentBosses = []; |
||
2449 | if (is_array($studentBossesList)) { |
||
2450 | foreach ($studentBossesList as $studentBossData) { |
||
2451 | $studentBosses[] = $studentBossData['user_id']; |
||
2452 | } |
||
2453 | } |
||
2454 | } |
||
2455 | |||
2456 | $teacherList = UserManager::getUsersFollowedByUser( |
||
2457 | $userId, |
||
2458 | COURSEMANAGER, |
||
2459 | false, |
||
2460 | false, |
||
2461 | $getCount, |
||
2462 | null, |
||
2463 | null, |
||
2464 | null, |
||
2465 | null, |
||
2466 | null, |
||
2467 | null, |
||
2468 | COURSEMANAGER, |
||
2469 | null, |
||
2470 | $checkSessionVisibility |
||
2471 | ); |
||
2472 | |||
2473 | if ($getCount) { |
||
2474 | $teachersCount = $teacherList; |
||
2475 | } else { |
||
2476 | $teachers = []; |
||
2477 | foreach ($teacherList as $teacherData) { |
||
2478 | $teachers[] = $teacherData['user_id']; |
||
2479 | } |
||
2480 | } |
||
2481 | |||
2482 | $humanResources = UserManager::getUsersFollowedByUser( |
||
2483 | $userId, |
||
2484 | DRH, |
||
2485 | false, |
||
2486 | false, |
||
2487 | $getCount, |
||
2488 | null, |
||
2489 | null, |
||
2490 | null, |
||
2491 | null, |
||
2492 | null, |
||
2493 | null, |
||
2494 | COURSEMANAGER, |
||
2495 | null, |
||
2496 | $checkSessionVisibility |
||
2497 | ); |
||
2498 | |||
2499 | if ($getCount) { |
||
2500 | $drhCount = $humanResources; |
||
2501 | } else { |
||
2502 | $humanResourcesList = []; |
||
2503 | foreach ($humanResources as $item) { |
||
2504 | $humanResourcesList[] = $item['user_id']; |
||
2505 | } |
||
2506 | } |
||
2507 | |||
2508 | $platformCourses = CourseManager::getCoursesFollowedByUser( |
||
2509 | $userId, |
||
2510 | COURSEMANAGER, |
||
2511 | null, |
||
2512 | null, |
||
2513 | null, |
||
2514 | null, |
||
2515 | $getCount, |
||
2516 | null, |
||
2517 | null, |
||
2518 | true |
||
2519 | ); |
||
2520 | |||
2521 | if ($getCount) { |
||
2522 | $assignedCourseCount = $platformCourses; |
||
2523 | } else { |
||
2524 | foreach ($platformCourses as $course) { |
||
2525 | $assignedCourses[$course['code']] = $course['code']; |
||
2526 | } |
||
2527 | } |
||
2528 | |||
2529 | $platformCourses = CourseManager::getCoursesFollowedByUser( |
||
2530 | $userId, |
||
2531 | COURSEMANAGER, |
||
2532 | null, |
||
2533 | null, |
||
2534 | null, |
||
2535 | null, |
||
2536 | $getCount |
||
2537 | ); |
||
2538 | |||
2539 | if ($getCount) { |
||
2540 | $courseCount = $platformCourses; |
||
2541 | } else { |
||
2542 | foreach ($platformCourses as $course) { |
||
2543 | $courses[$course['code']] = $course['code']; |
||
2544 | } |
||
2545 | } |
||
2546 | |||
2547 | $sessions = SessionManager::getSessionsFollowedByUser( |
||
2548 | $userId, |
||
2549 | COURSEMANAGER, |
||
2550 | null, |
||
2551 | null, |
||
2552 | false |
||
2553 | ); |
||
2554 | } |
||
2555 | |||
2556 | if ($getCount) { |
||
2557 | return [ |
||
2558 | 'drh' => $drhCount, |
||
2559 | 'teachers' => $teachersCount, |
||
2560 | 'student_count' => $studentCount, |
||
2561 | 'student_list' => $students, |
||
2562 | 'student_bosses' => $studentBossCount, |
||
2563 | 'courses' => $courseCount, |
||
2564 | 'session_count' => count($sessions), |
||
2565 | 'session_list' => $sessions, |
||
2566 | 'assigned_courses' => $assignedCourseCount, |
||
2567 | ]; |
||
2568 | } |
||
2569 | |||
2570 | return [ |
||
2571 | 'drh' => $humanResourcesList, |
||
2572 | 'teachers' => $teachers, |
||
2573 | 'student_list' => $students, |
||
2574 | 'student_bosses' => $studentBosses, |
||
2575 | 'courses' => $courses, |
||
2576 | 'sessions' => $sessions, |
||
2577 | 'assigned_courses' => $assignedCourses, |
||
2578 | ]; |
||
2579 | } |
||
2580 | |||
2581 | /** |
||
2582 | * Calculates the time spent on the platform by a user. |
||
2583 | * |
||
2584 | * @param int|array $userId |
||
2585 | * @param string $timeFilter type of time filter: 'last_week' or 'custom' |
||
2586 | * @param string $start_date start date date('Y-m-d H:i:s') |
||
2587 | * @param string $end_date end date date('Y-m-d H:i:s') |
||
2588 | * @param bool $returnAllRecords |
||
2589 | * |
||
2590 | * @return int |
||
2591 | */ |
||
2592 | public static function get_time_spent_on_the_platform( |
||
2593 | $userId, |
||
2594 | $timeFilter = 'last_7_days', |
||
2595 | $start_date = null, |
||
2596 | $end_date = null, |
||
2597 | $returnAllRecords = false |
||
2598 | ) { |
||
2599 | $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN); |
||
2600 | $condition_time = ''; |
||
2601 | |||
2602 | if (is_array($userId)) { |
||
2603 | $userList = array_map('intval', $userId); |
||
2604 | $userCondition = " login_user_id IN ('".implode("','", $userList)."')"; |
||
2605 | } else { |
||
2606 | $userId = (int) $userId; |
||
2607 | $userCondition = " login_user_id = $userId "; |
||
2608 | } |
||
2609 | |||
2610 | $url_condition = null; |
||
2611 | $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); |
||
2612 | $url_table = null; |
||
2613 | if (api_is_multiple_url_enabled()) { |
||
2614 | $access_url_id = api_get_current_access_url_id(); |
||
2615 | $url_table = ", $tbl_url_rel_user as url_users"; |
||
2616 | $url_condition = " AND u.login_user_id = url_users.user_id AND access_url_id='$access_url_id'"; |
||
2617 | } |
||
2618 | |||
2619 | if (empty($timeFilter)) { |
||
2620 | $timeFilter = 'last_week'; |
||
2621 | } |
||
2622 | |||
2623 | $today = new DateTime('now', new DateTimeZone('UTC')); |
||
2624 | |||
2625 | switch ($timeFilter) { |
||
2626 | case 'last_7_days': |
||
2627 | $newDate = new DateTime('-7 day', new DateTimeZone('UTC')); |
||
2628 | $condition_time = " AND (login_date >= '{$newDate->format('Y-m-d H:i:s')}'"; |
||
2629 | $condition_time .= " AND logout_date <= '{$today->format('Y-m-d H:i:s')}') "; |
||
2630 | break; |
||
2631 | case 'last_30_days': |
||
2632 | $newDate = new DateTime('-30 days', new DateTimeZone('UTC')); |
||
2633 | $condition_time = " AND (login_date >= '{$newDate->format('Y-m-d H:i:s')}'"; |
||
2634 | $condition_time .= "AND logout_date <= '{$today->format('Y-m-d H:i:s')}') "; |
||
2635 | break; |
||
2636 | case 'wide': |
||
2637 | if (!empty($start_date) && !empty($end_date)) { |
||
2638 | $start_date = Database::escape_string($start_date); |
||
2639 | $end_date = Database::escape_string($end_date); |
||
2640 | $condition_time = ' AND ( |
||
2641 | (login_date >= "'.$start_date.'" AND login_date <= "'.$end_date.'") OR |
||
2642 | (logout_date >= "'.$start_date.'" AND logout_date <= "'.$end_date.'") OR |
||
2643 | (login_date <= "'.$start_date.'" AND logout_date >= "'.$end_date.'") |
||
2644 | ) '; |
||
2645 | } |
||
2646 | break; |
||
2647 | case 'custom': |
||
2648 | if (!empty($start_date) && !empty($end_date)) { |
||
2649 | $start_date = Database::escape_string($start_date); |
||
2650 | $end_date = Database::escape_string($end_date); |
||
2651 | $condition_time = ' AND (login_date >= "'.$start_date.'" AND logout_date <= "'.$end_date.'" ) '; |
||
2652 | } |
||
2653 | break; |
||
2654 | } |
||
2655 | |||
2656 | if ($returnAllRecords) { |
||
2657 | $sql = "SELECT login_date, logout_date, TIMESTAMPDIFF(SECOND, login_date, logout_date) diff |
||
2658 | FROM $tbl_track_login u $url_table |
||
2659 | WHERE $userCondition $condition_time $url_condition |
||
2660 | ORDER BY login_date"; |
||
2661 | $rs = Database::query($sql); |
||
2662 | |||
2663 | return Database::store_result($rs, 'ASSOC'); |
||
2664 | } |
||
2665 | |||
2666 | $sql = "SELECT SUM(TIMESTAMPDIFF(SECOND, login_date, logout_date)) diff |
||
2667 | FROM $tbl_track_login u $url_table |
||
2668 | WHERE $userCondition $condition_time $url_condition"; |
||
2669 | $rs = Database::query($sql); |
||
2670 | $row = Database::fetch_array($rs, 'ASSOC'); |
||
2671 | $diff = $row['diff']; |
||
2672 | |||
2673 | if ($diff >= 0) { |
||
2674 | return $diff; |
||
2675 | } |
||
2676 | |||
2677 | return -1; |
||
2678 | } |
||
2679 | |||
2680 | /** |
||
2681 | * @param string $startDate |
||
2682 | * @param string $endDate |
||
2683 | * |
||
2684 | * @return int |
||
2685 | */ |
||
2686 | public static function getTotalTimeSpentOnThePlatform( |
||
2687 | $startDate = '', |
||
2688 | $endDate = '' |
||
2689 | ) { |
||
2690 | $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN); |
||
2691 | $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); |
||
2692 | |||
2693 | $url_table = null; |
||
2694 | $url_condition = null; |
||
2695 | if (api_is_multiple_url_enabled()) { |
||
2696 | $access_url_id = api_get_current_access_url_id(); |
||
2697 | $url_table = ", ".$tbl_url_rel_user." as url_users"; |
||
2698 | $url_condition = " AND u.login_user_id = url_users.user_id AND access_url_id='$access_url_id'"; |
||
2699 | } |
||
2700 | |||
2701 | if (!empty($startDate) && !empty($endDate)) { |
||
2702 | $startDate = Database::escape_string($startDate); |
||
2703 | $endDate = Database::escape_string($endDate); |
||
2704 | $condition_time = ' (login_date >= "'.$startDate.'" AND logout_date <= "'.$endDate.'" ) '; |
||
2705 | } |
||
2706 | $sql = "SELECT SUM(TIMESTAMPDIFF(SECOND, login_date, logout_date)) diff |
||
2707 | FROM $tbl_track_login u $url_table |
||
2708 | WHERE $condition_time $url_condition"; |
||
2709 | $rs = Database::query($sql); |
||
2710 | $row = Database::fetch_array($rs, 'ASSOC'); |
||
2711 | $diff = $row['diff']; |
||
2712 | |||
2713 | if ($diff >= 0) { |
||
2714 | return $diff; |
||
2715 | } |
||
2716 | |||
2717 | return -1; |
||
2718 | } |
||
2719 | |||
2720 | /** |
||
2721 | * Return the total time spent in courses (no the total in platform). |
||
2722 | * |
||
2723 | * @return int |
||
2724 | */ |
||
2725 | public static function getTotalTimeSpentInCourses( |
||
2726 | string $dateFrom = '', |
||
2727 | string $dateUntil = '' |
||
2728 | ) { |
||
2729 | $tableTrackLogin = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
2730 | $tableUrlRelUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); |
||
2731 | |||
2732 | $tableUrl = null; |
||
2733 | $urlCondition = null; |
||
2734 | $conditionTime = null; |
||
2735 | if (api_is_multiple_url_enabled()) { |
||
2736 | $accessUrlId = api_get_current_access_url_id(); |
||
2737 | $tableUrl = ", ".$tableUrlRelUser." as url_users"; |
||
2738 | $urlCondition = " AND teca.user_id = url_users.user_id AND url_users.access_url_id = $accessUrlId"; |
||
2739 | } |
||
2740 | |||
2741 | if (!empty($dateFrom) && !empty($dateUntil)) { |
||
2742 | $dateFrom = Database::escape_string($dateFrom); |
||
2743 | $dateUntil = Database::escape_string($dateUntil); |
||
2744 | $conditionTime = " (teca.login_course_date >= '$dateFrom' AND teca.logout_course_date <= '$dateUntil' ) "; |
||
2745 | } |
||
2746 | $sql = "SELECT SUM(TIMESTAMPDIFF(HOUR, teca.login_course_date, teca.logout_course_date)) diff |
||
2747 | FROM $tableTrackLogin teca $tableUrl |
||
2748 | WHERE $conditionTime $urlCondition"; |
||
2749 | |||
2750 | $rs = Database::query($sql); |
||
2751 | if (Database::num_rows($rs) < 1) { |
||
2752 | return -1; |
||
2753 | } |
||
2754 | $row = Database::fetch_array($rs, 'ASSOC'); |
||
2755 | $diff = $row['diff']; |
||
2756 | |||
2757 | if (isset($diff) && $diff >= 0) { |
||
2758 | return $diff; |
||
2759 | } |
||
2760 | |||
2761 | return -1; |
||
2762 | } |
||
2763 | |||
2764 | /** |
||
2765 | * Checks if the "lp_minimum_time" feature is available for the course. |
||
2766 | * |
||
2767 | * @param int $sessionId |
||
2768 | * @param int $courseId |
||
2769 | * |
||
2770 | * @return bool |
||
2771 | */ |
||
2772 | public static function minimumTimeAvailable($sessionId, $courseId) |
||
2773 | { |
||
2774 | if (!api_get_configuration_value('lp_minimum_time')) { |
||
2775 | return false; |
||
2776 | } |
||
2777 | |||
2778 | if (!empty($sessionId)) { |
||
2779 | $extraFieldValue = new ExtraFieldValue('session'); |
||
2780 | $value = $extraFieldValue->get_values_by_handler_and_field_variable($sessionId, 'new_tracking_system'); |
||
2781 | |||
2782 | if ($value && isset($value['value']) && 1 == $value['value']) { |
||
2783 | return true; |
||
2784 | } |
||
2785 | } else { |
||
2786 | if ($courseId) { |
||
2787 | $extraFieldValue = new ExtraFieldValue('course'); |
||
2788 | $value = $extraFieldValue->get_values_by_handler_and_field_variable($courseId, 'new_tracking_system'); |
||
2789 | if ($value && isset($value['value']) && 1 == $value['value']) { |
||
2790 | return true; |
||
2791 | } |
||
2792 | } |
||
2793 | } |
||
2794 | |||
2795 | return false; |
||
2796 | } |
||
2797 | |||
2798 | /** |
||
2799 | * Calculates the time spent on the course. |
||
2800 | * |
||
2801 | * @param int|array<int, int> $user_id |
||
2802 | * @param int $courseId |
||
2803 | * @param int $session_id |
||
2804 | * @param string $startDate date string |
||
2805 | * @param string $endDate date string |
||
2806 | * |
||
2807 | * @return int Time in seconds |
||
2808 | */ |
||
2809 | public static function get_time_spent_on_the_course( |
||
2810 | $user_id, |
||
2811 | $courseId, |
||
2812 | $session_id = 0, |
||
2813 | $startDate = null, |
||
2814 | $endDate = null |
||
2815 | ) { |
||
2816 | $courseId = (int) $courseId; |
||
2817 | |||
2818 | if (empty($courseId) || empty($user_id)) { |
||
2819 | return 0; |
||
2820 | } |
||
2821 | |||
2822 | if (self::minimumTimeAvailable($session_id, $courseId)) { |
||
2823 | $courseTime = self::getCalculateTime($user_id, $courseId, $session_id); |
||
2824 | |||
2825 | return isset($courseTime['total_time']) ? $courseTime['total_time'] : 0; |
||
2826 | } |
||
2827 | |||
2828 | $conditionUser = ''; |
||
2829 | $session_id = (int) $session_id; |
||
2830 | if (is_array($user_id)) { |
||
2831 | $user_id = array_map('intval', $user_id); |
||
2832 | $conditionUser = " AND user_id IN (".implode(',', $user_id).") "; |
||
2833 | } else { |
||
2834 | if (!empty($user_id)) { |
||
2835 | $user_id = (int) $user_id; |
||
2836 | $conditionUser = " AND user_id = $user_id "; |
||
2837 | } |
||
2838 | } |
||
2839 | |||
2840 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
2841 | $sql = "SELECT |
||
2842 | SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as nb_seconds |
||
2843 | FROM $table |
||
2844 | WHERE |
||
2845 | UNIX_TIMESTAMP(logout_course_date) > UNIX_TIMESTAMP(login_course_date) AND |
||
2846 | c_id = '$courseId' "; |
||
2847 | |||
2848 | if (-1 != $session_id) { |
||
2849 | $sql .= "AND session_id = '$session_id' "; |
||
2850 | } |
||
2851 | |||
2852 | if (!empty($startDate)) { |
||
2853 | $startDate = api_get_utc_datetime($startDate, false, true); |
||
2854 | $sql .= " AND login_course_date >= '".$startDate->format('Y-m-d 00:00:00')."' "; |
||
2855 | } |
||
2856 | if (!empty($endDate)) { |
||
2857 | $endDate = api_get_utc_datetime($endDate, false, true); |
||
2858 | $sql .= " AND login_course_date <= '".$endDate->format('Y-m-d 23:59:59')."' "; |
||
2859 | } |
||
2860 | |||
2861 | $sql .= $conditionUser; |
||
2862 | |||
2863 | $rs = Database::query($sql); |
||
2864 | $row = Database::fetch_array($rs); |
||
2865 | |||
2866 | return $row['nb_seconds']; |
||
2867 | } |
||
2868 | |||
2869 | /** |
||
2870 | * Get first connection date for a student. |
||
2871 | * |
||
2872 | * @param int $student_id |
||
2873 | * |
||
2874 | * @return string|bool Date format long without day or false if there are no connections |
||
2875 | */ |
||
2876 | public static function get_first_connection_date($student_id, $dateFormat = DATE_FORMAT_SHORT) |
||
2877 | { |
||
2878 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN); |
||
2879 | $sql = 'SELECT login_date |
||
2880 | FROM '.$table.' |
||
2881 | WHERE login_user_id = '.intval($student_id).' |
||
2882 | ORDER BY login_date ASC |
||
2883 | LIMIT 0,1'; |
||
2884 | |||
2885 | $rs = Database::query($sql); |
||
2886 | if (Database::num_rows($rs) > 0) { |
||
2887 | if ($first_login_date = Database::result($rs, 0, 0)) { |
||
2888 | return api_convert_and_format_date( |
||
2889 | $first_login_date, |
||
2890 | $dateFormat |
||
2891 | ); |
||
2892 | } |
||
2893 | } |
||
2894 | |||
2895 | return false; |
||
2896 | } |
||
2897 | |||
2898 | /** |
||
2899 | * Get las connection date for a student. |
||
2900 | * |
||
2901 | * @param int $student_id |
||
2902 | * @param bool $warning_message Show a warning message (optional) |
||
2903 | * @param bool $return_timestamp True for returning results in timestamp (optional) |
||
2904 | * |
||
2905 | * @return string|int|bool Date format long without day, false if there are no connections or |
||
2906 | * timestamp if parameter $return_timestamp is true |
||
2907 | */ |
||
2908 | public static function get_last_connection_date( |
||
2909 | $student_id, |
||
2910 | $warning_message = false, |
||
2911 | $return_timestamp = false, |
||
2912 | $dateFormat = DATE_FORMAT_SHORT |
||
2913 | ) { |
||
2914 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN); |
||
2915 | $sql = 'SELECT login_date |
||
2916 | FROM '.$table.' |
||
2917 | WHERE login_user_id = '.intval($student_id).' |
||
2918 | ORDER BY login_date |
||
2919 | DESC LIMIT 0,1'; |
||
2920 | |||
2921 | $rs = Database::query($sql); |
||
2922 | if (Database::num_rows($rs) > 0) { |
||
2923 | if ($last_login_date = Database::result($rs, 0, 0)) { |
||
2924 | $last_login_date = api_get_local_time($last_login_date); |
||
2925 | if ($return_timestamp) { |
||
2926 | return api_strtotime($last_login_date, 'UTC'); |
||
2927 | } else { |
||
2928 | if (!$warning_message) { |
||
2929 | return api_format_date($last_login_date, $dateFormat); |
||
2930 | } else { |
||
2931 | $timestamp = api_strtotime($last_login_date, 'UTC'); |
||
2932 | $currentTimestamp = time(); |
||
2933 | |||
2934 | // If the last connection is > than 7 days, the text is red |
||
2935 | // 604800 = 7 days in seconds |
||
2936 | if ($currentTimestamp - $timestamp > 604800) { |
||
2937 | return '<span style="color: #F00;">'.api_format_date($last_login_date, $dateFormat).'</span>'; |
||
2938 | } else { |
||
2939 | return api_format_date($last_login_date, $dateFormat); |
||
2940 | } |
||
2941 | } |
||
2942 | } |
||
2943 | } |
||
2944 | } |
||
2945 | |||
2946 | return false; |
||
2947 | } |
||
2948 | |||
2949 | /** |
||
2950 | * Get first user's connection date on the course. |
||
2951 | * |
||
2952 | * @param int User id |
||
2953 | * @param int $courseId |
||
2954 | * @param int Session id (optional, default=0) |
||
2955 | * @param bool $convert_date |
||
2956 | * |
||
2957 | * @return string|bool Date with format long without day or false if there is no date |
||
2958 | */ |
||
2959 | public static function get_first_connection_date_on_the_course( |
||
2960 | $student_id, |
||
2961 | $courseId, |
||
2962 | $session_id = 0, |
||
2963 | $convert_date = true |
||
2964 | ) { |
||
2965 | $student_id = (int) $student_id; |
||
2966 | $courseId = (int) $courseId; |
||
2967 | $session_id = (int) $session_id; |
||
2968 | |||
2969 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
2970 | $sql = 'SELECT login_course_date |
||
2971 | FROM '.$table.' |
||
2972 | WHERE |
||
2973 | user_id = '.$student_id.' AND |
||
2974 | c_id = '.$courseId.' AND |
||
2975 | session_id = '.$session_id.' |
||
2976 | ORDER BY login_course_date ASC |
||
2977 | LIMIT 0,1'; |
||
2978 | $rs = Database::query($sql); |
||
2979 | if (Database::num_rows($rs) > 0) { |
||
2980 | if ($first_login_date = Database::result($rs, 0, 0)) { |
||
2981 | if (empty($first_login_date)) { |
||
2982 | return false; |
||
2983 | } |
||
2984 | |||
2985 | if ($convert_date) { |
||
2986 | return api_convert_and_format_date( |
||
2987 | $first_login_date, |
||
2988 | DATE_FORMAT_SHORT |
||
2989 | ); |
||
2990 | } |
||
2991 | |||
2992 | return $first_login_date; |
||
2993 | } |
||
2994 | } |
||
2995 | |||
2996 | return false; |
||
2997 | } |
||
2998 | |||
2999 | /** |
||
3000 | * Get last user's connection date on the course. |
||
3001 | * |
||
3002 | * @param int User id |
||
3003 | * @param array $courseInfo real_id and code are used |
||
3004 | * @param int Session id (optional, default=0) |
||
3005 | * @param bool $convert_date |
||
3006 | * |
||
3007 | * @return string|bool Date with format long without day or false if there is no date |
||
3008 | */ |
||
3009 | public static function get_last_connection_date_on_the_course( |
||
3010 | $student_id, |
||
3011 | $courseInfo, |
||
3012 | $session_id = 0, |
||
3013 | $convert_date = true |
||
3014 | ) { |
||
3015 | // protect data |
||
3016 | $student_id = (int) $student_id; |
||
3017 | $session_id = (int) $session_id; |
||
3018 | |||
3019 | if (empty($courseInfo) || empty($student_id)) { |
||
3020 | return false; |
||
3021 | } |
||
3022 | |||
3023 | $courseId = $courseInfo['real_id']; |
||
3024 | |||
3025 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
3026 | |||
3027 | if (self::minimumTimeAvailable($session_id, $courseId)) { |
||
3028 | // Show the last date on which the user acceed the session when it was active |
||
3029 | $where_condition = ''; |
||
3030 | $userInfo = api_get_user_info($student_id); |
||
3031 | if (STUDENT == $userInfo['status'] && !empty($session_id)) { |
||
3032 | // fin de acceso a la sesión |
||
3033 | $sessionInfo = SessionManager::fetch($session_id); |
||
3034 | $last_access = $sessionInfo['access_end_date']; |
||
3035 | if (!empty($last_access)) { |
||
3036 | $where_condition = ' AND logout_course_date < "'.$last_access.'" '; |
||
3037 | } |
||
3038 | } |
||
3039 | $sql = "SELECT logout_course_date |
||
3040 | FROM $table |
||
3041 | WHERE user_id = $student_id AND |
||
3042 | c_id = $courseId AND |
||
3043 | session_id = $session_id $where_condition |
||
3044 | ORDER BY logout_course_date DESC |
||
3045 | LIMIT 0,1"; |
||
3046 | |||
3047 | $rs = Database::query($sql); |
||
3048 | if (Database::num_rows($rs) > 0) { |
||
3049 | if ($last_login_date = Database::result($rs, 0, 0)) { |
||
3050 | if (empty($last_login_date)) { |
||
3051 | return false; |
||
3052 | } |
||
3053 | if ($convert_date) { |
||
3054 | return api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT); |
||
3055 | } |
||
3056 | |||
3057 | return $last_login_date; |
||
3058 | } |
||
3059 | } |
||
3060 | } else { |
||
3061 | $sql = "SELECT logout_course_date |
||
3062 | FROM $table |
||
3063 | WHERE user_id = $student_id AND |
||
3064 | c_id = $courseId AND |
||
3065 | session_id = $session_id |
||
3066 | ORDER BY logout_course_date DESC |
||
3067 | LIMIT 0,1"; |
||
3068 | |||
3069 | $rs = Database::query($sql); |
||
3070 | if (Database::num_rows($rs) > 0) { |
||
3071 | if ($last_login_date = Database::result($rs, 0, 0)) { |
||
3072 | if (empty($last_login_date)) { |
||
3073 | return false; |
||
3074 | } |
||
3075 | // see #5736 |
||
3076 | $last_login_date_timestamp = api_strtotime($last_login_date); |
||
3077 | $now = time(); |
||
3078 | // If the last connection is > than 7 days, the text is red |
||
3079 | // 604800 = 7 days in seconds |
||
3080 | if ($now - $last_login_date_timestamp > 604800) { |
||
3081 | if ($convert_date) { |
||
3082 | $last_login_date = api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT); |
||
3083 | $icon = null; |
||
3084 | if (api_is_allowed_to_edit()) { |
||
3085 | $url = api_get_path(WEB_CODE_PATH). |
||
3086 | 'announcements/announcements.php?action=add&remind_inactive='.$student_id.'&cidReq='.$courseInfo['code']; |
||
3087 | $icon = '<a href="'.$url.'" title="'.get_lang('RemindInactiveUser').'"> |
||
3088 | '.Display::return_icon('messagebox_warning.gif').' |
||
3089 | </a>'; |
||
3090 | } |
||
3091 | |||
3092 | return $icon.Display::label($last_login_date, 'warning'); |
||
3093 | } |
||
3094 | |||
3095 | return $last_login_date; |
||
3096 | } else { |
||
3097 | if ($convert_date) { |
||
3098 | return api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT); |
||
3099 | } |
||
3100 | |||
3101 | return $last_login_date; |
||
3102 | } |
||
3103 | } |
||
3104 | } |
||
3105 | } |
||
3106 | |||
3107 | return false; |
||
3108 | } |
||
3109 | |||
3110 | public static function getLastConnectionInAnyCourse($studentId) |
||
3111 | { |
||
3112 | $studentId = (int) $studentId; |
||
3113 | |||
3114 | if (empty($studentId)) { |
||
3115 | return false; |
||
3116 | } |
||
3117 | |||
3118 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
3119 | $sql = "SELECT logout_course_date |
||
3120 | FROM $table |
||
3121 | WHERE user_id = $studentId |
||
3122 | ORDER BY logout_course_date DESC |
||
3123 | LIMIT 1"; |
||
3124 | $result = Database::query($sql); |
||
3125 | if (Database::num_rows($result)) { |
||
3126 | $row = Database::fetch_array($result); |
||
3127 | |||
3128 | return $row['logout_course_date']; |
||
3129 | } |
||
3130 | |||
3131 | return false; |
||
3132 | } |
||
3133 | |||
3134 | /** |
||
3135 | * Get last course access by course/session. |
||
3136 | */ |
||
3137 | public static function getLastConnectionDateByCourse($courseId, $sessionId = 0) |
||
3138 | { |
||
3139 | $courseId = (int) $courseId; |
||
3140 | $sessionId = (int) $sessionId; |
||
3141 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
3142 | |||
3143 | $sql = "SELECT logout_course_date |
||
3144 | FROM $table |
||
3145 | WHERE |
||
3146 | c_id = $courseId AND |
||
3147 | session_id = $sessionId |
||
3148 | ORDER BY logout_course_date DESC |
||
3149 | LIMIT 0,1"; |
||
3150 | |||
3151 | $result = Database::query($sql); |
||
3152 | if (Database::num_rows($result)) { |
||
3153 | $row = Database::fetch_array($result); |
||
3154 | if ($row) { |
||
3155 | return $row['logout_course_date']; |
||
3156 | } |
||
3157 | } |
||
3158 | |||
3159 | return ''; |
||
3160 | } |
||
3161 | |||
3162 | /** |
||
3163 | * Get count of the connections to the course during a specified period. |
||
3164 | * |
||
3165 | * @param int $courseId |
||
3166 | * @param int Session id (optional) |
||
3167 | * @param int Datetime from which to collect data (defaults to 0) |
||
3168 | * @param int Datetime to which to collect data (defaults to now) |
||
3169 | * |
||
3170 | * @return int count connections |
||
3171 | */ |
||
3172 | public static function get_course_connections_count( |
||
3173 | $courseId, |
||
3174 | $session_id = 0, |
||
3175 | $start = 0, |
||
3176 | $stop = null |
||
3177 | ) { |
||
3178 | if ($start < 0) { |
||
3179 | $start = 0; |
||
3180 | } |
||
3181 | if (!isset($stop) || $stop < 0) { |
||
3182 | $stop = api_get_utc_datetime(); |
||
3183 | } |
||
3184 | |||
3185 | // Given we're storing in cache, round the start and end times |
||
3186 | // to the lower minute |
||
3187 | $roundedStart = substr($start, 0, -2).'00'; |
||
3188 | $roundedStop = substr($stop, 0, -2).'00'; |
||
3189 | $roundedStart = Database::escape_string($roundedStart); |
||
3190 | $roundedStop = Database::escape_string($roundedStop); |
||
3191 | $month_filter = " AND login_course_date > '$roundedStart' AND login_course_date < '$roundedStop' "; |
||
3192 | $courseId = (int) $courseId; |
||
3193 | $session_id = (int) $session_id; |
||
3194 | $count = 0; |
||
3195 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
3196 | $sql = "SELECT count(*) as count_connections |
||
3197 | FROM $table |
||
3198 | WHERE |
||
3199 | c_id = $courseId AND |
||
3200 | session_id = $session_id |
||
3201 | $month_filter"; |
||
3202 | |||
3203 | // This query can be very slow (several seconds on an indexed table |
||
3204 | // with 14M rows). As such, we'll try to use APCu if it is |
||
3205 | // available to store the resulting value for a few seconds |
||
3206 | $cacheAvailable = api_get_configuration_value('apc'); |
||
3207 | if ($cacheAvailable === true) { |
||
3208 | $apc = apcu_cache_info(true); |
||
3209 | $apc_end = $apc['start_time'] + $apc['ttl']; |
||
3210 | $apc_var = api_get_configuration_value('apc_prefix').'course_access_'.$courseId.'_'.$session_id.'_'.strtotime($roundedStart).'_'.strtotime($roundedStop); |
||
3211 | if (apcu_exists($apc_var) && (time() < $apc_end) |
||
3212 | && apcu_fetch($apc_var) > 0 |
||
3213 | ) { |
||
3214 | $count = apcu_fetch($apc_var); |
||
3215 | } else { |
||
3216 | $rs = Database::query($sql); |
||
3217 | if (Database::num_rows($rs) > 0) { |
||
3218 | $row = Database::fetch_object($rs); |
||
3219 | $count = $row->count_connections; |
||
3220 | } |
||
3221 | apcu_clear_cache(); |
||
3222 | apcu_store($apc_var, $count, 60); |
||
3223 | } |
||
3224 | } else { |
||
3225 | $rs = Database::query($sql); |
||
3226 | if (Database::num_rows($rs) > 0) { |
||
3227 | $row = Database::fetch_object($rs); |
||
3228 | $count = $row->count_connections; |
||
3229 | } |
||
3230 | } |
||
3231 | |||
3232 | return $count; |
||
3233 | } |
||
3234 | |||
3235 | /** |
||
3236 | * Get count courses per student. |
||
3237 | * |
||
3238 | * @param int $user_id Student id |
||
3239 | * @param bool $include_sessions Include sessions (optional) |
||
3240 | * |
||
3241 | * @return int count courses |
||
3242 | */ |
||
3243 | public static function count_course_per_student($user_id, $include_sessions = true) |
||
3244 | { |
||
3245 | $user_id = (int) $user_id; |
||
3246 | $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER); |
||
3247 | $tbl_session_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
3248 | |||
3249 | $sql = 'SELECT DISTINCT c_id |
||
3250 | FROM '.$tbl_course_rel_user.' |
||
3251 | WHERE user_id = '.$user_id.' AND relation_type<>'.COURSE_RELATION_TYPE_RRHH; |
||
3252 | $rs = Database::query($sql); |
||
3253 | $nb_courses = Database::num_rows($rs); |
||
3254 | |||
3255 | if ($include_sessions) { |
||
3256 | $sql = 'SELECT DISTINCT c_id |
||
3257 | FROM '.$tbl_session_course_rel_user.' |
||
3258 | WHERE user_id = '.$user_id; |
||
3259 | $rs = Database::query($sql); |
||
3260 | $nb_courses += Database::num_rows($rs); |
||
3261 | } |
||
3262 | |||
3263 | return $nb_courses; |
||
3264 | } |
||
3265 | |||
3266 | public static function countSessionsPerStudent(int $userId): int |
||
3267 | { |
||
3268 | $tblSessionUser = Database::get_main_table(TABLE_MAIN_SESSION_USER); |
||
3269 | |||
3270 | $sql = 'SELECT DISTINCT id |
||
3271 | FROM '.$tblSessionUser.' |
||
3272 | WHERE relation_type = '.SessionEntity::STUDENT.' AND user_id = '.$userId; |
||
3273 | |||
3274 | $rs = Database::query($sql); |
||
3275 | |||
3276 | return Database::num_rows($rs); |
||
3277 | } |
||
3278 | |||
3279 | /** |
||
3280 | * Gets the score average from all tests in a course by student. |
||
3281 | * |
||
3282 | * @param $student_id |
||
3283 | * @param $course_code |
||
3284 | * @param int $exercise_id |
||
3285 | * @param null $session_id |
||
0 ignored issues
–
show
|
|||
3286 | * @param int $active_filter 2 for consider all tests |
||
3287 | * 1 for active <> -1 |
||
3288 | * 0 for active <> 0 |
||
3289 | * @param int $into_lp 1 for all exercises |
||
3290 | * 0 for without LP |
||
3291 | * @param mixed id |
||
3292 | * @param string code |
||
3293 | * @param int id (optional), filtered by exercise |
||
3294 | * @param int id (optional), if param $session_id is null |
||
3295 | * it'll return results including sessions, 0 = session is not |
||
3296 | * filtered |
||
3297 | * |
||
3298 | * @return string value (number %) Which represents a round integer about the score average |
||
3299 | */ |
||
3300 | public static function get_avg_student_exercise_score( |
||
3301 | $student_id, |
||
3302 | $course_code, |
||
3303 | $exercise_id = 0, |
||
3304 | $session_id = null, |
||
3305 | $active_filter = 1, |
||
3306 | $into_lp = 0 |
||
3307 | ) { |
||
3308 | $course_code = Database::escape_string($course_code); |
||
3309 | $course_info = api_get_course_info($course_code); |
||
3310 | if (!empty($course_info)) { |
||
3311 | // table definition |
||
3312 | $tbl_course_quiz = Database::get_course_table(TABLE_QUIZ_TEST); |
||
3313 | $tbl_stats_exercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
3314 | |||
3315 | // Compose a filter based on optional exercise given |
||
3316 | $condition_quiz = ""; |
||
3317 | if (!empty($exercise_id)) { |
||
3318 | $exercise_id = intval($exercise_id); |
||
3319 | $condition_quiz = " AND iid = $exercise_id "; |
||
3320 | } |
||
3321 | |||
3322 | // Compose a filter based on optional session id given |
||
3323 | $condition_session = ''; |
||
3324 | if (isset($session_id)) { |
||
3325 | $session_id = intval($session_id); |
||
3326 | $condition_session = " AND session_id = $session_id "; |
||
3327 | } |
||
3328 | if ($active_filter == 1) { |
||
3329 | $condition_active = 'AND active <> -1'; |
||
3330 | } elseif ($active_filter == 0) { |
||
3331 | $condition_active = 'AND active <> 0'; |
||
3332 | } else { |
||
3333 | $condition_active = ''; |
||
3334 | } |
||
3335 | $condition_into_lp = ''; |
||
3336 | $select_lp_id = ''; |
||
3337 | if ($into_lp == 0) { |
||
3338 | $condition_into_lp = 'AND orig_lp_id = 0 AND orig_lp_item_id = 0'; |
||
3339 | } else { |
||
3340 | $select_lp_id = ', orig_lp_id as lp_id '; |
||
3341 | } |
||
3342 | |||
3343 | $sql = "SELECT count(iid) |
||
3344 | FROM $tbl_course_quiz |
||
3345 | WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz "; |
||
3346 | $count_quiz = 0; |
||
3347 | $countQuizResult = Database::query($sql); |
||
3348 | if (!empty($countQuizResult)) { |
||
3349 | $count_quiz = Database::fetch_row($countQuizResult); |
||
3350 | } |
||
3351 | |||
3352 | if (!empty($count_quiz[0]) && !empty($student_id)) { |
||
3353 | if (is_array($student_id)) { |
||
3354 | $student_id = array_map('intval', $student_id); |
||
3355 | $condition_user = " AND exe_user_id IN (".implode(',', $student_id).") "; |
||
3356 | } else { |
||
3357 | $student_id = intval($student_id); |
||
3358 | $condition_user = " AND exe_user_id = '$student_id' "; |
||
3359 | } |
||
3360 | |||
3361 | if (empty($exercise_id)) { |
||
3362 | $sql = "SELECT iid FROM $tbl_course_quiz |
||
3363 | WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz"; |
||
3364 | $result = Database::query($sql); |
||
3365 | $exercise_list = []; |
||
3366 | $exercise_id = null; |
||
3367 | if (!empty($result) && Database::num_rows($result)) { |
||
3368 | while ($row = Database::fetch_array($result)) { |
||
3369 | $exercise_list[] = $row['iid']; |
||
3370 | } |
||
3371 | } |
||
3372 | if (!empty($exercise_list)) { |
||
3373 | $exercise_id = implode("','", $exercise_list); |
||
3374 | } |
||
3375 | } |
||
3376 | |||
3377 | $count_quiz = Database::fetch_row(Database::query($sql)); |
||
3378 | $sql = "SELECT |
||
3379 | SUM(exe_result/exe_weighting*100) as avg_score, |
||
3380 | COUNT(*) as num_attempts |
||
3381 | $select_lp_id |
||
3382 | FROM $tbl_stats_exercise |
||
3383 | WHERE |
||
3384 | exe_exo_id IN ('".$exercise_id."') |
||
3385 | $condition_user AND |
||
3386 | status = '' AND |
||
3387 | c_id = {$course_info['real_id']} |
||
3388 | $condition_session |
||
3389 | $condition_into_lp |
||
3390 | ORDER BY exe_date DESC"; |
||
3391 | |||
3392 | $res = Database::query($sql); |
||
3393 | $row = Database::fetch_array($res); |
||
3394 | $quiz_avg_score = null; |
||
3395 | |||
3396 | if (!empty($row['avg_score'])) { |
||
3397 | $quiz_avg_score = round($row['avg_score'], 2); |
||
3398 | } |
||
3399 | |||
3400 | if (!empty($row['num_attempts'])) { |
||
3401 | $quiz_avg_score = round($quiz_avg_score / $row['num_attempts'], 2); |
||
3402 | } |
||
3403 | if (is_array($student_id)) { |
||
3404 | $quiz_avg_score = round($quiz_avg_score / count($student_id), 2); |
||
3405 | } |
||
3406 | if ($into_lp == 0) { |
||
3407 | return $quiz_avg_score; |
||
3408 | } else { |
||
3409 | if (!empty($row['lp_id'])) { |
||
3410 | $tbl_lp = Database::get_course_table(TABLE_LP_MAIN); |
||
3411 | $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE); |
||
3412 | $sql = "SELECT lp.name |
||
3413 | FROM $tbl_lp as lp, $tbl_course as c |
||
3414 | WHERE |
||
3415 | c.code = '$course_code' AND |
||
3416 | lp.id = ".$row['lp_id']." AND |
||
3417 | lp.c_id = c.id |
||
3418 | LIMIT 1; |
||
3419 | "; |
||
3420 | $result = Database::query($sql); |
||
3421 | $row_lp = Database::fetch_row($result); |
||
3422 | $lp_name = null; |
||
3423 | if ($row_lp && isset($row_lp[0])) { |
||
3424 | $lp_name = $row_lp[0]; |
||
3425 | } |
||
3426 | |||
3427 | return [$quiz_avg_score, $lp_name]; |
||
3428 | } else { |
||
3429 | return [$quiz_avg_score, null]; |
||
3430 | } |
||
3431 | } |
||
3432 | } |
||
3433 | } |
||
3434 | |||
3435 | return null; |
||
3436 | } |
||
3437 | |||
3438 | /** |
||
3439 | * Get count student's exercise COMPLETED attempts. |
||
3440 | * |
||
3441 | * @param int $student_id |
||
3442 | * @param int $courseId |
||
3443 | * @param int $exercise_id |
||
3444 | * @param int $lp_id |
||
3445 | * @param int $lp_item_id |
||
3446 | * @param int $session_id |
||
3447 | * @param int $find_all_lp 0 = just LP specified |
||
3448 | * 1 = LP specified or whitout LP, |
||
3449 | * 2 = all rows |
||
3450 | * |
||
3451 | * @internal param \Student $int id |
||
3452 | * @internal param \Course $string code |
||
3453 | * @internal param \Exercise $int id |
||
3454 | * @internal param \Learning $int path id (optional), |
||
3455 | * for showing attempts inside a learning path $lp_id and $lp_item_id params are required |
||
3456 | * @internal param \Learning $int path item id (optional), |
||
3457 | * for showing attempts inside a learning path $lp_id and $lp_item_id params are required |
||
3458 | * |
||
3459 | * @return int count of attempts |
||
3460 | */ |
||
3461 | public static function count_student_exercise_attempts( |
||
3462 | $student_id, |
||
3463 | $courseId, |
||
3464 | $exercise_id, |
||
3465 | $lp_id = 0, |
||
3466 | $lp_item_id = 0, |
||
3467 | $session_id = 0, |
||
3468 | $find_all_lp = 0 |
||
3469 | ) { |
||
3470 | $courseId = intval($courseId); |
||
3471 | $student_id = intval($student_id); |
||
3472 | $exercise_id = intval($exercise_id); |
||
3473 | $session_id = intval($session_id); |
||
3474 | |||
3475 | $lp_id = intval($lp_id); |
||
3476 | $lp_item_id = intval($lp_item_id); |
||
3477 | $tbl_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
3478 | |||
3479 | $sql = "SELECT COUNT(ex.exe_id) as essais |
||
3480 | FROM $tbl_stats_exercises AS ex |
||
3481 | WHERE |
||
3482 | ex.c_id = $courseId AND |
||
3483 | ex.exe_exo_id = $exercise_id AND |
||
3484 | status = '' AND |
||
3485 | exe_user_id= $student_id AND |
||
3486 | session_id = $session_id "; |
||
3487 | |||
3488 | if ($find_all_lp == 1) { |
||
3489 | $sql .= "AND (orig_lp_id = $lp_id OR orig_lp_id = 0) |
||
3490 | AND (orig_lp_item_id = $lp_item_id OR orig_lp_item_id = 0)"; |
||
3491 | } elseif ($find_all_lp == 0) { |
||
3492 | $sql .= "AND orig_lp_id = $lp_id |
||
3493 | AND orig_lp_item_id = $lp_item_id"; |
||
3494 | } |
||
3495 | |||
3496 | $rs = Database::query($sql); |
||
3497 | $row = Database::fetch_row($rs); |
||
3498 | $count_attempts = $row[0]; |
||
3499 | |||
3500 | return $count_attempts; |
||
3501 | } |
||
3502 | |||
3503 | /** |
||
3504 | * It gets the last finalization date of learnpaths in a course. |
||
3505 | * |
||
3506 | * @return string finalization date formatted or false if it is empty. |
||
3507 | */ |
||
3508 | public static function getCourseLpFinalizationDate( |
||
3509 | int $userId, |
||
3510 | int $courseId, |
||
3511 | int $sessionId, |
||
3512 | bool $convertDate = true |
||
3513 | ) { |
||
3514 | $tblLpView = Database::get_course_table(TABLE_LP_VIEW); |
||
3515 | $tblLpItem = Database::get_course_table(TABLE_LP_ITEM); |
||
3516 | $tblLpItemView = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
3517 | |||
3518 | $sql = "SELECT FROM_UNIXTIME(liv.start_time) as start_date |
||
3519 | FROM $tblLpItemView liv |
||
3520 | INNER JOIN |
||
3521 | $tblLpView lv ON lv.iid = liv.lp_view_id |
||
3522 | INNER JOIN |
||
3523 | $tblLpItem li ON li.iid = liv.lp_item_id |
||
3524 | WHERE |
||
3525 | lv.user_id = $userId AND |
||
3526 | lv.c_id = $courseId AND |
||
3527 | lv.session_id = $sessionId AND |
||
3528 | li.item_type = '".TOOL_LP_FINAL_ITEM."' AND |
||
3529 | liv.status = 'completed' |
||
3530 | ORDER BY start_date DESC |
||
3531 | LIMIT 1"; |
||
3532 | |||
3533 | $rs = Database::query($sql); |
||
3534 | $lpFinalDate = Database::result($rs, 0, 0); |
||
3535 | |||
3536 | if (empty($lpFinalDate)) { |
||
3537 | return false; |
||
3538 | } |
||
3539 | |||
3540 | if ($convertDate) { |
||
3541 | return api_convert_and_format_date($lpFinalDate, DATE_FORMAT_SHORT); |
||
3542 | } |
||
3543 | |||
3544 | return $lpFinalDate; |
||
3545 | } |
||
3546 | |||
3547 | /** |
||
3548 | * It gets the last finalization date of exercises in a course. |
||
3549 | * |
||
3550 | * @return string finalization date formatted or false if it is empty. |
||
3551 | */ |
||
3552 | public static function getCourseQuizLastFinalizationDate( |
||
3553 | int $userId, |
||
3554 | int $courseId, |
||
3555 | int $sessionId, |
||
3556 | bool $convertDate = true |
||
3557 | ) { |
||
3558 | $tblTrackExercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
3559 | |||
3560 | $sql = "SELECT ex.exe_date |
||
3561 | FROM $tblTrackExercise AS ex |
||
3562 | WHERE |
||
3563 | ex.c_id = $courseId AND |
||
3564 | ex.session_id = $sessionId AND |
||
3565 | ex.exe_user_id = $userId AND |
||
3566 | ex.status = '' |
||
3567 | ORDER BY ex.exe_date DESC |
||
3568 | LIMIT 1"; |
||
3569 | $rs = Database::query($sql); |
||
3570 | $exeDate = Database::result($rs, 0, 0); |
||
3571 | |||
3572 | if (empty($exeDate)) { |
||
3573 | return false; |
||
3574 | } |
||
3575 | |||
3576 | if ($convertDate) { |
||
3577 | return api_convert_and_format_date($exeDate, DATE_FORMAT_SHORT); |
||
3578 | } |
||
3579 | |||
3580 | return $exeDate; |
||
3581 | } |
||
3582 | |||
3583 | /** |
||
3584 | * Get count student's exercise progress. |
||
3585 | * |
||
3586 | * @param array $exercise_list |
||
3587 | * @param int $user_id |
||
3588 | * @param int $courseId |
||
3589 | * @param int $session_id |
||
3590 | * |
||
3591 | * @return string |
||
3592 | */ |
||
3593 | public static function get_exercise_student_progress( |
||
3594 | $exercise_list, |
||
3595 | $user_id, |
||
3596 | $courseId, |
||
3597 | $session_id |
||
3598 | ) { |
||
3599 | $courseId = (int) $courseId; |
||
3600 | $user_id = (int) $user_id; |
||
3601 | $session_id = (int) $session_id; |
||
3602 | |||
3603 | if (empty($exercise_list)) { |
||
3604 | return '0%'; |
||
3605 | } |
||
3606 | $tbl_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
3607 | $exercise_list = array_keys($exercise_list); |
||
3608 | $exercise_list = array_map('intval', $exercise_list); |
||
3609 | |||
3610 | $exercise_list_imploded = implode("' ,'", $exercise_list); |
||
3611 | |||
3612 | $sql = "SELECT COUNT(DISTINCT ex.exe_exo_id) |
||
3613 | FROM $tbl_stats_exercises AS ex |
||
3614 | WHERE |
||
3615 | ex.c_id = $courseId AND |
||
3616 | ex.session_id = $session_id AND |
||
3617 | ex.exe_user_id = $user_id AND |
||
3618 | ex.status = '' AND |
||
3619 | ex.exe_exo_id IN ('$exercise_list_imploded') "; |
||
3620 | |||
3621 | $rs = Database::query($sql); |
||
3622 | $count = 0; |
||
3623 | if ($rs) { |
||
3624 | $row = Database::fetch_row($rs); |
||
3625 | $count = $row[0]; |
||
3626 | } |
||
3627 | $count = ($count != 0) ? 100 * round(intval($count) / count($exercise_list), 2).'%' : '0%'; |
||
3628 | |||
3629 | return $count; |
||
3630 | } |
||
3631 | |||
3632 | /** |
||
3633 | * @param array $exercise_list |
||
3634 | * @param int $user_id |
||
3635 | * @param int $courseId |
||
3636 | * @param int $session_id |
||
3637 | * |
||
3638 | * @return string |
||
3639 | */ |
||
3640 | public static function get_exercise_student_average_best_attempt( |
||
3641 | $exercise_list, |
||
3642 | $user_id, |
||
3643 | $courseId, |
||
3644 | $session_id |
||
3645 | ) { |
||
3646 | $result = 0; |
||
3647 | if (!empty($exercise_list)) { |
||
3648 | foreach ($exercise_list as $exercise_data) { |
||
3649 | $exercise_id = $exercise_data['iid']; |
||
3650 | $best_attempt = Event::get_best_attempt_exercise_results_per_user( |
||
3651 | $user_id, |
||
3652 | $exercise_id, |
||
3653 | $courseId, |
||
3654 | $session_id |
||
3655 | ); |
||
3656 | |||
3657 | if (!empty($best_attempt) && !empty($best_attempt['exe_weighting'])) { |
||
3658 | $result += $best_attempt['exe_result'] / $best_attempt['exe_weighting']; |
||
3659 | } |
||
3660 | } |
||
3661 | $result = $result / count($exercise_list); |
||
3662 | $result = round($result, 2) * 100; |
||
3663 | } |
||
3664 | |||
3665 | return $result.'%'; |
||
3666 | } |
||
3667 | |||
3668 | /** |
||
3669 | * Returns the average student progress in the learning paths of the given |
||
3670 | * course, it will take into account the progress that were not started. |
||
3671 | * |
||
3672 | * @param int|array $studentId |
||
3673 | * @param string $courseCode |
||
3674 | * @param array $lpIdList Limit average to listed lp ids |
||
3675 | * @param int $sessionId Session id (optional), |
||
3676 | * if parameter $session_id is null(default) it'll return results including |
||
3677 | * sessions, 0 = session is not filtered |
||
3678 | * @param bool $returnArray Will return an array of the type: |
||
3679 | * [sum_of_progresses, number] if it is set to true |
||
3680 | * @param bool $onlySeriousGame Optional. Limit average to lp on seriousgame mode |
||
3681 | * @param bool $maxInsteadAvg Optional. It will return the max progress instead the average |
||
3682 | * |
||
3683 | * @return float Average or max progress of the user in this course from 0 to 100 |
||
3684 | */ |
||
3685 | public static function get_avg_student_progress( |
||
3686 | $studentId, |
||
3687 | $courseCode = null, |
||
3688 | $lpIdList = [], |
||
3689 | $sessionId = null, |
||
3690 | $returnArray = false, |
||
3691 | $onlySeriousGame = false, |
||
3692 | $maxInsteadAvg = false, |
||
3693 | $startDate = null, |
||
3694 | $endDate = null |
||
3695 | ) { |
||
3696 | // If there is at least one learning path and one student. |
||
3697 | if (empty($studentId)) { |
||
3698 | return false; |
||
3699 | } |
||
3700 | |||
3701 | $sessionId = (int) $sessionId; |
||
3702 | $courseInfo = api_get_course_info($courseCode); |
||
3703 | |||
3704 | if (empty($courseInfo)) { |
||
3705 | return false; |
||
3706 | } |
||
3707 | |||
3708 | $lPTable = Database::get_course_table(TABLE_LP_MAIN); |
||
3709 | $lpViewTable = Database::get_course_table(TABLE_LP_VIEW); |
||
3710 | $lpConditions = []; |
||
3711 | $lpConditions['c_id = ? '] = $courseInfo['real_id']; |
||
3712 | |||
3713 | if ($sessionId > 0) { |
||
3714 | $lpConditions['AND (session_id = ? OR session_id = 0 OR session_id IS NULL)'] = $sessionId; |
||
3715 | } else { |
||
3716 | $lpConditions['AND session_id = ?'] = $sessionId; |
||
3717 | } |
||
3718 | |||
3719 | if (is_array($lpIdList) && count($lpIdList) > 0) { |
||
3720 | $placeHolders = []; |
||
3721 | for ($i = 0; $i < count($lpIdList); $i++) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
3722 | $placeHolders[] = '?'; |
||
3723 | } |
||
3724 | $lpConditions['AND id IN('.implode(', ', $placeHolders).') '] = $lpIdList; |
||
3725 | } |
||
3726 | |||
3727 | if ($onlySeriousGame) { |
||
3728 | $lpConditions['AND seriousgame_mode = ? '] = true; |
||
3729 | } |
||
3730 | |||
3731 | $resultLP = Database::select( |
||
3732 | 'id', |
||
3733 | $lPTable, |
||
3734 | ['where' => $lpConditions] |
||
3735 | ); |
||
3736 | $filteredLP = array_keys($resultLP); |
||
3737 | |||
3738 | if (empty($filteredLP)) { |
||
3739 | return false; |
||
3740 | } |
||
3741 | |||
3742 | $conditions = [ |
||
3743 | " lp_view.c_id = {$courseInfo['real_id']} ", |
||
3744 | " lp_view.lp_id IN (".implode(', ', $filteredLP).") ", |
||
3745 | ]; |
||
3746 | |||
3747 | $groupBy = 'GROUP BY lp_view.lp_id'; |
||
3748 | |||
3749 | if (is_array($studentId)) { |
||
3750 | $studentId = array_map('intval', $studentId); |
||
3751 | $conditions[] = " lp_view.user_id IN (".implode(',', $studentId).") "; |
||
3752 | } else { |
||
3753 | $studentId = (int) $studentId; |
||
3754 | $conditions[] = " lp_view.user_id = '$studentId' "; |
||
3755 | |||
3756 | if (empty($lpIdList)) { |
||
3757 | $lpList = new LearnpathList( |
||
3758 | $studentId, |
||
3759 | $courseInfo, |
||
3760 | $sessionId, |
||
3761 | null, |
||
3762 | false, |
||
3763 | null, |
||
3764 | true, |
||
3765 | false, |
||
3766 | true, |
||
3767 | true |
||
3768 | ); |
||
3769 | $lpList = $lpList->get_flat_list(); |
||
3770 | if (!empty($lpList)) { |
||
3771 | /** @var $lp */ |
||
3772 | foreach ($lpList as $lpId => $lp) { |
||
3773 | $lpIdList[] = $lp['lp_old_id']; |
||
3774 | } |
||
3775 | } |
||
3776 | } |
||
3777 | } |
||
3778 | |||
3779 | if (!empty($sessionId)) { |
||
3780 | $conditions[] = " session_id = $sessionId "; |
||
3781 | } else { |
||
3782 | $conditions[] = ' (session_id = 0 OR session_id IS NULL) '; |
||
3783 | } |
||
3784 | |||
3785 | $innerJoin = ""; |
||
3786 | if (!empty($startDate) || !empty($endDate)) { |
||
3787 | $lpItemViewTable = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
3788 | $innerJoin = " INNER JOIN $lpItemViewTable liv ON liv.lp_view_id = lp_view.iid"; |
||
3789 | if (!empty($startDate)) { |
||
3790 | $startDate = api_get_utc_datetime($startDate, false, true); |
||
3791 | $startTime = strtotime($startDate->format('Y-m-d 00:00:00')); |
||
3792 | $conditions[] = " liv.start_time >= '".$startTime."' "; |
||
3793 | } |
||
3794 | if (!empty($endDate)) { |
||
3795 | $endDate = api_get_utc_datetime($endDate, false, true); |
||
3796 | $endTime = strtotime($endDate->format('Y-m-d 23:59:59')); |
||
3797 | $conditions[] = " liv.start_time <= '".$endTime."' "; |
||
3798 | } |
||
3799 | } |
||
3800 | |||
3801 | $conditionToString = implode('AND', $conditions); |
||
3802 | $sql = "SELECT lp_view.lp_id, lp_view.view_count, lp_view.progress |
||
3803 | FROM $lpViewTable lp_view |
||
3804 | $innerJoin |
||
3805 | WHERE |
||
3806 | $conditionToString |
||
3807 | $groupBy |
||
3808 | ORDER BY view_count DESC"; |
||
3809 | $result = Database::query($sql); |
||
3810 | |||
3811 | $progress = []; |
||
3812 | $viewCount = []; |
||
3813 | while ($row = Database::fetch_array($result, 'ASSOC')) { |
||
3814 | if (!isset($viewCount[$row['lp_id']])) { |
||
3815 | $progress[$row['lp_id']] = $row['progress']; |
||
3816 | } |
||
3817 | $viewCount[$row['lp_id']] = $row['view_count']; |
||
3818 | } |
||
3819 | |||
3820 | // Fill with lp ids |
||
3821 | $newProgress = []; |
||
3822 | if (!empty($lpIdList)) { |
||
3823 | foreach ($lpIdList as $lpId) { |
||
3824 | if (isset($progress[$lpId])) { |
||
3825 | $newProgress[] = $progress[$lpId]; |
||
3826 | } |
||
3827 | } |
||
3828 | $total = count($lpIdList); |
||
3829 | } else { |
||
3830 | $newProgress = $progress; |
||
3831 | $total = count($newProgress); |
||
3832 | } |
||
3833 | |||
3834 | $average = 0; |
||
3835 | $sum = 0; |
||
3836 | if (!empty($newProgress)) { |
||
3837 | if ($maxInsteadAvg) { |
||
3838 | // It will return the max progress instead the average |
||
3839 | return max($newProgress); |
||
3840 | } else { |
||
3841 | $sum = array_sum($newProgress); |
||
3842 | $average = $sum / $total; |
||
3843 | } |
||
3844 | } |
||
3845 | |||
3846 | if ($returnArray) { |
||
3847 | return [ |
||
3848 | $sum, |
||
3849 | $total, |
||
3850 | ]; |
||
3851 | } |
||
3852 | |||
3853 | return round($average, 1); |
||
3854 | } |
||
3855 | |||
3856 | /** |
||
3857 | * This function gets: |
||
3858 | * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores. |
||
3859 | * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores. |
||
3860 | * 3. And finally it will return the average between 1. and 2. |
||
3861 | * |
||
3862 | * @todo improve performance, when loading 1500 users with 20 lps the script dies |
||
3863 | * This function does not take the results of a Test out of a LP |
||
3864 | * |
||
3865 | * @param mixed $student_id Array of user ids or an user id |
||
3866 | * @param string $course_code |
||
3867 | * @param array $lp_ids List of LP ids |
||
3868 | * @param int $session_id Session id (optional), |
||
3869 | * if param $session_id is null(default) it'll return results |
||
3870 | * including sessions, 0 = session is not filtered |
||
3871 | * @param bool $return_array Returns an array of the |
||
3872 | * type [sum_score, num_score] if set to true |
||
3873 | * @param bool $get_only_latest_attempt_results get only the latest attempts or ALL attempts |
||
3874 | * @param bool $getOnlyBestAttempt |
||
3875 | * |
||
3876 | * @return string value (number %) Which represents a round integer explain in got in 3 |
||
3877 | */ |
||
3878 | public static function get_avg_student_score( |
||
3879 | $student_id, |
||
3880 | $course_code, |
||
3881 | $lp_ids = [], |
||
3882 | $session_id = null, |
||
3883 | $return_array = false, |
||
3884 | $get_only_latest_attempt_results = false, |
||
3885 | $getOnlyBestAttempt = false |
||
3886 | ) { |
||
3887 | $debug = false; |
||
3888 | if ($debug) { |
||
3889 | echo '<h1>Tracking::get_avg_student_score</h1>'; |
||
3890 | } |
||
3891 | $tbl_stats_exercices = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
3892 | $tbl_stats_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
3893 | $course = api_get_course_info($course_code); |
||
3894 | |||
3895 | if (empty($course)) { |
||
3896 | return null; |
||
3897 | } |
||
3898 | |||
3899 | // Get course tables names |
||
3900 | $tbl_quiz_questions = Database::get_course_table(TABLE_QUIZ_QUESTION); |
||
3901 | $lp_table = Database::get_course_table(TABLE_LP_MAIN); |
||
3902 | $lp_item_table = Database::get_course_table(TABLE_LP_ITEM); |
||
3903 | $lp_view_table = Database::get_course_table(TABLE_LP_VIEW); |
||
3904 | $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
3905 | $course_id = $course['real_id']; |
||
3906 | |||
3907 | // Compose a filter based on optional learning paths list given |
||
3908 | $condition_lp = ''; |
||
3909 | if (count($lp_ids) > 0) { |
||
3910 | $condition_lp = " AND id IN(".implode(',', $lp_ids).") "; |
||
3911 | } |
||
3912 | |||
3913 | // Compose a filter based on optional session id |
||
3914 | $session_id = (int) $session_id; |
||
3915 | if (count($lp_ids) > 0) { |
||
3916 | $condition_session = " AND session_id = $session_id "; |
||
3917 | } else { |
||
3918 | $condition_session = " WHERE session_id = $session_id "; |
||
3919 | } |
||
3920 | |||
3921 | // Check the real number of LPs corresponding to the filter in the |
||
3922 | // database (and if no list was given, get them all) |
||
3923 | if (empty($session_id)) { |
||
3924 | $sql = "SELECT DISTINCT(id), use_max_score |
||
3925 | FROM $lp_table |
||
3926 | WHERE |
||
3927 | c_id = $course_id AND |
||
3928 | (session_id = 0 OR session_id IS NULL) $condition_lp "; |
||
3929 | } else { |
||
3930 | $sql = "SELECT DISTINCT(id), use_max_score |
||
3931 | FROM $lp_table |
||
3932 | WHERE c_id = $course_id $condition_lp "; |
||
3933 | } |
||
3934 | |||
3935 | $res_row_lp = Database::query($sql); |
||
3936 | $count_row_lp = Database::num_rows($res_row_lp); |
||
3937 | |||
3938 | $lp_list = $use_max_score = []; |
||
3939 | while ($row_lp = Database::fetch_array($res_row_lp)) { |
||
3940 | $lp_list[] = $row_lp['id']; |
||
3941 | $use_max_score[$row_lp['id']] = $row_lp['use_max_score']; |
||
3942 | } |
||
3943 | |||
3944 | // prepare filter on users |
||
3945 | if (is_array($student_id)) { |
||
3946 | array_walk($student_id, 'intval'); |
||
3947 | $condition_user1 = " AND user_id IN (".implode(',', $student_id).") "; |
||
3948 | } else { |
||
3949 | $condition_user1 = " AND user_id = $student_id "; |
||
3950 | } |
||
3951 | |||
3952 | if (empty($count_row_lp) || empty($student_id)) { |
||
3953 | return null; |
||
3954 | } |
||
3955 | |||
3956 | // Getting latest LP result for a student |
||
3957 | // @todo problem when a course have more than 1500 users |
||
3958 | $sql = "SELECT MAX(view_count) as vc, id, progress, lp_id, user_id |
||
3959 | FROM $lp_view_table |
||
3960 | WHERE |
||
3961 | c_id = $course_id AND |
||
3962 | lp_id IN (".implode(',', $lp_list).") |
||
3963 | $condition_user1 AND |
||
3964 | session_id = $session_id |
||
3965 | GROUP BY lp_id, user_id"; |
||
3966 | |||
3967 | $rs_last_lp_view_id = Database::query($sql); |
||
3968 | $global_result = 0; |
||
3969 | |||
3970 | if (Database::num_rows($rs_last_lp_view_id) > 0) { |
||
3971 | // Cycle through each line of the results (grouped by lp_id, user_id) |
||
3972 | while ($row_lp_view = Database::fetch_array($rs_last_lp_view_id)) { |
||
3973 | $count_items = 0; |
||
3974 | $lpPartialTotal = 0; |
||
3975 | $list = []; |
||
3976 | $lp_view_id = $row_lp_view['id']; |
||
3977 | $lp_id = $row_lp_view['lp_id']; |
||
3978 | $user_id = $row_lp_view['user_id']; |
||
3979 | |||
3980 | if ($debug) { |
||
3981 | echo '<h2>LP id '.$lp_id.'</h2>'; |
||
3982 | echo "get_only_latest_attempt_results: $get_only_latest_attempt_results <br />"; |
||
3983 | echo "getOnlyBestAttempt: $getOnlyBestAttempt <br />"; |
||
3984 | } |
||
3985 | |||
3986 | if ($get_only_latest_attempt_results || $getOnlyBestAttempt) { |
||
3987 | // Getting lp_items done by the user |
||
3988 | $sql = "SELECT DISTINCT lp_item_id |
||
3989 | FROM $lp_item_view_table |
||
3990 | WHERE |
||
3991 | c_id = $course_id AND |
||
3992 | lp_view_id = $lp_view_id |
||
3993 | ORDER BY lp_item_id"; |
||
3994 | $res_lp_item = Database::query($sql); |
||
3995 | |||
3996 | while ($row_lp_item = Database::fetch_array($res_lp_item, 'ASSOC')) { |
||
3997 | $my_lp_item_id = $row_lp_item['lp_item_id']; |
||
3998 | $order = ' view_count DESC'; |
||
3999 | if ($getOnlyBestAttempt) { |
||
4000 | $order = ' lp_iv.score DESC'; |
||
4001 | } |
||
4002 | |||
4003 | // Getting the most recent attempt |
||
4004 | $sql = "SELECT |
||
4005 | lp_iv.id as lp_item_view_id, |
||
4006 | lp_iv.score as score, |
||
4007 | lp_i.max_score, |
||
4008 | lp_iv.max_score as max_score_item_view, |
||
4009 | lp_i.path, |
||
4010 | lp_i.item_type, |
||
4011 | lp_i.id as iid |
||
4012 | FROM $lp_item_view_table as lp_iv |
||
4013 | INNER JOIN $lp_item_table as lp_i |
||
4014 | ON ( |
||
4015 | lp_i.id = lp_iv.lp_item_id AND |
||
4016 | lp_iv.c_id = lp_i.c_id |
||
4017 | ) |
||
4018 | WHERE |
||
4019 | lp_iv.c_id = $course_id AND |
||
4020 | lp_i.c_id = $course_id AND |
||
4021 | lp_item_id = $my_lp_item_id AND |
||
4022 | lp_view_id = $lp_view_id AND |
||
4023 | (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."') |
||
4024 | ORDER BY $order |
||
4025 | LIMIT 1"; |
||
4026 | |||
4027 | $res_lp_item_result = Database::query($sql); |
||
4028 | while ($row_max_score = Database::fetch_array($res_lp_item_result, 'ASSOC')) { |
||
4029 | $list[] = $row_max_score; |
||
4030 | } |
||
4031 | } |
||
4032 | } else { |
||
4033 | // For the currently analysed view, get the score and |
||
4034 | // max_score of each item if it is a sco or a TOOL_QUIZ |
||
4035 | $sql = "SELECT |
||
4036 | lp_iv.id as lp_item_view_id, |
||
4037 | lp_iv.score as score, |
||
4038 | lp_i.max_score, |
||
4039 | lp_iv.max_score as max_score_item_view, |
||
4040 | lp_i.path, |
||
4041 | lp_i.item_type, |
||
4042 | lp_i.id as iid |
||
4043 | FROM $lp_item_view_table as lp_iv |
||
4044 | INNER JOIN $lp_item_table as lp_i |
||
4045 | ON lp_i.id = lp_iv.lp_item_id AND |
||
4046 | lp_iv.c_id = lp_i.c_id |
||
4047 | WHERE |
||
4048 | lp_iv.c_id = $course_id AND |
||
4049 | lp_i.c_id = $course_id AND |
||
4050 | lp_view_id = $lp_view_id AND |
||
4051 | (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."') |
||
4052 | "; |
||
4053 | $res_max_score = Database::query($sql); |
||
4054 | while ($row_max_score = Database::fetch_array($res_max_score, 'ASSOC')) { |
||
4055 | $list[] = $row_max_score; |
||
4056 | } |
||
4057 | } |
||
4058 | |||
4059 | // Go through each scorable element of this view |
||
4060 | $score_of_scorm_calculate = 0; |
||
4061 | foreach ($list as $row_max_score) { |
||
4062 | // Came from the original lp_item |
||
4063 | $max_score = $row_max_score['max_score']; |
||
4064 | // Came from the lp_item_view |
||
4065 | $max_score_item_view = $row_max_score['max_score_item_view']; |
||
4066 | $score = $row_max_score['score']; |
||
4067 | if ($debug) { |
||
4068 | echo '<h3>Item Type: '.$row_max_score['item_type'].'</h3>'; |
||
4069 | } |
||
4070 | |||
4071 | if ($row_max_score['item_type'] === 'sco') { |
||
4072 | /* Check if it is sco (easier to get max_score) |
||
4073 | when there's no max score, we assume 100 as the max score, |
||
4074 | as the SCORM 1.2 says that the value should always be between 0 and 100. |
||
4075 | */ |
||
4076 | if ($max_score == 0 || is_null($max_score) || $max_score == '') { |
||
4077 | // Chamilo style |
||
4078 | if ($use_max_score[$lp_id]) { |
||
4079 | $max_score = 100; |
||
4080 | } else { |
||
4081 | // Overwrites max score = 100 to use the one that came in the lp_item_view see BT#1613 |
||
4082 | $max_score = $max_score_item_view; |
||
4083 | } |
||
4084 | } |
||
4085 | // Avoid division by zero errors |
||
4086 | if (!empty($max_score)) { |
||
4087 | $lpPartialTotal += $score / $max_score; |
||
4088 | } |
||
4089 | if ($debug) { |
||
4090 | var_dump("lpPartialTotal: $lpPartialTotal"); |
||
0 ignored issues
–
show
|
|||
4091 | var_dump("score: $score"); |
||
4092 | var_dump("max_score: $max_score"); |
||
4093 | } |
||
4094 | } else { |
||
4095 | // Case of a TOOL_QUIZ element |
||
4096 | $item_id = $row_max_score['iid']; |
||
4097 | $item_path = $row_max_score['path']; |
||
4098 | $lp_item_view_id = (int) $row_max_score['lp_item_view_id']; |
||
4099 | |||
4100 | if (empty($lp_item_view_id)) { |
||
4101 | $lpItemCondition = ' (orig_lp_item_view_id = 0 OR orig_lp_item_view_id IS NULL) '; |
||
4102 | } else { |
||
4103 | $lpItemCondition = " orig_lp_item_view_id = $lp_item_view_id "; |
||
4104 | } |
||
4105 | |||
4106 | // Get last attempt to this exercise through |
||
4107 | // the current lp for the current user |
||
4108 | $order = 'exe_date DESC'; |
||
4109 | if ($getOnlyBestAttempt) { |
||
4110 | $order = 'exe_result DESC'; |
||
4111 | } |
||
4112 | $sql = "SELECT exe_id, exe_result |
||
4113 | FROM $tbl_stats_exercices |
||
4114 | WHERE |
||
4115 | exe_exo_id = '$item_path' AND |
||
4116 | exe_user_id = $user_id AND |
||
4117 | orig_lp_item_id = $item_id AND |
||
4118 | $lpItemCondition AND |
||
4119 | c_id = $course_id AND |
||
4120 | session_id = $session_id AND |
||
4121 | status = '' |
||
4122 | ORDER BY $order |
||
4123 | LIMIT 1"; |
||
4124 | |||
4125 | $result_last_attempt = Database::query($sql); |
||
4126 | $num = Database::num_rows($result_last_attempt); |
||
4127 | if ($num > 0) { |
||
4128 | $attemptResult = Database::fetch_array($result_last_attempt, 'ASSOC'); |
||
4129 | $id_last_attempt = (int) $attemptResult['exe_id']; |
||
4130 | // We overwrite the score with the best one not the one saved in the LP (latest) |
||
4131 | if ($getOnlyBestAttempt && $get_only_latest_attempt_results == false) { |
||
4132 | if ($debug) { |
||
4133 | echo "Following score comes from the track_exercise table not in the LP because the score is the best<br />"; |
||
4134 | } |
||
4135 | $score = $attemptResult['exe_result']; |
||
4136 | } |
||
4137 | |||
4138 | if ($debug) { |
||
4139 | echo "Attempt id: $id_last_attempt with score $score<br />"; |
||
4140 | } |
||
4141 | // Within the last attempt number tracking, get the sum of |
||
4142 | // the max_scores of all questions that it was |
||
4143 | // made of (we need to make this call dynamic because of random questions selection) |
||
4144 | $sql = "SELECT SUM(t.ponderation) as maxscore FROM |
||
4145 | ( |
||
4146 | SELECT DISTINCT |
||
4147 | question_id, |
||
4148 | marks, |
||
4149 | ponderation |
||
4150 | FROM $tbl_stats_attempts AS at |
||
4151 | INNER JOIN $tbl_quiz_questions AS q |
||
4152 | ON q.iid = at.question_id |
||
4153 | WHERE |
||
4154 | exe_id = $id_last_attempt AND |
||
4155 | at.c_id = $course_id |
||
4156 | ) |
||
4157 | AS t"; |
||
4158 | |||
4159 | $res_max_score_bis = Database::query($sql); |
||
4160 | $row_max_score_bis = Database::fetch_array($res_max_score_bis); |
||
4161 | |||
4162 | if (!empty($row_max_score_bis['maxscore'])) { |
||
4163 | $max_score = $row_max_score_bis['maxscore']; |
||
4164 | } |
||
4165 | if (!empty($max_score) && floatval($max_score) > 0) { |
||
4166 | $lpPartialTotal += $score / $max_score; |
||
4167 | } |
||
4168 | if ($debug) { |
||
4169 | var_dump("score: $score"); |
||
4170 | var_dump("max_score: $max_score"); |
||
4171 | var_dump("lpPartialTotal: $lpPartialTotal"); |
||
4172 | } |
||
4173 | } |
||
4174 | } |
||
4175 | |||
4176 | if (in_array($row_max_score['item_type'], ['quiz', 'sco'])) { |
||
4177 | // Normal way |
||
4178 | if ($use_max_score[$lp_id]) { |
||
4179 | $count_items++; |
||
4180 | } else { |
||
4181 | if ($max_score != '') { |
||
4182 | $count_items++; |
||
4183 | } |
||
4184 | } |
||
4185 | if ($debug) { |
||
4186 | echo '$count_items: '.$count_items; |
||
4187 | } |
||
4188 | } |
||
4189 | } // end for |
||
4190 | |||
4191 | $score_of_scorm_calculate += $count_items ? (($lpPartialTotal / $count_items) * 100) : 0; |
||
4192 | $global_result += $score_of_scorm_calculate; |
||
4193 | |||
4194 | if ($debug) { |
||
4195 | var_dump("count_items: $count_items"); |
||
4196 | var_dump("score_of_scorm_calculate: $score_of_scorm_calculate"); |
||
4197 | var_dump("global_result: $global_result"); |
||
4198 | } |
||
4199 | } // end while |
||
4200 | } |
||
4201 | |||
4202 | $lp_with_quiz = 0; |
||
4203 | foreach ($lp_list as $lp_id) { |
||
4204 | // Check if LP have a score we assume that all SCO have an score |
||
4205 | $sql = "SELECT count(id) as count |
||
4206 | FROM $lp_item_table |
||
4207 | WHERE |
||
4208 | c_id = $course_id AND |
||
4209 | (item_type = 'quiz' OR item_type = 'sco') AND |
||
4210 | lp_id = ".$lp_id; |
||
4211 | $result_have_quiz = Database::query($sql); |
||
4212 | if (Database::num_rows($result_have_quiz) > 0) { |
||
4213 | $row = Database::fetch_array($result_have_quiz, 'ASSOC'); |
||
4214 | if (is_numeric($row['count']) && $row['count'] != 0) { |
||
4215 | $lp_with_quiz++; |
||
4216 | } |
||
4217 | } |
||
4218 | } |
||
4219 | |||
4220 | if ($debug) { |
||
4221 | echo '<h3>$lp_with_quiz '.$lp_with_quiz.' </h3>'; |
||
4222 | } |
||
4223 | if ($debug) { |
||
4224 | echo '<h3>Final return</h3>'; |
||
4225 | } |
||
4226 | |||
4227 | if ($lp_with_quiz != 0) { |
||
4228 | if (!$return_array) { |
||
4229 | $score_of_scorm_calculate = round($global_result / $lp_with_quiz, 2); |
||
4230 | if ($debug) { |
||
4231 | var_dump($score_of_scorm_calculate); |
||
4232 | } |
||
4233 | if (empty($lp_ids)) { |
||
4234 | if ($debug) { |
||
4235 | echo '<h2>All lps fix: '.$score_of_scorm_calculate.'</h2>'; |
||
4236 | } |
||
4237 | } |
||
4238 | |||
4239 | return $score_of_scorm_calculate; |
||
4240 | } |
||
4241 | |||
4242 | if ($debug) { |
||
4243 | var_dump($global_result, $lp_with_quiz); |
||
4244 | } |
||
4245 | |||
4246 | return [$global_result, $lp_with_quiz]; |
||
4247 | } |
||
4248 | |||
4249 | return '-'; |
||
4250 | } |
||
4251 | |||
4252 | /** |
||
4253 | * This function gets: |
||
4254 | * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores. |
||
4255 | * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores. |
||
4256 | * 3. And finally it will return the average between 1. and 2. |
||
4257 | * This function does not take the results of a Test out of a LP. |
||
4258 | * |
||
4259 | * @param int|array $student_id Array of user ids or an user id |
||
4260 | * @param string $course_code Course code |
||
4261 | * @param array $lp_ids List of LP ids |
||
4262 | * @param int $session_id Session id (optional), if param $session_id is 0(default) |
||
4263 | * it'll return results including sessions, 0 = session is not filtered |
||
4264 | * |
||
4265 | * @return string value (number %) Which represents a round integer explain in got in 3 |
||
4266 | */ |
||
4267 | public static function getAverageStudentScore( |
||
4268 | $student_id, |
||
4269 | $course_code = '', |
||
4270 | $lp_ids = [], |
||
4271 | $session_id = 0 |
||
4272 | ) { |
||
4273 | if (empty($student_id)) { |
||
4274 | return 0; |
||
4275 | } |
||
4276 | |||
4277 | $conditions = []; |
||
4278 | if (!empty($course_code)) { |
||
4279 | $course = api_get_course_info($course_code); |
||
4280 | $courseId = $course['real_id']; |
||
4281 | $conditions[] = " lp.c_id = $courseId"; |
||
4282 | } |
||
4283 | |||
4284 | // Get course tables names |
||
4285 | $lp_table = Database::get_course_table(TABLE_LP_MAIN); |
||
4286 | $lp_item_table = Database::get_course_table(TABLE_LP_ITEM); |
||
4287 | $lp_view_table = Database::get_course_table(TABLE_LP_VIEW); |
||
4288 | $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
4289 | |||
4290 | // Compose a filter based on optional learning paths list given |
||
4291 | if (!empty($lp_ids) && count($lp_ids) > 0) { |
||
4292 | $conditions[] = ' lp.id IN ('.implode(',', $lp_ids).') '; |
||
4293 | } |
||
4294 | |||
4295 | // Compose a filter based on optional session id |
||
4296 | $session_id = (int) $session_id; |
||
4297 | if (!empty($session_id)) { |
||
4298 | $conditions[] = " lp_view.session_id = $session_id "; |
||
4299 | } |
||
4300 | |||
4301 | if (is_array($student_id)) { |
||
4302 | array_walk($student_id, 'intval'); |
||
4303 | $conditions[] = " lp_view.user_id IN (".implode(',', $student_id).") "; |
||
4304 | } else { |
||
4305 | $student_id = (int) $student_id; |
||
4306 | $conditions[] = " lp_view.user_id = $student_id "; |
||
4307 | } |
||
4308 | |||
4309 | $conditionsToString = implode(' AND ', $conditions); |
||
4310 | $sql = "SELECT |
||
4311 | SUM(lp_iv.score) sum_score, |
||
4312 | SUM(lp_i.max_score) sum_max_score |
||
4313 | FROM $lp_table as lp |
||
4314 | INNER JOIN $lp_item_table as lp_i |
||
4315 | ON lp.iid = lp_id AND lp.c_id = lp_i.c_id |
||
4316 | INNER JOIN $lp_view_table as lp_view |
||
4317 | ON lp_view.lp_id = lp_i.lp_id AND lp_view.c_id = lp_i.c_id |
||
4318 | INNER JOIN $lp_item_view_table as lp_iv |
||
4319 | ON lp_i.iid = lp_iv.lp_item_id AND lp_view.c_id = lp_iv.c_id AND lp_iv.lp_view_id = lp_view.iid |
||
4320 | WHERE (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."') AND |
||
4321 | $conditionsToString |
||
4322 | "; |
||
4323 | $result = Database::query($sql); |
||
4324 | $row = Database::fetch_array($result, 'ASSOC'); |
||
4325 | |||
4326 | if (empty($row['sum_max_score'])) { |
||
4327 | return 0; |
||
4328 | } |
||
4329 | |||
4330 | return ($row['sum_score'] / $row['sum_max_score']) * 100; |
||
4331 | } |
||
4332 | |||
4333 | /** |
||
4334 | * This function gets time spent in learning path for a student inside a course. |
||
4335 | * |
||
4336 | * @param int|array $student_id Student id(s) |
||
4337 | * @param string $course_code Course code |
||
4338 | * @param array $lp_ids Limit average to listed lp ids |
||
4339 | * @param int $session_id Session id (optional), if param $session_id is null(default) |
||
4340 | * it'll return results including sessions, 0 = session is not filtered |
||
4341 | * |
||
4342 | * @return int Total time in seconds |
||
4343 | */ |
||
4344 | public static function get_time_spent_in_lp( |
||
4345 | $student_id, |
||
4346 | $course_code, |
||
4347 | $lp_ids = [], |
||
4348 | $session_id = 0 |
||
4349 | ) { |
||
4350 | $course = api_get_course_info($course_code); |
||
4351 | $student_id = (int) $student_id; |
||
4352 | $session_id = (int) $session_id; |
||
4353 | $total_time = 0; |
||
4354 | |||
4355 | if (!empty($course)) { |
||
4356 | $lpTable = Database::get_course_table(TABLE_LP_MAIN); |
||
4357 | $lpItemTable = Database::get_course_table(TABLE_LP_ITEM); |
||
4358 | $lpViewTable = Database::get_course_table(TABLE_LP_VIEW); |
||
4359 | $lpItemViewTable = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
4360 | $trackExercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
4361 | $course_id = $course['real_id']; |
||
4362 | |||
4363 | // Compose a filter based on optional learning paths list given |
||
4364 | $condition_lp = ''; |
||
4365 | if (count($lp_ids) > 0) { |
||
4366 | $condition_lp = " AND id IN(".implode(',', $lp_ids).") "; |
||
4367 | } |
||
4368 | |||
4369 | // Check the real number of LPs corresponding to the filter in the |
||
4370 | // database (and if no list was given, get them all) |
||
4371 | $sql = "SELECT DISTINCT(id) FROM $lpTable |
||
4372 | WHERE c_id = $course_id $condition_lp"; |
||
4373 | $result = Database::query($sql); |
||
4374 | $session_condition = api_get_session_condition($session_id); |
||
4375 | |||
4376 | // calculates time |
||
4377 | if (Database::num_rows($result) > 0) { |
||
4378 | while ($row = Database::fetch_array($result)) { |
||
4379 | $lp_id = (int) $row['id']; |
||
4380 | |||
4381 | // Start Exercise in LP total_time |
||
4382 | // Get duration time from track_e_exercises.exe_duration instead of lp_view_item.total_time |
||
4383 | $list = learnpath::get_flat_ordered_items_list($lp_id, 0, $course_id); |
||
4384 | foreach ($list as $itemId) { |
||
4385 | $sql = "SELECT max(view_count) |
||
4386 | FROM $lpViewTable |
||
4387 | WHERE |
||
4388 | c_id = $course_id AND |
||
4389 | lp_id = $lp_id AND |
||
4390 | user_id = $student_id |
||
4391 | $session_condition"; |
||
4392 | $res = Database::query($sql); |
||
4393 | $view = ''; |
||
4394 | if (Database::num_rows($res) > 0) { |
||
4395 | $myrow = Database::fetch_array($res); |
||
4396 | $view = $myrow[0]; |
||
4397 | } |
||
4398 | $viewCondition = null; |
||
4399 | if (!empty($view)) { |
||
4400 | $viewCondition = " AND v.view_count = $view "; |
||
4401 | } |
||
4402 | $sql = "SELECT |
||
4403 | iv.iid, |
||
4404 | iv.total_time as mytime, |
||
4405 | i.id as myid, |
||
4406 | iv.view_count as iv_view_count, |
||
4407 | path |
||
4408 | FROM $lpItemTable as i |
||
4409 | INNER JOIN $lpItemViewTable as iv |
||
4410 | ON (i.id = iv.lp_item_id AND i.c_id = iv.c_id) |
||
4411 | INNER JOIN $lpViewTable as v |
||
4412 | ON (iv.lp_view_id = v.id AND v.c_id = iv.c_id) |
||
4413 | WHERE |
||
4414 | v.c_id = $course_id AND |
||
4415 | i.id = $itemId AND |
||
4416 | i.lp_id = $lp_id AND |
||
4417 | v.user_id = $student_id AND |
||
4418 | item_type = 'quiz' AND |
||
4419 | path <> '' AND |
||
4420 | v.session_id = $session_id |
||
4421 | $viewCondition |
||
4422 | ORDER BY iv.view_count DESC "; |
||
4423 | |||
4424 | $resultRow = Database::query($sql); |
||
4425 | if (Database::num_rows($resultRow)) { |
||
4426 | $row = Database::fetch_array($resultRow); |
||
4427 | $totalTimeInLpItemView = $row['mytime']; |
||
4428 | $lpItemViewId = $row['iid']; |
||
4429 | |||
4430 | $sql = 'SELECT SUM(exe_duration) exe_duration |
||
4431 | FROM '.$trackExercises.' |
||
4432 | WHERE |
||
4433 | exe_exo_id="'.$row['path'].'" AND |
||
4434 | exe_user_id="'.$student_id.'" AND |
||
4435 | orig_lp_id = "'.$lp_id.'" AND |
||
4436 | orig_lp_item_id = "'.$row['myid'].'" AND |
||
4437 | c_id = '.$course_id.' AND |
||
4438 | status <> "incomplete" AND |
||
4439 | session_id = '.$session_id.' |
||
4440 | ORDER BY exe_date DESC '; |
||
4441 | |||
4442 | $sumScoreResult = Database::query($sql); |
||
4443 | $durationRow = Database::fetch_array($sumScoreResult, 'ASSOC'); |
||
4444 | if (!empty($durationRow['exe_duration'])) { |
||
4445 | $exeDuration = $durationRow['exe_duration']; |
||
4446 | if ($exeDuration != $totalTimeInLpItemView |
||
4447 | && !empty($lpItemViewId) |
||
4448 | && !empty($exeDuration) |
||
4449 | ) { |
||
4450 | // Update c_lp_item_view.total_time |
||
4451 | $sqlUpdate = "UPDATE $lpItemViewTable SET total_time = '$exeDuration' |
||
4452 | WHERE iid = ".$lpItemViewId; |
||
4453 | Database::query($sqlUpdate); |
||
4454 | } |
||
4455 | } |
||
4456 | } |
||
4457 | } |
||
4458 | |||
4459 | // End total_time fix |
||
4460 | |||
4461 | // Calculate total time |
||
4462 | $sql = "SELECT SUM(total_time) |
||
4463 | FROM $lpItemViewTable AS item_view |
||
4464 | INNER JOIN $lpViewTable AS view |
||
4465 | ON ( |
||
4466 | item_view.lp_view_id = view.id AND |
||
4467 | item_view.c_id = view.c_id |
||
4468 | ) |
||
4469 | WHERE |
||
4470 | item_view.c_id = $course_id AND |
||
4471 | view.c_id = $course_id AND |
||
4472 | view.lp_id = $lp_id AND |
||
4473 | view.user_id = $student_id AND |
||
4474 | session_id = $session_id"; |
||
4475 | |||
4476 | $rs = Database::query($sql); |
||
4477 | if (Database::num_rows($rs) > 0) { |
||
4478 | $total_time += Database::result($rs, 0, 0); |
||
4479 | } |
||
4480 | } |
||
4481 | } |
||
4482 | } |
||
4483 | |||
4484 | return $total_time; |
||
4485 | } |
||
4486 | |||
4487 | /** |
||
4488 | * This function gets last connection time to one learning path. |
||
4489 | * |
||
4490 | * @param int|array $student_id Student id(s) |
||
4491 | * @param string $course_code Course code |
||
4492 | * @param int $lp_id Learning path id |
||
4493 | * @param int $session_id |
||
4494 | * |
||
4495 | * @return int last connection timestamp |
||
4496 | */ |
||
4497 | public static function get_last_connection_time_in_lp( |
||
4498 | $student_id, |
||
4499 | $course_code, |
||
4500 | $lp_id, |
||
4501 | $session_id = 0 |
||
4502 | ) { |
||
4503 | $course = api_get_course_info($course_code); |
||
4504 | |||
4505 | if (empty($course)) { |
||
4506 | return 0; |
||
4507 | } |
||
4508 | |||
4509 | $course_id = $course['real_id']; |
||
4510 | $student_id = (int) $student_id; |
||
4511 | $lp_id = (int) $lp_id; |
||
4512 | $session_id = (int) $session_id; |
||
4513 | $lastTime = 0; |
||
4514 | |||
4515 | // Use new system |
||
4516 | if (self::minimumTimeAvailable($session_id, $course_id)) { |
||
4517 | $sql = "SELECT MAX(date_reg) max |
||
4518 | FROM track_e_access_complete |
||
4519 | WHERE |
||
4520 | user_id = $student_id AND |
||
4521 | c_id = $course_id AND |
||
4522 | session_id = $session_id AND |
||
4523 | tool = 'learnpath' AND |
||
4524 | tool_id = $lp_id AND |
||
4525 | action = 'view' AND |
||
4526 | login_as = 0 |
||
4527 | ORDER BY date_reg ASC |
||
4528 | LIMIT 1"; |
||
4529 | $rs = Database::query($sql); |
||
4530 | |||
4531 | $lastConnection = 0; |
||
4532 | if (Database::num_rows($rs) > 0) { |
||
4533 | $value = Database::fetch_array($rs); |
||
4534 | if (isset($value['max']) && !empty($value['max'])) { |
||
4535 | $lastConnection = api_strtotime($value['max'], 'UTC'); |
||
4536 | } |
||
4537 | } |
||
4538 | |||
4539 | if (!empty($lastConnection)) { |
||
4540 | return $lastConnection; |
||
4541 | } |
||
4542 | } |
||
4543 | |||
4544 | if (!empty($course)) { |
||
4545 | $lp_table = Database::get_course_table(TABLE_LP_MAIN); |
||
4546 | $t_lpv = Database::get_course_table(TABLE_LP_VIEW); |
||
4547 | $t_lpiv = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
4548 | |||
4549 | // Check the real number of LPs corresponding to the filter in the |
||
4550 | // database (and if no list was given, get them all) |
||
4551 | $sql = "SELECT id FROM $lp_table |
||
4552 | WHERE c_id = $course_id AND id = $lp_id "; |
||
4553 | $row = Database::query($sql); |
||
4554 | $count = Database::num_rows($row); |
||
4555 | |||
4556 | // calculates last connection time |
||
4557 | if ($count > 0) { |
||
4558 | $sql = 'SELECT MAX(start_time) |
||
4559 | FROM '.$t_lpiv.' AS item_view |
||
4560 | INNER JOIN '.$t_lpv.' AS view |
||
4561 | ON (item_view.lp_view_id = view.id AND item_view.c_id = view.c_id) |
||
4562 | WHERE |
||
4563 | item_view.c_id = '.$course_id.' AND |
||
4564 | view.c_id = '.$course_id.' AND |
||
4565 | view.lp_id = '.$lp_id.' AND |
||
4566 | view.user_id = '.$student_id.' AND |
||
4567 | view.session_id = '.$session_id; |
||
4568 | $rs = Database::query($sql); |
||
4569 | if (Database::num_rows($rs) > 0) { |
||
4570 | $lastTime = Database::result($rs, 0, 0); |
||
4571 | } |
||
4572 | } |
||
4573 | } |
||
4574 | |||
4575 | return $lastTime; |
||
4576 | } |
||
4577 | |||
4578 | /** |
||
4579 | * Gets the last connection time in the last learning path for a student in a course session. |
||
4580 | */ |
||
4581 | public static function getLastConnectionTimeInSessionCourseLp( |
||
4582 | int $studentId, |
||
4583 | string $courseCode, |
||
4584 | int $sessionId = 0 |
||
4585 | ): int { |
||
4586 | $course = api_get_course_info($courseCode); |
||
4587 | |||
4588 | if (empty($course)) { |
||
4589 | return 0; |
||
4590 | } |
||
4591 | |||
4592 | $courseId = $course['real_id']; |
||
4593 | $lastTime = 0; |
||
4594 | |||
4595 | $tLpv = Database::get_course_table(TABLE_LP_VIEW); |
||
4596 | $tLpiv = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
4597 | |||
4598 | $sql = 'SELECT MAX(item_view.start_time) as last_time |
||
4599 | FROM '.$tLpiv.' AS item_view |
||
4600 | INNER JOIN '.$tLpv.' AS view |
||
4601 | ON (item_view.lp_view_id = view.id) |
||
4602 | WHERE |
||
4603 | view.c_id = '.$courseId.' AND |
||
4604 | view.user_id = '.$studentId.' AND |
||
4605 | view.session_id = '.$sessionId; |
||
4606 | |||
4607 | $rs = Database::query($sql); |
||
4608 | if ($rs && Database::num_rows($rs) > 0) { |
||
4609 | $lastTime = (int) Database::result($rs, 0, 'last_time'); |
||
4610 | } |
||
4611 | |||
4612 | return $lastTime; |
||
4613 | } |
||
4614 | |||
4615 | public static function getFirstConnectionTimeInLp( |
||
4616 | $student_id, |
||
4617 | $course_code, |
||
4618 | $lp_id, |
||
4619 | $session_id = 0 |
||
4620 | ) { |
||
4621 | $course = api_get_course_info($course_code); |
||
4622 | $student_id = (int) $student_id; |
||
4623 | $lp_id = (int) $lp_id; |
||
4624 | $session_id = (int) $session_id; |
||
4625 | $time = 0; |
||
4626 | |||
4627 | if (!empty($course)) { |
||
4628 | $course_id = $course['real_id']; |
||
4629 | $lp_table = Database::get_course_table(TABLE_LP_MAIN); |
||
4630 | $t_lpv = Database::get_course_table(TABLE_LP_VIEW); |
||
4631 | $t_lpiv = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
4632 | |||
4633 | // Check the real number of LPs corresponding to the filter in the |
||
4634 | // database (and if no list was given, get them all) |
||
4635 | $sql = "SELECT id FROM $lp_table |
||
4636 | WHERE c_id = $course_id AND id = $lp_id "; |
||
4637 | $row = Database::query($sql); |
||
4638 | $count = Database::num_rows($row); |
||
4639 | |||
4640 | // calculates first connection time |
||
4641 | if ($count > 0) { |
||
4642 | $sql = 'SELECT MIN(start_time) |
||
4643 | FROM '.$t_lpiv.' AS item_view |
||
4644 | INNER JOIN '.$t_lpv.' AS view |
||
4645 | ON (item_view.lp_view_id = view.id AND item_view.c_id = view.c_id) |
||
4646 | WHERE |
||
4647 | status != "not attempted" AND |
||
4648 | item_view.c_id = '.$course_id.' AND |
||
4649 | view.c_id = '.$course_id.' AND |
||
4650 | view.lp_id = '.$lp_id.' AND |
||
4651 | view.user_id = '.$student_id.' AND |
||
4652 | view.session_id = '.$session_id; |
||
4653 | $rs = Database::query($sql); |
||
4654 | if (Database::num_rows($rs) > 0) { |
||
4655 | $time = Database::result($rs, 0, 0); |
||
4656 | } |
||
4657 | } |
||
4658 | } |
||
4659 | |||
4660 | return $time; |
||
4661 | } |
||
4662 | |||
4663 | /** |
||
4664 | * gets the list of students followed by coach. |
||
4665 | * |
||
4666 | * @param int $coach_id Coach id |
||
4667 | * |
||
4668 | * @return array List of students |
||
4669 | */ |
||
4670 | public static function get_student_followed_by_coach($coach_id) |
||
4671 | { |
||
4672 | $coach_id = intval($coach_id); |
||
4673 | $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
4674 | $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE); |
||
4675 | $tbl_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER); |
||
4676 | $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION); |
||
4677 | |||
4678 | $students = []; |
||
4679 | // At first, courses where $coach_id is coach of the course // |
||
4680 | $sql = 'SELECT session_id, c_id |
||
4681 | FROM '.$tbl_session_course_user.' |
||
4682 | WHERE user_id='.$coach_id.' AND status=2'; |
||
4683 | |||
4684 | if (api_is_multiple_url_enabled()) { |
||
4685 | $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION); |
||
4686 | $access_url_id = api_get_current_access_url_id(); |
||
4687 | if (-1 != $access_url_id) { |
||
4688 | $sql = 'SELECT scu.session_id, scu.c_id |
||
4689 | FROM '.$tbl_session_course_user.' scu |
||
4690 | INNER JOIN '.$tbl_session_rel_access_url.' sru |
||
4691 | ON (scu.session_id=sru.session_id) |
||
4692 | WHERE |
||
4693 | scu.user_id='.$coach_id.' AND |
||
4694 | scu.status=2 AND |
||
4695 | sru.access_url_id = '.$access_url_id; |
||
4696 | } |
||
4697 | } |
||
4698 | |||
4699 | $result = Database::query($sql); |
||
4700 | |||
4701 | while ($a_courses = Database::fetch_array($result)) { |
||
4702 | $courseId = $a_courses['c_id']; |
||
4703 | $id_session = $a_courses['session_id']; |
||
4704 | |||
4705 | $sql = "SELECT DISTINCT srcru.user_id |
||
4706 | FROM $tbl_session_course_user AS srcru |
||
4707 | INNER JOIN $tbl_session_user sru |
||
4708 | ON (srcru.user_id = sru.user_id AND srcru.session_id = sru.session_id) |
||
4709 | WHERE |
||
4710 | sru.relation_type <> ".SESSION_RELATION_TYPE_RRHH." AND |
||
4711 | srcru.c_id = '$courseId' AND |
||
4712 | srcru.session_id = '$id_session'"; |
||
4713 | |||
4714 | $rs = Database::query($sql); |
||
4715 | while ($row = Database::fetch_array($rs)) { |
||
4716 | $students[$row['user_id']] = $row['user_id']; |
||
4717 | } |
||
4718 | } |
||
4719 | |||
4720 | // Then, courses where $coach_id is coach of the session |
||
4721 | $sql = 'SELECT session_course_user.user_id |
||
4722 | FROM '.$tbl_session_course_user.' as session_course_user |
||
4723 | INNER JOIN '.$tbl_session_user.' sru |
||
4724 | ON session_course_user.user_id = sru.user_id AND session_course_user.session_id = sru.session_id |
||
4725 | INNER JOIN '.$tbl_session_course.' as session_course |
||
4726 | ON session_course.c_id = session_course_user.c_id |
||
4727 | AND session_course_user.session_id = session_course.session_id |
||
4728 | INNER JOIN '.$tbl_session.' as session |
||
4729 | ON session.id = session_course.session_id |
||
4730 | AND session.id_coach = '.$coach_id; |
||
4731 | if (api_is_multiple_url_enabled()) { |
||
4732 | $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION); |
||
4733 | $access_url_id = api_get_current_access_url_id(); |
||
4734 | if (-1 != $access_url_id) { |
||
4735 | $sql = 'SELECT session_course_user.user_id |
||
4736 | FROM '.$tbl_session_course_user.' as session_course_user |
||
4737 | INNER JOIN '.$tbl_session_user.' sru |
||
4738 | ON session_course_user.user_id = sru.user_id AND |
||
4739 | session_course_user.session_id = sru.session_id |
||
4740 | INNER JOIN '.$tbl_session_course.' as session_course |
||
4741 | ON session_course.c_id = session_course_user.c_id AND |
||
4742 | session_course_user.session_id = session_course.session_id |
||
4743 | INNER JOIN '.$tbl_session.' as session |
||
4744 | ON session.id = session_course.session_id AND |
||
4745 | session.id_coach = '.$coach_id.' |
||
4746 | INNER JOIN '.$tbl_session_rel_access_url.' session_rel_url |
||
4747 | ON session.id = session_rel_url.session_id |
||
4748 | WHERE access_url_id = '.$access_url_id; |
||
4749 | } |
||
4750 | } |
||
4751 | |||
4752 | $result = Database::query($sql); |
||
4753 | while ($row = Database::fetch_array($result)) { |
||
4754 | $students[$row['user_id']] = $row['user_id']; |
||
4755 | } |
||
4756 | |||
4757 | return $students; |
||
4758 | } |
||
4759 | |||
4760 | /** |
||
4761 | * Check if a coach is allowed to follow a student. |
||
4762 | * |
||
4763 | * @param int Coach id |
||
4764 | * @param int Student id |
||
4765 | * |
||
4766 | * @return bool |
||
4767 | */ |
||
4768 | public static function is_allowed_to_coach_student($coach_id, $student_id) |
||
4769 | { |
||
4770 | $coach_id = intval($coach_id); |
||
4771 | $student_id = intval($student_id); |
||
4772 | |||
4773 | $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
4774 | $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE); |
||
4775 | $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION); |
||
4776 | |||
4777 | // At first, courses where $coach_id is coach of the course |
||
4778 | $sql = 'SELECT 1 FROM '.$tbl_session_course_user.' |
||
4779 | WHERE user_id='.$coach_id.' AND status=2'; |
||
4780 | $result = Database::query($sql); |
||
4781 | if (Database::num_rows($result) > 0) { |
||
4782 | return true; |
||
4783 | } |
||
4784 | |||
4785 | // Then, courses where $coach_id is coach of the session |
||
4786 | $sql = 'SELECT session_course_user.user_id |
||
4787 | FROM '.$tbl_session_course_user.' as session_course_user |
||
4788 | INNER JOIN '.$tbl_session_course.' as session_course |
||
4789 | ON session_course.c_id = session_course_user.c_id |
||
4790 | INNER JOIN '.$tbl_session.' as session |
||
4791 | ON session.id = session_course.session_id |
||
4792 | AND session.id_coach = '.$coach_id.' |
||
4793 | WHERE user_id = '.$student_id; |
||
4794 | $result = Database::query($sql); |
||
4795 | if (Database::num_rows($result) > 0) { |
||
4796 | return true; |
||
4797 | } |
||
4798 | |||
4799 | return false; |
||
4800 | } |
||
4801 | |||
4802 | /** |
||
4803 | * Get courses followed by coach. |
||
4804 | * |
||
4805 | * @param int Coach id |
||
4806 | * @param int Session id (optional) |
||
4807 | * |
||
4808 | * @return array Courses list |
||
4809 | */ |
||
4810 | public static function get_courses_followed_by_coach($coach_id, $id_session = 0) |
||
4811 | { |
||
4812 | $coach_id = intval($coach_id); |
||
4813 | if (!empty($id_session)) { |
||
4814 | $id_session = intval($id_session); |
||
4815 | } |
||
4816 | |||
4817 | $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
4818 | $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE); |
||
4819 | $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION); |
||
4820 | $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE); |
||
4821 | $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); |
||
4822 | |||
4823 | // At first, courses where $coach_id is coach of the course. |
||
4824 | $sql = 'SELECT DISTINCT c.code |
||
4825 | FROM '.$tbl_session_course_user.' sc |
||
4826 | INNER JOIN '.$tbl_course.' c |
||
4827 | ON (c.id = sc.c_id) |
||
4828 | WHERE user_id = '.$coach_id.' AND status = 2'; |
||
4829 | |||
4830 | if (api_is_multiple_url_enabled()) { |
||
4831 | $access_url_id = api_get_current_access_url_id(); |
||
4832 | if (-1 != $access_url_id) { |
||
4833 | $sql = 'SELECT DISTINCT c.code |
||
4834 | FROM '.$tbl_session_course_user.' scu |
||
4835 | INNER JOIN '.$tbl_course.' c |
||
4836 | ON (c.code = scu.c_id) |
||
4837 | INNER JOIN '.$tbl_course_rel_access_url.' cru |
||
4838 | ON (c.id = cru.c_id) |
||
4839 | WHERE |
||
4840 | scu.user_id='.$coach_id.' AND |
||
4841 | scu.status=2 AND |
||
4842 | cru.access_url_id = '.$access_url_id; |
||
4843 | } |
||
4844 | } |
||
4845 | |||
4846 | if (!empty($id_session)) { |
||
4847 | $sql .= ' AND session_id='.$id_session; |
||
4848 | } |
||
4849 | |||
4850 | $courseList = []; |
||
4851 | $result = Database::query($sql); |
||
4852 | while ($row = Database::fetch_array($result)) { |
||
4853 | $courseList[$row['code']] = $row['code']; |
||
4854 | } |
||
4855 | |||
4856 | // Then, courses where $coach_id is coach of the session |
||
4857 | $sql = 'SELECT DISTINCT course.code |
||
4858 | FROM '.$tbl_session_course.' as session_course |
||
4859 | INNER JOIN '.$tbl_session.' as session |
||
4860 | ON session.id = session_course.session_id |
||
4861 | AND session.id_coach = '.$coach_id.' |
||
4862 | INNER JOIN '.$tbl_course.' as course |
||
4863 | ON course.id = session_course.c_id'; |
||
4864 | |||
4865 | if (api_is_multiple_url_enabled()) { |
||
4866 | $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); |
||
4867 | $access_url_id = api_get_current_access_url_id(); |
||
4868 | if (-1 != $access_url_id) { |
||
4869 | $sql = 'SELECT DISTINCT c.code |
||
4870 | FROM '.$tbl_session_course.' as session_course |
||
4871 | INNER JOIN '.$tbl_course.' c |
||
4872 | ON (c.id = session_course.c_id) |
||
4873 | INNER JOIN '.$tbl_session.' as session |
||
4874 | ON session.id = session_course.session_id |
||
4875 | AND session.id_coach = '.$coach_id.' |
||
4876 | INNER JOIN '.$tbl_course.' as course |
||
4877 | ON course.id = session_course.c_id |
||
4878 | INNER JOIN '.$tbl_course_rel_access_url.' course_rel_url |
||
4879 | ON (course_rel_url.c_id = c.id)'; |
||
4880 | } |
||
4881 | } |
||
4882 | |||
4883 | if (!empty($id_session)) { |
||
4884 | $sql .= ' WHERE session_course.session_id='.$id_session; |
||
4885 | if (api_is_multiple_url_enabled()) { |
||
4886 | $sql .= ' AND access_url_id = '.$access_url_id; |
||
4887 | } |
||
4888 | } else { |
||
4889 | if (api_is_multiple_url_enabled()) { |
||
4890 | $sql .= ' WHERE access_url_id = '.$access_url_id; |
||
4891 | } |
||
4892 | } |
||
4893 | |||
4894 | $result = Database::query($sql); |
||
4895 | while ($row = Database::fetch_array($result)) { |
||
4896 | $courseList[$row['code']] = $row['code']; |
||
4897 | } |
||
4898 | |||
4899 | return $courseList; |
||
4900 | } |
||
4901 | |||
4902 | /** |
||
4903 | * Get sessions coached by user. |
||
4904 | * |
||
4905 | * @param int $coach_id |
||
4906 | * @param int $start |
||
4907 | * @param int $limit |
||
4908 | * @param bool $getCount |
||
4909 | * @param string $keyword |
||
4910 | * @param string $description |
||
4911 | * @param string $orderByName |
||
4912 | * @param string $orderByDirection |
||
4913 | * @param array $options |
||
4914 | */ |
||
4915 | public static function get_sessions_coached_by_user( |
||
4916 | $coach_id, |
||
4917 | $start = 0, |
||
4918 | $limit = 0, |
||
4919 | $getCount = false, |
||
4920 | $keyword = '', |
||
4921 | $description = '', |
||
4922 | $orderByName = '', |
||
4923 | $orderByDirection = '', |
||
4924 | $options = [] |
||
4925 | ) { |
||
4926 | // table definition |
||
4927 | $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION); |
||
4928 | $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
4929 | $coach_id = (int) $coach_id; |
||
4930 | |||
4931 | $select = ' SELECT * FROM '; |
||
4932 | if ($getCount) { |
||
4933 | $select = ' SELECT count(DISTINCT id) as count FROM '; |
||
4934 | } |
||
4935 | |||
4936 | $limitCondition = null; |
||
4937 | if (!empty($start) && !empty($limit)) { |
||
4938 | $limitCondition = " LIMIT ".intval($start).", ".intval($limit); |
||
4939 | } |
||
4940 | |||
4941 | $keywordCondition = null; |
||
4942 | if (!empty($keyword)) { |
||
4943 | $keyword = Database::escape_string($keyword); |
||
4944 | $keywordCondition = " AND (name LIKE '%$keyword%' ) "; |
||
4945 | |||
4946 | if (!empty($description)) { |
||
4947 | $description = Database::escape_string($description); |
||
4948 | $keywordCondition = " AND (name LIKE '%$keyword%' OR description LIKE '%$description%' ) "; |
||
4949 | } |
||
4950 | } |
||
4951 | |||
4952 | $extraFieldModel = new ExtraFieldModel('session'); |
||
4953 | $conditions = $extraFieldModel->parseConditions($options); |
||
4954 | $sqlInjectJoins = $conditions['inject_joins']; |
||
4955 | $extraFieldsConditions = $conditions['where']; |
||
4956 | $sqlInjectWhere = $conditions['inject_where']; |
||
4957 | $injectExtraFields = $conditions['inject_extra_fields']; |
||
4958 | |||
4959 | $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION); |
||
4960 | $access_url_id = api_get_current_access_url_id(); |
||
4961 | |||
4962 | $orderBy = ''; |
||
4963 | if (!empty($orderByName)) { |
||
4964 | if (in_array($orderByName, ['name', 'access_start_date'])) { |
||
4965 | $orderByDirection = in_array(strtolower($orderByDirection), ['asc', 'desc']) ? $orderByDirection : 'asc'; |
||
4966 | $orderByName = Database::escape_string($orderByName); |
||
4967 | $orderBy .= " ORDER BY `$orderByName` $orderByDirection"; |
||
4968 | } |
||
4969 | } |
||
4970 | |||
4971 | $sql = " |
||
4972 | $select |
||
4973 | ( |
||
4974 | SELECT DISTINCT |
||
4975 | s.id, |
||
4976 | name, |
||
4977 | $injectExtraFields |
||
4978 | access_start_date, |
||
4979 | access_end_date |
||
4980 | FROM $tbl_session s |
||
4981 | INNER JOIN $tbl_session_rel_access_url session_rel_url |
||
4982 | ON (s.id = session_rel_url.session_id) |
||
4983 | $sqlInjectJoins |
||
4984 | WHERE |
||
4985 | id_coach = $coach_id AND |
||
4986 | access_url_id = $access_url_id |
||
4987 | $keywordCondition |
||
4988 | $extraFieldsConditions |
||
4989 | $sqlInjectWhere |
||
4990 | UNION |
||
4991 | SELECT DISTINCT |
||
4992 | s.id, |
||
4993 | s.name, |
||
4994 | $injectExtraFields |
||
4995 | s.access_start_date, |
||
4996 | s.access_end_date |
||
4997 | FROM $tbl_session as s |
||
4998 | INNER JOIN $tbl_session_course_user as session_course_user |
||
4999 | ON |
||
5000 | s.id = session_course_user.session_id AND |
||
5001 | session_course_user.user_id = $coach_id AND |
||
5002 | session_course_user.status = 2 |
||
5003 | INNER JOIN $tbl_session_rel_access_url session_rel_url |
||
5004 | ON (s.id = session_rel_url.session_id) |
||
5005 | $sqlInjectJoins |
||
5006 | WHERE |
||
5007 | access_url_id = $access_url_id |
||
5008 | $keywordCondition |
||
5009 | $extraFieldsConditions |
||
5010 | $sqlInjectWhere |
||
5011 | ) as sessions $limitCondition $orderBy |
||
5012 | "; |
||
5013 | |||
5014 | $rs = Database::query($sql); |
||
5015 | if ($getCount) { |
||
5016 | $row = Database::fetch_array($rs); |
||
5017 | |||
5018 | return $row['count']; |
||
5019 | } |
||
5020 | |||
5021 | $sessions = []; |
||
5022 | while ($row = Database::fetch_array($rs)) { |
||
5023 | if ($row['access_start_date'] === '0000-00-00 00:00:00') { |
||
5024 | $row['access_start_date'] = null; |
||
5025 | } |
||
5026 | |||
5027 | $sessions[$row['id']] = $row; |
||
5028 | } |
||
5029 | |||
5030 | if (!empty($sessions)) { |
||
5031 | foreach ($sessions as &$session) { |
||
5032 | if (empty($session['access_start_date'])) { |
||
5033 | $session['status'] = get_lang('SessionActive'); |
||
5034 | } else { |
||
5035 | $time_start = api_strtotime($session['access_start_date'], 'UTC'); |
||
5036 | $time_end = api_strtotime($session['access_end_date'], 'UTC'); |
||
5037 | if ($time_start < time() && time() < $time_end) { |
||
5038 | $session['status'] = get_lang('SessionActive'); |
||
5039 | } else { |
||
5040 | if (time() < $time_start) { |
||
5041 | $session['status'] = get_lang('SessionFuture'); |
||
5042 | } else { |
||
5043 | if (time() > $time_end) { |
||
5044 | $session['status'] = get_lang('SessionPast'); |
||
5045 | } |
||
5046 | } |
||
5047 | } |
||
5048 | } |
||
5049 | } |
||
5050 | } |
||
5051 | |||
5052 | return $sessions; |
||
5053 | } |
||
5054 | |||
5055 | /** |
||
5056 | * Get courses list from a session. |
||
5057 | * |
||
5058 | * @param int Session id |
||
5059 | * |
||
5060 | * @return array Courses list |
||
5061 | */ |
||
5062 | public static function get_courses_list_from_session($session_id) |
||
5063 | { |
||
5064 | $session_id = (int) $session_id; |
||
5065 | |||
5066 | // table definition |
||
5067 | $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE); |
||
5068 | $courseTable = Database::get_main_table(TABLE_MAIN_COURSE); |
||
5069 | |||
5070 | $sql = "SELECT DISTINCT code, c_id |
||
5071 | FROM $tbl_session_course sc |
||
5072 | INNER JOIN $courseTable c |
||
5073 | ON sc.c_id = c.id |
||
5074 | WHERE session_id= $session_id"; |
||
5075 | |||
5076 | $result = Database::query($sql); |
||
5077 | |||
5078 | $courses = []; |
||
5079 | while ($row = Database::fetch_array($result)) { |
||
5080 | $courses[$row['code']] = $row; |
||
5081 | } |
||
5082 | |||
5083 | return $courses; |
||
5084 | } |
||
5085 | |||
5086 | /** |
||
5087 | * Count the number of documents that an user has uploaded to a course. |
||
5088 | * |
||
5089 | * @param int|array Student id(s) |
||
5090 | * @param string Course code |
||
5091 | * @param int Session id (optional), |
||
5092 | * if param $session_id is null(default) |
||
5093 | * return count of assignments including sessions, 0 = session is not filtered |
||
5094 | * |
||
5095 | * @return int Number of documents |
||
5096 | */ |
||
5097 | public static function count_student_uploaded_documents( |
||
5098 | $student_id, |
||
5099 | $course_code, |
||
5100 | $session_id = null |
||
5101 | ) { |
||
5102 | // get the information of the course |
||
5103 | $a_course = api_get_course_info($course_code); |
||
5104 | if (!empty($a_course)) { |
||
5105 | // table definition |
||
5106 | $tbl_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY); |
||
5107 | $tbl_document = Database::get_course_table(TABLE_DOCUMENT); |
||
5108 | $course_id = $a_course['real_id']; |
||
5109 | if (is_array($student_id)) { |
||
5110 | $studentList = array_map('intval', $student_id); |
||
5111 | $condition_user = " AND ip.insert_user_id IN ('".implode(',', $studentList)."') "; |
||
5112 | } else { |
||
5113 | $student_id = (int) $student_id; |
||
5114 | $condition_user = " AND ip.insert_user_id = '$student_id' "; |
||
5115 | } |
||
5116 | |||
5117 | $condition_session = null; |
||
5118 | if (isset($session_id)) { |
||
5119 | $session_id = (int) $session_id; |
||
5120 | $condition_session = " AND pub.session_id = $session_id "; |
||
5121 | } |
||
5122 | |||
5123 | $sql = "SELECT count(ip.tool) AS count |
||
5124 | FROM $tbl_item_property ip |
||
5125 | INNER JOIN $tbl_document pub |
||
5126 | ON (ip.ref = pub.iid AND ip.c_id = pub.c_id) |
||
5127 | WHERE |
||
5128 | ip.c_id = $course_id AND |
||
5129 | pub.c_id = $course_id AND |
||
5130 | pub.filetype ='file' AND |
||
5131 | ip.tool = 'document' |
||
5132 | $condition_user $condition_session "; |
||
5133 | $rs = Database::query($sql); |
||
5134 | $row = Database::fetch_array($rs, 'ASSOC'); |
||
5135 | |||
5136 | return $row['count']; |
||
5137 | } |
||
5138 | |||
5139 | return null; |
||
5140 | } |
||
5141 | |||
5142 | /** |
||
5143 | * Count assignments per student. |
||
5144 | * |
||
5145 | * @param array|int $student_id |
||
5146 | * @param string $course_code |
||
5147 | * @param int $session_id if param is null(default) return count of assignments including sessions, |
||
5148 | * 0 = session is not filtered |
||
5149 | * |
||
5150 | * @return int Count of assignments |
||
5151 | */ |
||
5152 | public static function count_student_assignments( |
||
5153 | $student_id, |
||
5154 | $course_code = null, |
||
5155 | $session_id = null |
||
5156 | ) { |
||
5157 | if (empty($student_id)) { |
||
5158 | return 0; |
||
5159 | } |
||
5160 | |||
5161 | $conditions = []; |
||
5162 | |||
5163 | // Get the information of the course |
||
5164 | $a_course = api_get_course_info($course_code); |
||
5165 | if (!empty($a_course)) { |
||
5166 | $course_id = $a_course['real_id']; |
||
5167 | $conditions[] = " ip.c_id = $course_id AND pub.c_id = $course_id "; |
||
5168 | } |
||
5169 | |||
5170 | // table definition |
||
5171 | $tbl_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY); |
||
5172 | $tbl_student_publication = Database::get_course_table(TABLE_STUDENT_PUBLICATION); |
||
5173 | |||
5174 | if (is_array($student_id)) { |
||
5175 | $studentList = array_map('intval', $student_id); |
||
5176 | $conditions[] = " ip.insert_user_id IN ('".implode("','", $studentList)."') "; |
||
5177 | } else { |
||
5178 | $student_id = (int) $student_id; |
||
5179 | $conditions[] = " ip.insert_user_id = '$student_id' "; |
||
5180 | } |
||
5181 | |||
5182 | $conditions[] = ' pub.active <> 2 '; |
||
5183 | $conditionToString = implode(' AND ', $conditions); |
||
5184 | $sessionCondition = api_get_session_condition($session_id, true, false, 'pub.session_id'); |
||
5185 | $conditionToString .= $sessionCondition; |
||
5186 | |||
5187 | $sql = "SELECT count(ip.tool) as count |
||
5188 | FROM $tbl_item_property ip |
||
5189 | INNER JOIN $tbl_student_publication pub |
||
5190 | ON (ip.ref = pub.iid AND ip.c_id = pub.c_id) |
||
5191 | WHERE |
||
5192 | ip.tool='work' AND |
||
5193 | $conditionToString"; |
||
5194 | $rs = Database::query($sql); |
||
5195 | $row = Database::fetch_array($rs, 'ASSOC'); |
||
5196 | |||
5197 | return $row['count']; |
||
5198 | } |
||
5199 | |||
5200 | /** |
||
5201 | * Count messages per student inside forum tool. |
||
5202 | * |
||
5203 | * @param int|array Student id |
||
5204 | * @param string Course code |
||
5205 | * @param int Session id if null(default) return count of messages including sessions, 0 = session is not |
||
5206 | * filtered |
||
5207 | * |
||
5208 | * @return int Count of messages |
||
5209 | */ |
||
5210 | public static function count_student_messages($student_id, $courseCode = null, $session_id = null) |
||
5211 | { |
||
5212 | if (empty($student_id)) { |
||
5213 | return 0; |
||
5214 | } |
||
5215 | |||
5216 | // Table definition. |
||
5217 | $tbl_forum_post = Database::get_course_table(TABLE_FORUM_POST); |
||
5218 | $tbl_forum = Database::get_course_table(TABLE_FORUM); |
||
5219 | |||
5220 | $conditions = []; |
||
5221 | if (is_array($student_id)) { |
||
5222 | $studentList = array_map('intval', $student_id); |
||
5223 | $conditions[] = " post.poster_id IN ('".implode("','", $studentList)."') "; |
||
5224 | } else { |
||
5225 | $student_id = (int) $student_id; |
||
5226 | $conditions[] = " post.poster_id = '$student_id' "; |
||
5227 | } |
||
5228 | |||
5229 | $conditionsToString = implode('AND ', $conditions); |
||
5230 | |||
5231 | if (empty($courseCode)) { |
||
5232 | $sql = "SELECT count(poster_id) as count |
||
5233 | FROM $tbl_forum_post post |
||
5234 | INNER JOIN $tbl_forum forum |
||
5235 | ON (forum.forum_id = post.forum_id AND forum.c_id = post.c_id) |
||
5236 | WHERE $conditionsToString"; |
||
5237 | |||
5238 | $rs = Database::query($sql); |
||
5239 | $row = Database::fetch_array($rs, 'ASSOC'); |
||
5240 | |||
5241 | return $row['count']; |
||
5242 | } |
||
5243 | |||
5244 | require_once api_get_path(SYS_CODE_PATH).'forum/forumfunction.inc.php'; |
||
5245 | |||
5246 | $courseInfo = api_get_course_info($courseCode); |
||
5247 | |||
5248 | $forums = []; |
||
5249 | if (!empty($courseInfo)) { |
||
5250 | $forums = get_forums('', $courseCode, true, $session_id); |
||
5251 | $course_id = $courseInfo['real_id']; |
||
5252 | $conditions[] = " post.c_id = $course_id "; |
||
5253 | } |
||
5254 | |||
5255 | if (!empty($forums)) { |
||
5256 | $idList = array_column($forums, 'forum_id'); |
||
5257 | $idListToString = implode("', '", $idList); |
||
5258 | $conditions[] = " post.forum_id IN ('$idListToString')"; |
||
5259 | } |
||
5260 | |||
5261 | $conditionsToString = implode('AND ', $conditions); |
||
5262 | $sql = "SELECT count(poster_id) as count |
||
5263 | FROM $tbl_forum_post post |
||
5264 | WHERE $conditionsToString"; |
||
5265 | |||
5266 | $rs = Database::query($sql); |
||
5267 | $row = Database::fetch_array($rs, 'ASSOC'); |
||
5268 | $count = $row['count']; |
||
5269 | |||
5270 | return $count; |
||
5271 | } |
||
5272 | |||
5273 | /** |
||
5274 | * This function counts the number of post by course. |
||
5275 | * |
||
5276 | * @param string $course_code |
||
5277 | * @param int $session_id (optional), if is null(default) it'll return results including sessions, |
||
5278 | * 0 = session is not filtered |
||
5279 | * @param int $groupId |
||
5280 | * |
||
5281 | * @return int The number of post by course |
||
5282 | */ |
||
5283 | public static function count_number_of_posts_by_course($course_code, $session_id = null, $groupId = 0) |
||
5284 | { |
||
5285 | $courseInfo = api_get_course_info($course_code); |
||
5286 | if (!empty($courseInfo)) { |
||
5287 | $tbl_posts = Database::get_course_table(TABLE_FORUM_POST); |
||
5288 | $tbl_forums = Database::get_course_table(TABLE_FORUM); |
||
5289 | |||
5290 | $condition_session = ''; |
||
5291 | if (isset($session_id)) { |
||
5292 | $session_id = (int) $session_id; |
||
5293 | $condition_session = api_get_session_condition( |
||
5294 | $session_id, |
||
5295 | true, |
||
5296 | false, |
||
5297 | 'f.session_id' |
||
5298 | ); |
||
5299 | } |
||
5300 | |||
5301 | $course_id = $courseInfo['real_id']; |
||
5302 | $groupId = (int) $groupId; |
||
5303 | if (!empty($groupId)) { |
||
5304 | $groupCondition = " i.to_group_id = $groupId "; |
||
5305 | } else { |
||
5306 | $groupCondition = ' (i.to_group_id = 0 OR i.to_group_id IS NULL) '; |
||
5307 | } |
||
5308 | |||
5309 | $item = Database::get_course_table(TABLE_ITEM_PROPERTY); |
||
5310 | $sql = "SELECT count(*) FROM $tbl_posts p |
||
5311 | INNER JOIN $tbl_forums f |
||
5312 | ON f.forum_id = p.forum_id AND p.c_id = f.c_id |
||
5313 | INNER JOIN $item i |
||
5314 | ON (tool = '".TOOL_FORUM."' AND f.c_id = i.c_id AND f.iid = i.ref) |
||
5315 | WHERE |
||
5316 | p.c_id = $course_id AND |
||
5317 | f.c_id = $course_id AND |
||
5318 | $groupCondition |
||
5319 | $condition_session |
||
5320 | "; |
||
5321 | $result = Database::query($sql); |
||
5322 | $row = Database::fetch_row($result); |
||
5323 | $count = $row[0]; |
||
5324 | |||
5325 | return $count; |
||
5326 | } |
||
5327 | |||
5328 | return 0; |
||
5329 | } |
||
5330 | |||
5331 | /** |
||
5332 | * This function counts the number of threads by course. |
||
5333 | * |
||
5334 | * @param string Course code |
||
5335 | * @param int Session id (optional), |
||
5336 | * if param $session_id is null(default) it'll return results including |
||
5337 | * sessions, 0 = session is not filtered |
||
5338 | * @param int $groupId |
||
5339 | * |
||
5340 | * @return int The number of threads by course |
||
5341 | */ |
||
5342 | public static function count_number_of_threads_by_course( |
||
5343 | $course_code, |
||
5344 | $session_id = null, |
||
5345 | $groupId = 0 |
||
5346 | ) { |
||
5347 | $course_info = api_get_course_info($course_code); |
||
5348 | if (empty($course_info)) { |
||
5349 | return null; |
||
5350 | } |
||
5351 | |||
5352 | $course_id = $course_info['real_id']; |
||
5353 | $tbl_threads = Database::get_course_table(TABLE_FORUM_THREAD); |
||
5354 | $tbl_forums = Database::get_course_table(TABLE_FORUM); |
||
5355 | |||
5356 | $condition_session = ''; |
||
5357 | if (isset($session_id)) { |
||
5358 | $session_id = (int) $session_id; |
||
5359 | $condition_session = ' AND f.session_id = '.$session_id; |
||
5360 | } |
||
5361 | |||
5362 | $groupId = (int) $groupId; |
||
5363 | |||
5364 | if (!empty($groupId)) { |
||
5365 | $groupCondition = " i.to_group_id = $groupId "; |
||
5366 | } else { |
||
5367 | $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) "; |
||
5368 | } |
||
5369 | |||
5370 | $item = Database::get_course_table(TABLE_ITEM_PROPERTY); |
||
5371 | $sql = "SELECT count(*) |
||
5372 | FROM $tbl_threads t |
||
5373 | INNER JOIN $tbl_forums f |
||
5374 | ON f.iid = t.forum_id AND f.c_id = t.c_id |
||
5375 | INNER JOIN $item i |
||
5376 | ON ( |
||
5377 | tool = '".TOOL_FORUM_THREAD."' AND |
||
5378 | f.c_id = i.c_id AND |
||
5379 | t.iid = i.ref |
||
5380 | ) |
||
5381 | WHERE |
||
5382 | t.c_id = $course_id AND |
||
5383 | f.c_id = $course_id AND |
||
5384 | $groupCondition |
||
5385 | $condition_session |
||
5386 | "; |
||
5387 | |||
5388 | $result = Database::query($sql); |
||
5389 | if (Database::num_rows($result)) { |
||
5390 | $row = Database::fetch_row($result); |
||
5391 | $count = $row[0]; |
||
5392 | |||
5393 | return $count; |
||
5394 | } |
||
5395 | |||
5396 | return 0; |
||
5397 | } |
||
5398 | |||
5399 | /** |
||
5400 | * This function counts the number of forums by course. |
||
5401 | * |
||
5402 | * @param string Course code |
||
5403 | * @param int Session id (optional), |
||
5404 | * if param $session_id is null(default) it'll return results |
||
5405 | * including sessions, 0 = session is not filtered |
||
5406 | * @param int $groupId |
||
5407 | * |
||
5408 | * @return int The number of forums by course |
||
5409 | */ |
||
5410 | public static function count_number_of_forums_by_course( |
||
5411 | $course_code, |
||
5412 | $session_id = null, |
||
5413 | $groupId = 0 |
||
5414 | ) { |
||
5415 | $course_info = api_get_course_info($course_code); |
||
5416 | if (empty($course_info)) { |
||
5417 | return null; |
||
5418 | } |
||
5419 | $course_id = $course_info['real_id']; |
||
5420 | |||
5421 | $condition_session = ''; |
||
5422 | if (isset($session_id)) { |
||
5423 | $session_id = (int) $session_id; |
||
5424 | $condition_session = ' AND f.session_id = '.$session_id; |
||
5425 | } |
||
5426 | |||
5427 | $groupId = (int) $groupId; |
||
5428 | if (!empty($groupId)) { |
||
5429 | $groupCondition = " i.to_group_id = $groupId "; |
||
5430 | } else { |
||
5431 | $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) "; |
||
5432 | } |
||
5433 | |||
5434 | $tbl_forums = Database::get_course_table(TABLE_FORUM); |
||
5435 | $item = Database::get_course_table(TABLE_ITEM_PROPERTY); |
||
5436 | |||
5437 | $sql = "SELECT count(*) |
||
5438 | FROM $tbl_forums f |
||
5439 | INNER JOIN $item i |
||
5440 | ON f.c_id = i.c_id AND f.iid = i.ref AND tool = '".TOOL_FORUM."' |
||
5441 | WHERE |
||
5442 | f.c_id = $course_id AND |
||
5443 | $groupCondition |
||
5444 | $condition_session |
||
5445 | "; |
||
5446 | $result = Database::query($sql); |
||
5447 | if (Database::num_rows($result)) { |
||
5448 | $row = Database::fetch_row($result); |
||
5449 | $count = $row[0]; |
||
5450 | |||
5451 | return $count; |
||
5452 | } |
||
5453 | |||
5454 | return 0; |
||
5455 | } |
||
5456 | |||
5457 | /** |
||
5458 | * This function counts the chat last connections by course in x days. |
||
5459 | * |
||
5460 | * @param string Course code |
||
5461 | * @param int Last x days |
||
5462 | * @param int Session id (optional) |
||
5463 | * |
||
5464 | * @return int Chat last connections by course in x days |
||
5465 | */ |
||
5466 | public static function chat_connections_during_last_x_days_by_course( |
||
5467 | $course_code, |
||
5468 | $last_days, |
||
5469 | $session_id = 0 |
||
5470 | ) { |
||
5471 | $course_info = api_get_course_info($course_code); |
||
5472 | if (empty($course_info)) { |
||
5473 | return null; |
||
5474 | } |
||
5475 | $course_id = $course_info['real_id']; |
||
5476 | |||
5477 | // Protect data |
||
5478 | $last_days = (int) $last_days; |
||
5479 | $session_id = (int) $session_id; |
||
5480 | |||
5481 | $tbl_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS); |
||
5482 | $now = api_get_utc_datetime(); |
||
5483 | |||
5484 | $sql = "SELECT count(*) FROM $tbl_stats_access |
||
5485 | WHERE |
||
5486 | DATE_SUB('$now',INTERVAL $last_days DAY) <= access_date AND |
||
5487 | c_id = '$course_id' AND |
||
5488 | access_tool='".TOOL_CHAT."' AND |
||
5489 | access_session_id = '$session_id' "; |
||
5490 | $result = Database::query($sql); |
||
5491 | if (Database::num_rows($result)) { |
||
5492 | $row = Database::fetch_row($result); |
||
5493 | $count = $row[0]; |
||
5494 | |||
5495 | return $count; |
||
5496 | } |
||
5497 | |||
5498 | return 0; |
||
5499 | } |
||
5500 | |||
5501 | /** |
||
5502 | * This function gets the last student's connection in chat. |
||
5503 | * |
||
5504 | * @param int Student id |
||
5505 | * @param string Course code |
||
5506 | * @param int Session id (optional) |
||
5507 | * |
||
5508 | * @return string datetime formatted without day (e.g: February 23, 2010 10:20:50 ) |
||
5509 | */ |
||
5510 | public static function chat_last_connection( |
||
5511 | $student_id, |
||
5512 | $courseId, |
||
5513 | $session_id = 0 |
||
5514 | ) { |
||
5515 | $student_id = (int) $student_id; |
||
5516 | $courseId = (int) $courseId; |
||
5517 | $session_id = (int) $session_id; |
||
5518 | $date_time = ''; |
||
5519 | |||
5520 | // table definition |
||
5521 | $tbl_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS); |
||
5522 | $sql = "SELECT access_date |
||
5523 | FROM $tbl_stats_access |
||
5524 | WHERE |
||
5525 | access_tool='".TOOL_CHAT."' AND |
||
5526 | access_user_id='$student_id' AND |
||
5527 | c_id = $courseId AND |
||
5528 | access_session_id = '$session_id' |
||
5529 | ORDER BY access_date DESC limit 1"; |
||
5530 | $rs = Database::query($sql); |
||
5531 | if (Database::num_rows($rs) > 0) { |
||
5532 | $row = Database::fetch_array($rs); |
||
5533 | $date_time = api_convert_and_format_date( |
||
5534 | $row['access_date'], |
||
5535 | null, |
||
5536 | date_default_timezone_get() |
||
5537 | ); |
||
5538 | } |
||
5539 | |||
5540 | return $date_time; |
||
5541 | } |
||
5542 | |||
5543 | /** |
||
5544 | * Get count student's visited links. |
||
5545 | * |
||
5546 | * @param int $student_id Student id |
||
5547 | * @param int $courseId |
||
5548 | * @param int $session_id Session id (optional) |
||
5549 | * |
||
5550 | * @return int count of visited links |
||
5551 | */ |
||
5552 | public static function count_student_visited_links($student_id, $courseId, $session_id = 0) |
||
5553 | { |
||
5554 | $student_id = (int) $student_id; |
||
5555 | $courseId = (int) $courseId; |
||
5556 | $session_id = (int) $session_id; |
||
5557 | |||
5558 | // table definition |
||
5559 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS); |
||
5560 | |||
5561 | $sql = 'SELECT 1 |
||
5562 | FROM '.$table.' |
||
5563 | WHERE |
||
5564 | links_user_id= '.$student_id.' AND |
||
5565 | c_id = "'.$courseId.'" AND |
||
5566 | links_session_id = '.$session_id.' '; |
||
5567 | |||
5568 | $rs = Database::query($sql); |
||
5569 | |||
5570 | return Database::num_rows($rs); |
||
5571 | } |
||
5572 | |||
5573 | /** |
||
5574 | * Get count student downloaded documents. |
||
5575 | * |
||
5576 | * @param int Student id |
||
5577 | * @param int $courseId |
||
5578 | * @param int Session id (optional) |
||
5579 | * |
||
5580 | * @return int Count downloaded documents |
||
5581 | */ |
||
5582 | public static function count_student_downloaded_documents($student_id, $courseId, $session_id = 0) |
||
5583 | { |
||
5584 | $student_id = (int) $student_id; |
||
5585 | $courseId = (int) $courseId; |
||
5586 | $session_id = (int) $session_id; |
||
5587 | |||
5588 | // table definition |
||
5589 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS); |
||
5590 | |||
5591 | $sql = 'SELECT 1 |
||
5592 | FROM '.$table.' |
||
5593 | WHERE down_user_id = '.$student_id.' |
||
5594 | AND c_id = "'.$courseId.'" |
||
5595 | AND down_session_id = '.$session_id.' '; |
||
5596 | $rs = Database::query($sql); |
||
5597 | |||
5598 | return Database::num_rows($rs); |
||
5599 | } |
||
5600 | |||
5601 | /** |
||
5602 | * Get course list inside a session from a student. |
||
5603 | * |
||
5604 | * @param int $user_id Student id |
||
5605 | * @param int $id_session Session id (optional) |
||
5606 | * |
||
5607 | * @return array Courses list |
||
5608 | */ |
||
5609 | public static function get_course_list_in_session_from_student($user_id, $id_session = 0) |
||
5610 | { |
||
5611 | $user_id = intval($user_id); |
||
5612 | $id_session = intval($id_session); |
||
5613 | $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
5614 | $courseTable = Database::get_main_table(TABLE_MAIN_COURSE); |
||
5615 | |||
5616 | $sql = "SELECT c.code |
||
5617 | FROM $tbl_session_course_user sc |
||
5618 | INNER JOIN $courseTable c |
||
5619 | WHERE |
||
5620 | user_id= $user_id AND |
||
5621 | session_id = $id_session"; |
||
5622 | $result = Database::query($sql); |
||
5623 | $courses = []; |
||
5624 | while ($row = Database::fetch_array($result)) { |
||
5625 | $courses[$row['code']] = $row['code']; |
||
5626 | } |
||
5627 | |||
5628 | return $courses; |
||
5629 | } |
||
5630 | |||
5631 | /** |
||
5632 | * Get inactive students in course. |
||
5633 | * |
||
5634 | * @param int $courseId |
||
5635 | * @param string|int $since Since login course date (optional, default = 'never') |
||
5636 | * @param int $session_id (optional) |
||
5637 | * |
||
5638 | * @return array Inactive users |
||
5639 | */ |
||
5640 | public static function getInactiveStudentsInCourse( |
||
5641 | $courseId, |
||
5642 | $since = 'never', |
||
5643 | $session_id = 0, |
||
5644 | $userActive = null |
||
5645 | ) { |
||
5646 | $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
5647 | $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
5648 | $table_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER); |
||
5649 | $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE); |
||
5650 | $now = api_get_utc_datetime(); |
||
5651 | $courseId = (int) $courseId; |
||
5652 | $session_id = (int) $session_id; |
||
5653 | |||
5654 | if (empty($courseId)) { |
||
5655 | return false; |
||
5656 | } |
||
5657 | |||
5658 | if ($since === 'never') { |
||
5659 | if (empty($session_id)) { |
||
5660 | $sql = 'SELECT course_user.user_id |
||
5661 | FROM '.$table_course_rel_user.' course_user |
||
5662 | LEFT JOIN '.$tbl_track_login.' stats_login |
||
5663 | ON course_user.user_id = stats_login.user_id AND |
||
5664 | relation_type<>'.COURSE_RELATION_TYPE_RRHH.' |
||
5665 | INNER JOIN '.$tableCourse.' c |
||
5666 | ON (c.id = course_user.c_id) |
||
5667 | WHERE |
||
5668 | course_user.c_id = '.$courseId.' AND |
||
5669 | stats_login.login_course_date IS NULL |
||
5670 | GROUP BY course_user.user_id'; |
||
5671 | } else { |
||
5672 | $sql = 'SELECT session_course_user.user_id |
||
5673 | FROM '.$tbl_session_course_user.' session_course_user |
||
5674 | LEFT JOIN '.$tbl_track_login.' stats_login |
||
5675 | ON session_course_user.user_id = stats_login.user_id |
||
5676 | INNER JOIN '.$tableCourse.' c |
||
5677 | ON (c.id = session_course_user.c_id) |
||
5678 | WHERE |
||
5679 | session_course_user.c_id = '.$courseId.' AND |
||
5680 | stats_login.login_course_date IS NULL |
||
5681 | GROUP BY session_course_user.user_id'; |
||
5682 | } |
||
5683 | } else { |
||
5684 | $since = (int) $since; |
||
5685 | if (empty($session_id)) { |
||
5686 | $inner = 'INNER JOIN '.$table_course_rel_user.' course_user |
||
5687 | ON course_user.user_id = stats_login.user_id AND course_user.c_id = c.id '; |
||
5688 | } else { |
||
5689 | $inner = 'INNER JOIN '.$tbl_session_course_user.' session_course_user |
||
5690 | ON |
||
5691 | c.id = session_course_user.c_id AND |
||
5692 | session_course_user.session_id = '.$session_id.' AND |
||
5693 | session_course_user.user_id = stats_login.user_id '; |
||
5694 | } |
||
5695 | |||
5696 | $sql = 'SELECT |
||
5697 | stats_login.user_id, |
||
5698 | MAX(login_course_date) max_date |
||
5699 | FROM '.$tbl_track_login.' stats_login |
||
5700 | INNER JOIN '.$tableCourse.' c |
||
5701 | ON (c.id = stats_login.c_id) |
||
5702 | '.$inner.' |
||
5703 | WHERE c.id = '.$courseId.' |
||
5704 | GROUP BY stats_login.user_id |
||
5705 | HAVING DATE_SUB("'.$now.'", INTERVAL '.$since.' DAY) > max_date '; |
||
5706 | } |
||
5707 | |||
5708 | $rs = Database::query($sql); |
||
5709 | |||
5710 | $allow = api_get_plugin_setting('pausetraining', 'tool_enable') === 'true'; |
||
5711 | $allowPauseFormation = api_get_plugin_setting('pausetraining', 'allow_users_to_edit_pause_formation') === 'true'; |
||
5712 | |||
5713 | $extraFieldValue = new ExtraFieldValue('user'); |
||
5714 | $users = []; |
||
5715 | while ($user = Database::fetch_array($rs)) { |
||
5716 | $userId = $user['user_id']; |
||
5717 | if (isset($userActive)) { |
||
5718 | $userActive = (int) $userActive; |
||
5719 | $uInfo = api_get_user_info($userId); |
||
5720 | if ((int) $uInfo['active'] !== $userActive) { |
||
5721 | continue; |
||
5722 | } |
||
5723 | } |
||
5724 | if ($allow && $allowPauseFormation) { |
||
5725 | $pause = $extraFieldValue->get_values_by_handler_and_field_variable($userId, 'pause_formation'); |
||
5726 | if (!empty($pause) && isset($pause['value']) && 1 == $pause['value']) { |
||
5727 | // Skip user because he paused his formation. |
||
5728 | continue; |
||
5729 | } |
||
5730 | } |
||
5731 | |||
5732 | $users[] = $userId; |
||
5733 | } |
||
5734 | |||
5735 | return $users; |
||
5736 | } |
||
5737 | |||
5738 | /** |
||
5739 | * get count clicks about tools most used by course. |
||
5740 | * |
||
5741 | * @param int $courseId |
||
5742 | * @param int Session id (optional), |
||
5743 | * if param $session_id is null(default) it'll return results |
||
5744 | * including sessions, 0 = session is not filtered |
||
5745 | * |
||
5746 | * @return array tools data |
||
5747 | */ |
||
5748 | public static function get_tools_most_used_by_course($courseId, $session_id = null) |
||
5749 | { |
||
5750 | $courseId = (int) $courseId; |
||
5751 | $data = []; |
||
5752 | $TABLETRACK_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS); |
||
5753 | $condition_session = ''; |
||
5754 | if (isset($session_id)) { |
||
5755 | $session_id = (int) $session_id; |
||
5756 | $condition_session = ' AND access_session_id = '.$session_id; |
||
5757 | } |
||
5758 | $sql = "SELECT |
||
5759 | access_tool, |
||
5760 | COUNT(DISTINCT access_user_id), |
||
5761 | count(access_tool) as count_access_tool |
||
5762 | FROM $TABLETRACK_ACCESS |
||
5763 | WHERE |
||
5764 | access_tool IS NOT NULL AND |
||
5765 | access_tool != '' AND |
||
5766 | c_id = '$courseId' |
||
5767 | $condition_session |
||
5768 | GROUP BY access_tool |
||
5769 | ORDER BY count_access_tool DESC |
||
5770 | LIMIT 0, 3"; |
||
5771 | $rs = Database::query($sql); |
||
5772 | if (Database::num_rows($rs) > 0) { |
||
5773 | while ($row = Database::fetch_array($rs)) { |
||
5774 | $data[] = $row; |
||
5775 | } |
||
5776 | } |
||
5777 | |||
5778 | return $data; |
||
5779 | } |
||
5780 | |||
5781 | /** |
||
5782 | * get documents most downloaded by course. |
||
5783 | * |
||
5784 | * @param string Course code |
||
5785 | * @param int Session id (optional), |
||
5786 | * if param $session_id is null(default) it'll return results including |
||
5787 | * sessions, 0 = session is not filtered |
||
5788 | * @param int Limit (optional, default = 0, 0 = without limit) |
||
5789 | * |
||
5790 | * @return array documents downloaded |
||
5791 | */ |
||
5792 | public static function get_documents_most_downloaded_by_course( |
||
5793 | $course_code, |
||
5794 | $session_id = 0, |
||
5795 | $limit = 0 |
||
5796 | ) { |
||
5797 | $courseId = api_get_course_int_id($course_code); |
||
5798 | $data = []; |
||
5799 | |||
5800 | $TABLETRACK_DOWNLOADS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS); |
||
5801 | $condition_session = ''; |
||
5802 | $session_id = intval($session_id); |
||
5803 | if (!empty($session_id)) { |
||
5804 | $condition_session = ' AND down_session_id = '.$session_id; |
||
5805 | } |
||
5806 | $sql = "SELECT |
||
5807 | down_doc_path, |
||
5808 | COUNT(DISTINCT down_user_id), |
||
5809 | COUNT(down_doc_path) as count_down |
||
5810 | FROM $TABLETRACK_DOWNLOADS |
||
5811 | WHERE c_id = $courseId |
||
5812 | $condition_session |
||
5813 | GROUP BY down_doc_path |
||
5814 | ORDER BY count_down DESC |
||
5815 | LIMIT 0, $limit"; |
||
5816 | $rs = Database::query($sql); |
||
5817 | |||
5818 | if (Database::num_rows($rs) > 0) { |
||
5819 | while ($row = Database::fetch_array($rs)) { |
||
5820 | $data[] = $row; |
||
5821 | } |
||
5822 | } |
||
5823 | |||
5824 | return $data; |
||
5825 | } |
||
5826 | |||
5827 | /** |
||
5828 | * get links most visited by course. |
||
5829 | * |
||
5830 | * @param string Course code |
||
5831 | * @param int Session id (optional), |
||
5832 | * if param $session_id is null(default) it'll |
||
5833 | * return results including sessions, 0 = session is not filtered |
||
5834 | * |
||
5835 | * @return array links most visited |
||
5836 | */ |
||
5837 | public static function get_links_most_visited_by_course($course_code, $session_id = null) |
||
5838 | { |
||
5839 | $course_code = Database::escape_string($course_code); |
||
5840 | $course_info = api_get_course_info($course_code); |
||
5841 | $course_id = $course_info['real_id']; |
||
5842 | $data = []; |
||
5843 | |||
5844 | $TABLETRACK_LINKS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS); |
||
5845 | $TABLECOURSE_LINKS = Database::get_course_table(TABLE_LINK); |
||
5846 | |||
5847 | $condition_session = ''; |
||
5848 | if (isset($session_id)) { |
||
5849 | $session_id = intval($session_id); |
||
5850 | $condition_session = ' AND cl.session_id = '.$session_id; |
||
5851 | } |
||
5852 | |||
5853 | $sql = "SELECT cl.title, cl.url,count(DISTINCT sl.links_user_id), count(cl.title) as count_visits |
||
5854 | FROM $TABLETRACK_LINKS AS sl, $TABLECOURSE_LINKS AS cl |
||
5855 | WHERE |
||
5856 | cl.c_id = $course_id AND |
||
5857 | sl.links_link_id = cl.id AND |
||
5858 | sl.c_id = $course_id |
||
5859 | $condition_session |
||
5860 | GROUP BY cl.title, cl.url |
||
5861 | ORDER BY count_visits DESC |
||
5862 | LIMIT 0, 3"; |
||
5863 | $rs = Database::query($sql); |
||
5864 | if (Database::num_rows($rs) > 0) { |
||
5865 | while ($row = Database::fetch_array($rs)) { |
||
5866 | $data[] = $row; |
||
5867 | } |
||
5868 | } |
||
5869 | |||
5870 | return $data; |
||
5871 | } |
||
5872 | |||
5873 | /** |
||
5874 | * Shows the user progress (when clicking in the Progress tab). |
||
5875 | * |
||
5876 | * @param int $user_id |
||
5877 | * @param int $session_id |
||
5878 | * @param string $extra_params |
||
5879 | * @param bool $show_courses |
||
5880 | * @param bool $showAllSessions |
||
5881 | * @param bool $returnArray |
||
5882 | * |
||
5883 | * @return string|array |
||
5884 | */ |
||
5885 | public static function showUserProgress( |
||
5886 | $user_id, |
||
5887 | $session_id = 0, |
||
5888 | $extra_params = '', |
||
5889 | $show_courses = true, |
||
5890 | $showAllSessions = true, |
||
5891 | $returnArray = false, |
||
5892 | $showGraph = true |
||
5893 | ) { |
||
5894 | $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE); |
||
5895 | $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION); |
||
5896 | $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER); |
||
5897 | $tbl_access_rel_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); |
||
5898 | $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
5899 | $tbl_access_rel_session = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION); |
||
5900 | |||
5901 | $trackingColumns = [ |
||
5902 | 'course_session' => [ |
||
5903 | 'course_title' => true, |
||
5904 | 'published_exercises' => true, |
||
5905 | 'new_exercises' => true, |
||
5906 | 'my_average' => true, |
||
5907 | 'average_exercise_result' => true, |
||
5908 | 'time_spent' => true, |
||
5909 | 'lp_progress' => true, |
||
5910 | 'score' => true, |
||
5911 | 'best_score' => true, |
||
5912 | 'last_connection' => true, |
||
5913 | 'details' => true, |
||
5914 | ], |
||
5915 | ]; |
||
5916 | |||
5917 | $trackingColumnsConfig = api_get_configuration_value('tracking_columns'); |
||
5918 | if (!empty($trackingColumnsConfig)) { |
||
5919 | $trackingColumns = $trackingColumnsConfig; |
||
5920 | } |
||
5921 | |||
5922 | $user_id = (int) $user_id; |
||
5923 | $session_id = (int) $session_id; |
||
5924 | $urlId = api_get_current_access_url_id(); |
||
5925 | |||
5926 | if (api_is_multiple_url_enabled()) { |
||
5927 | $sql = "SELECT c.id, c.code, title |
||
5928 | FROM $tbl_course_user cu |
||
5929 | INNER JOIN $tbl_course c |
||
5930 | ON (cu.c_id = c.id) |
||
5931 | INNER JOIN $tbl_access_rel_course a |
||
5932 | ON (a.c_id = c.id) |
||
5933 | WHERE |
||
5934 | cu.user_id = $user_id AND |
||
5935 | relation_type<> ".COURSE_RELATION_TYPE_RRHH." AND |
||
5936 | access_url_id = $urlId |
||
5937 | ORDER BY title"; |
||
5938 | } else { |
||
5939 | $sql = "SELECT c.id, c.code, title |
||
5940 | FROM $tbl_course_user u |
||
5941 | INNER JOIN $tbl_course c ON (c_id = c.id) |
||
5942 | WHERE |
||
5943 | u.user_id= $user_id AND |
||
5944 | relation_type <> ".COURSE_RELATION_TYPE_RRHH." |
||
5945 | ORDER BY title"; |
||
5946 | } |
||
5947 | |||
5948 | $rs = Database::query($sql); |
||
5949 | $courses = $course_in_session = $temp_course_in_session = []; |
||
5950 | $courseIdList = []; |
||
5951 | while ($row = Database::fetch_array($rs, 'ASSOC')) { |
||
5952 | $courses[$row['code']] = $row['title']; |
||
5953 | $courseIdList[] = $row['id']; |
||
5954 | } |
||
5955 | |||
5956 | $orderBy = ' ORDER BY display_end_date DESC, name '; |
||
5957 | $extraInnerJoin = null; |
||
5958 | |||
5959 | if (SessionManager::orderCourseIsEnabled() && !empty($session_id)) { |
||
5960 | $orderBy = ' ORDER BY s.id, src.position '; |
||
5961 | $tableSessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE); |
||
5962 | $extraInnerJoin = " INNER JOIN $tableSessionRelCourse src |
||
5963 | ON (cu.c_id = src.c_id AND src.session_id = $session_id) "; |
||
5964 | } |
||
5965 | |||
5966 | $sessionCondition = ''; |
||
5967 | if (!empty($session_id)) { |
||
5968 | $sessionCondition = " AND s.id = $session_id"; |
||
5969 | } |
||
5970 | |||
5971 | // Get the list of sessions where the user is subscribed as student |
||
5972 | if (api_is_multiple_url_enabled()) { |
||
5973 | $sql = "SELECT DISTINCT c.code, s.id as session_id, name |
||
5974 | FROM $tbl_session_course_user cu |
||
5975 | INNER JOIN $tbl_access_rel_session a |
||
5976 | ON (a.session_id = cu.session_id) |
||
5977 | INNER JOIN $tbl_session s |
||
5978 | ON (s.id = a.session_id) |
||
5979 | INNER JOIN $tbl_course c |
||
5980 | ON (c.id = cu.c_id) |
||
5981 | $extraInnerJoin |
||
5982 | WHERE |
||
5983 | cu.user_id = $user_id AND |
||
5984 | access_url_id = ".$urlId." |
||
5985 | $sessionCondition |
||
5986 | $orderBy "; |
||
5987 | } else { |
||
5988 | $sql = "SELECT DISTINCT c.code, s.id as session_id, name |
||
5989 | FROM $tbl_session_course_user cu |
||
5990 | INNER JOIN $tbl_session s |
||
5991 | ON (s.id = cu.session_id) |
||
5992 | INNER JOIN $tbl_course c |
||
5993 | ON (c.id = cu.c_id) |
||
5994 | $extraInnerJoin |
||
5995 | WHERE |
||
5996 | cu.user_id = $user_id |
||
5997 | $sessionCondition |
||
5998 | $orderBy "; |
||
5999 | } |
||
6000 | |||
6001 | $rs = Database::query($sql); |
||
6002 | $simple_session_array = []; |
||
6003 | while ($row = Database::fetch_array($rs, 'ASSOC')) { |
||
6004 | $course_info = api_get_course_info($row['code']); |
||
6005 | $temp_course_in_session[$row['session_id']]['course_list'][$course_info['real_id']] = $course_info; |
||
6006 | $temp_course_in_session[$row['session_id']]['name'] = $row['name']; |
||
6007 | $simple_session_array[$row['session_id']] = $row['name']; |
||
6008 | } |
||
6009 | |||
6010 | foreach ($simple_session_array as $my_session_id => $session_name) { |
||
6011 | $course_list = $temp_course_in_session[$my_session_id]['course_list']; |
||
6012 | $my_course_data = []; |
||
6013 | foreach ($course_list as $courseId => $course_data) { |
||
6014 | $my_course_data[$courseId] = $course_data['title']; |
||
6015 | } |
||
6016 | |||
6017 | if (empty($session_id)) { |
||
6018 | $my_course_data = utf8_sort($my_course_data); |
||
6019 | } |
||
6020 | |||
6021 | $final_course_data = []; |
||
6022 | foreach ($my_course_data as $course_id => $value) { |
||
6023 | if (isset($course_list[$course_id])) { |
||
6024 | $final_course_data[$course_id] = $course_list[$course_id]; |
||
6025 | } |
||
6026 | } |
||
6027 | $course_in_session[$my_session_id]['course_list'] = $final_course_data; |
||
6028 | $course_in_session[$my_session_id]['name'] = $session_name; |
||
6029 | } |
||
6030 | |||
6031 | if ($returnArray) { |
||
6032 | $course_in_session[0] = $courseIdList; |
||
6033 | |||
6034 | return $course_in_session; |
||
6035 | } |
||
6036 | |||
6037 | $html = ''; |
||
6038 | // Course list. |
||
6039 | if ($show_courses) { |
||
6040 | if (!empty($courses)) { |
||
6041 | $html .= Display::page_header( |
||
6042 | Display::return_icon('course.png', get_lang('MyCourses')).PHP_EOL.get_lang('MyCourses') |
||
6043 | ); |
||
6044 | |||
6045 | $columns = [ |
||
6046 | 'course_title' => get_lang('Course'), |
||
6047 | 'time_spent' => get_lang('TimeSpentInTheCourse'), |
||
6048 | 'progress' => get_lang('Progress'), |
||
6049 | 'best_score_in_lp' => get_lang('BestScoreInLearningPath'), |
||
6050 | 'best_score_not_in_lp' => get_lang('BestScoreNotInLearningPath'), |
||
6051 | 'latest_login' => get_lang('LastConnexion'), |
||
6052 | 'details' => get_lang('Details'), |
||
6053 | ]; |
||
6054 | $availableColumns = []; |
||
6055 | if (isset($trackingColumns['my_progress_courses'])) { |
||
6056 | $availableColumns = $trackingColumns['my_progress_courses']; |
||
6057 | } |
||
6058 | |||
6059 | $columns = array_filter( |
||
6060 | $columns, |
||
6061 | function ($column, $columnKey) use ($availableColumns) { |
||
6062 | if (isset($availableColumns[$columnKey]) && $availableColumns[$columnKey] == false) { |
||
6063 | return false; |
||
6064 | } |
||
6065 | |||
6066 | return true; |
||
6067 | }, |
||
6068 | ARRAY_FILTER_USE_BOTH |
||
6069 | ); |
||
6070 | |||
6071 | $coursesTable = new SortableTableFromArray([], 0, 0, 'courses'); |
||
6072 | $coursesTable->setHeaders($columns); |
||
6073 | |||
6074 | foreach ($courses as $course_code => $course_title) { |
||
6075 | $courseInfo = api_get_course_info($course_code); |
||
6076 | $courseId = $courseInfo['real_id']; |
||
6077 | $lpShowMaxProgress = api_get_configuration_value('lp_show_max_progress_instead_of_average'); |
||
6078 | if (api_get_configuration_value('lp_show_max_progress_or_average_enable_course_level_redefinition')) { |
||
6079 | $lpShowProgressCourseSetting = api_get_course_setting('lp_show_max_or_average_progress', $courseInfo, true); |
||
6080 | if (in_array($lpShowProgressCourseSetting, ['max', 'average'])) { |
||
6081 | $lpShowMaxProgress = ('max' === $lpShowProgressCourseSetting); |
||
6082 | } |
||
6083 | } |
||
6084 | |||
6085 | $total_time_login = self::get_time_spent_on_the_course( |
||
6086 | $user_id, |
||
6087 | $courseId |
||
6088 | ); |
||
6089 | $time = api_time_to_hms($total_time_login); |
||
6090 | $progress = self::get_avg_student_progress( |
||
6091 | $user_id, |
||
6092 | $course_code, |
||
6093 | [], |
||
6094 | null, |
||
6095 | false, |
||
6096 | false, |
||
6097 | $lpShowMaxProgress |
||
6098 | ); |
||
6099 | $bestScore = self::get_avg_student_score( |
||
6100 | $user_id, |
||
6101 | $course_code, |
||
6102 | [], |
||
6103 | null, |
||
6104 | false, |
||
6105 | false, |
||
6106 | true |
||
6107 | ); |
||
6108 | |||
6109 | $exerciseList = ExerciseLib::get_all_exercises( |
||
6110 | $courseInfo, |
||
6111 | 0, |
||
6112 | false, |
||
6113 | null, |
||
6114 | false, |
||
6115 | 1 |
||
6116 | ); |
||
6117 | |||
6118 | $bestScoreAverageNotInLP = 0; |
||
6119 | if (!empty($exerciseList)) { |
||
6120 | foreach ($exerciseList as $exerciseData) { |
||
6121 | $results = Event::get_best_exercise_results_by_user( |
||
6122 | $exerciseData['iid'], |
||
6123 | $courseInfo['real_id'], |
||
6124 | 0, |
||
6125 | $user_id |
||
6126 | ); |
||
6127 | $best = 0; |
||
6128 | if (!empty($results)) { |
||
6129 | foreach ($results as $result) { |
||
6130 | if (!empty($result['exe_weighting'])) { |
||
6131 | $score = $result['exe_result'] / $result['exe_weighting']; |
||
6132 | if ($score > $best) { |
||
6133 | $best = $score; |
||
6134 | } |
||
6135 | } |
||
6136 | } |
||
6137 | } |
||
6138 | $bestScoreAverageNotInLP += $best; |
||
6139 | } |
||
6140 | $bestScoreAverageNotInLP = round($bestScoreAverageNotInLP / count($exerciseList) * 100, 2); |
||
6141 | } |
||
6142 | |||
6143 | $last_connection = self::get_last_connection_date_on_the_course($user_id, $courseInfo); |
||
6144 | |||
6145 | if (is_null($progress) || empty($progress)) { |
||
6146 | $progress = '0%'; |
||
6147 | } else { |
||
6148 | $progress = $progress.'%'; |
||
6149 | } |
||
6150 | |||
6151 | $filterByCourse = isset($_GET['course']) && $course_code == $_GET['course'] |
||
6152 | && empty($_GET['session_id']); |
||
6153 | |||
6154 | $url = api_get_course_url($course_code, $session_id); |
||
6155 | $course_url = Display::url($course_title, $url, ['target' => SESSION_LINK_TARGET]); |
||
6156 | $bestScoreResult = empty($bestScore) ? '-' : sprintf(get_lang('XPercent'), $bestScore); |
||
6157 | $bestScoreNotInLP = empty($bestScoreAverageNotInLP) |
||
6158 | ? '-' |
||
6159 | : sprintf(get_lang('XPercent'), $bestScoreAverageNotInLP); |
||
6160 | |||
6161 | $detailsLink = ''; |
||
6162 | if ($filterByCourse) { |
||
6163 | $detailsLink .= '<a href="#course_session_data">'; |
||
6164 | $detailsLink .= Display::return_icon('2rightarrow_na.png', get_lang('Details')); |
||
6165 | $detailsLink .= '</a>'; |
||
6166 | } else { |
||
6167 | $detailsLink .= '<a href="'.api_get_self().'?course='.$course_code.$extra_params.'#course_session_data">'; |
||
6168 | $detailsLink .= Display::return_icon('2rightarrow.png', get_lang('Details')); |
||
6169 | $detailsLink .= '</a>'; |
||
6170 | } |
||
6171 | |||
6172 | $result = array_filter( |
||
6173 | [ |
||
6174 | 'course_title' => $course_url, |
||
6175 | 'time_spent' => $time, |
||
6176 | 'progress' => $progress, |
||
6177 | 'best_score_in_lp' => $bestScoreResult, |
||
6178 | 'best_score_not_in_lp' => $bestScoreNotInLP, |
||
6179 | 'latest_login' => $last_connection, |
||
6180 | 'details' => $detailsLink, |
||
6181 | ], |
||
6182 | function ($data, $columnKey) { |
||
6183 | if (isset($availableColumns[$columnKey]) && $availableColumns[$columnKey] == false) { |
||
6184 | return false; |
||
6185 | } |
||
6186 | |||
6187 | return true; |
||
6188 | }, |
||
6189 | ARRAY_FILTER_USE_BOTH |
||
6190 | ); |
||
6191 | |||
6192 | $coursesTable->addRow( |
||
6193 | array_values($result), |
||
6194 | ['style' => $filterByCourse ? 'background-color: #FBF09D;' : ''] |
||
6195 | ); |
||
6196 | } |
||
6197 | |||
6198 | $html .= Display::div($coursesTable->toHtml(), ['class' => 'table-responsive']); |
||
6199 | } |
||
6200 | } |
||
6201 | |||
6202 | $allowCareerUser = api_get_configuration_value('allow_career_users'); |
||
6203 | |||
6204 | // Session list. |
||
6205 | $visibleSessions = []; |
||
6206 | if (!empty($course_in_session)) { |
||
6207 | $main_session_graph = ''; |
||
6208 | // Load graphics only when calling to an specific session |
||
6209 | $all_exercise_graph_name_list = []; |
||
6210 | $my_results = []; |
||
6211 | $all_exercise_graph_list = []; |
||
6212 | $all_exercise_start_time = []; |
||
6213 | foreach ($course_in_session as $my_session_id => $session_data) { |
||
6214 | $course_list = $session_data['course_list']; |
||
6215 | $user_count = count(SessionManager::get_users_by_session($my_session_id)); |
||
6216 | $exercise_graph_name_list = []; |
||
6217 | $exercise_graph_list = []; |
||
6218 | |||
6219 | $visibility = api_get_session_visibility($my_session_id, null, false, $user_id); |
||
6220 | |||
6221 | if (SESSION_AVAILABLE === $visibility) { |
||
6222 | $visibleSessions[] = $my_session_id; |
||
6223 | } |
||
6224 | |||
6225 | foreach ($course_list as $course_data) { |
||
6226 | $exercise_list = ExerciseLib::get_all_exercises( |
||
6227 | $course_data, |
||
6228 | $my_session_id, |
||
6229 | false, |
||
6230 | null, |
||
6231 | false, |
||
6232 | 1 |
||
6233 | ); |
||
6234 | |||
6235 | foreach ($exercise_list as $exercise_data) { |
||
6236 | $exercise_obj = new Exercise($course_data['real_id']); |
||
6237 | $exercise_obj->read($exercise_data['iid']); |
||
6238 | // Exercise is not necessary to be visible to show results check the result_disable configuration instead |
||
6239 | // $visible_return = $exercise_obj->is_visible(); |
||
6240 | if ($exercise_data['results_disabled'] == 0 || $exercise_data['results_disabled'] == 2) { |
||
6241 | $best_average = (int) |
||
6242 | ExerciseLib::get_best_average_score_by_exercise( |
||
6243 | $exercise_data['iid'], |
||
6244 | $course_data['real_id'], |
||
6245 | $my_session_id, |
||
6246 | $user_count |
||
6247 | ) |
||
6248 | ; |
||
6249 | |||
6250 | $exercise_graph_list[] = $best_average; |
||
6251 | $all_exercise_graph_list[] = $best_average; |
||
6252 | |||
6253 | $user_result_data = ExerciseLib::get_best_attempt_by_user( |
||
6254 | api_get_user_id(), |
||
6255 | $exercise_data['iid'], |
||
6256 | $course_data['real_id'], |
||
6257 | $my_session_id |
||
6258 | ); |
||
6259 | |||
6260 | $score = 0; |
||
6261 | if (!empty($user_result_data['exe_weighting']) && intval($user_result_data['exe_weighting']) != 0) { |
||
6262 | $score = intval($user_result_data['exe_result'] / $user_result_data['exe_weighting'] * 100); |
||
6263 | } |
||
6264 | $time = api_strtotime($exercise_data['start_time']) ? api_strtotime($exercise_data['start_time'], 'UTC') : 0; |
||
6265 | $all_exercise_start_time[] = $time; |
||
6266 | $my_results[] = $score; |
||
6267 | if (count($exercise_list) <= 10) { |
||
6268 | $title = cut($course_data['title'], 30)." \n ".cut($exercise_data['title'], 30); |
||
6269 | $exercise_graph_name_list[] = $title; |
||
6270 | $all_exercise_graph_name_list[] = $title; |
||
6271 | } else { |
||
6272 | // if there are more than 10 results, space becomes difficult to find, |
||
6273 | // so only show the title of the exercise, not the tool |
||
6274 | $title = cut($exercise_data['title'], 30); |
||
6275 | $exercise_graph_name_list[] = $title; |
||
6276 | $all_exercise_graph_name_list[] = $title; |
||
6277 | } |
||
6278 | } |
||
6279 | } |
||
6280 | } |
||
6281 | } |
||
6282 | |||
6283 | // Complete graph |
||
6284 | if (!empty($my_results) && !empty($all_exercise_graph_list)) { |
||
6285 | asort($all_exercise_start_time); |
||
6286 | |||
6287 | // Fix exams order |
||
6288 | $final_all_exercise_graph_name_list = []; |
||
6289 | $my_results_final = []; |
||
6290 | $final_all_exercise_graph_list = []; |
||
6291 | |||
6292 | foreach ($all_exercise_start_time as $key => $time) { |
||
6293 | $label_time = ''; |
||
6294 | if (!empty($time)) { |
||
6295 | $label_time = date('d-m-y', $time); |
||
6296 | } |
||
6297 | $final_all_exercise_graph_name_list[] = $all_exercise_graph_name_list[$key].' '.$label_time; |
||
6298 | $my_results_final[] = $my_results[$key]; |
||
6299 | $final_all_exercise_graph_list[] = $all_exercise_graph_list[$key]; |
||
6300 | } |
||
6301 | if ($showGraph) { |
||
6302 | $main_session_graph = '<div class="row"><div class="col-md-10 col-md-offset-1">' |
||
6303 | .self::generate_session_exercise_graph( |
||
6304 | $final_all_exercise_graph_name_list, |
||
6305 | $my_results_final, |
||
6306 | $final_all_exercise_graph_list |
||
6307 | ) |
||
6308 | .'</div></div>'; |
||
6309 | } |
||
6310 | } |
||
6311 | |||
6312 | $sessionIcon = Display::return_icon('session.png', get_lang('Sessions')); |
||
6313 | |||
6314 | $anchor = Display::url('', '', ['name' => 'course_session_header']); |
||
6315 | $html .= $anchor.Display::page_header( |
||
6316 | $sessionIcon.PHP_EOL.get_lang('Sessions') |
||
6317 | ); |
||
6318 | |||
6319 | $sessionsTable = new SortableTableFromArray([], 0, 0, 'sessions'); |
||
6320 | $sessionsTable->setHeaders( |
||
6321 | [ |
||
6322 | get_lang('Session'), |
||
6323 | get_lang('PublishedExercises'), |
||
6324 | get_lang('NewExercises'), |
||
6325 | get_lang('AverageExerciseResult'), |
||
6326 | get_lang('Details'), |
||
6327 | ] |
||
6328 | ); |
||
6329 | |||
6330 | foreach ($course_in_session as $my_session_id => $session_data) { |
||
6331 | $course_list = $session_data['course_list']; |
||
6332 | $session_name = $session_data['name']; |
||
6333 | if ($showAllSessions == false) { |
||
6334 | if (isset($session_id) && !empty($session_id)) { |
||
6335 | if ($session_id != $my_session_id) { |
||
6336 | continue; |
||
6337 | } |
||
6338 | } |
||
6339 | } |
||
6340 | |||
6341 | $all_exercises = 0; |
||
6342 | $all_unanswered_exercises_by_user = 0; |
||
6343 | $all_average = 0; |
||
6344 | $stats_array = []; |
||
6345 | |||
6346 | foreach ($course_list as $course_data) { |
||
6347 | // All exercises in the course @todo change for a real count |
||
6348 | $exercises = ExerciseLib::get_all_exercises($course_data, $my_session_id); |
||
6349 | $count_exercises = 0; |
||
6350 | if (is_array($exercises) && !empty($exercises)) { |
||
6351 | $count_exercises = count($exercises); |
||
6352 | } |
||
6353 | |||
6354 | // Count of user results |
||
6355 | $done_exercises = null; |
||
6356 | $courseInfo = api_get_course_info($course_data['code']); |
||
6357 | |||
6358 | $answered_exercises = 0; |
||
6359 | if (!empty($exercises)) { |
||
6360 | foreach ($exercises as $exercise_item) { |
||
6361 | $attempts = Event::count_exercise_attempts_by_user( |
||
6362 | api_get_user_id(), |
||
6363 | $exercise_item['iid'], |
||
6364 | $courseInfo['real_id'], |
||
6365 | $my_session_id |
||
6366 | ); |
||
6367 | if ($attempts > 1) { |
||
6368 | $answered_exercises++; |
||
6369 | } |
||
6370 | } |
||
6371 | } |
||
6372 | |||
6373 | // Average |
||
6374 | $average = ExerciseLib::get_average_score_by_course( |
||
6375 | $courseInfo['real_id'], |
||
6376 | $my_session_id |
||
6377 | ); |
||
6378 | $all_exercises += $count_exercises; |
||
6379 | $all_unanswered_exercises_by_user += $count_exercises - $answered_exercises; |
||
6380 | $all_average += $average; |
||
6381 | } |
||
6382 | |||
6383 | if (!empty($course_list)) { |
||
6384 | $all_average = $all_average / count($course_list); |
||
6385 | } |
||
6386 | |||
6387 | $filterBySession = isset($_GET['session_id']) && $my_session_id == $_GET['session_id']; |
||
6388 | |||
6389 | $url = api_get_path(WEB_CODE_PATH)."session/index.php?session_id={$my_session_id}"; |
||
6390 | |||
6391 | $sessionsTable->addRow( |
||
6392 | [ |
||
6393 | Display::url($session_name, $url, ['target' => SESSION_LINK_TARGET]), |
||
6394 | $all_exercises, |
||
6395 | $all_unanswered_exercises_by_user, |
||
6396 | ExerciseLib::convert_to_percentage($all_average), |
||
6397 | Display::url( |
||
6398 | Display::return_icon( |
||
6399 | $filterBySession ? '2rightarrow_na.png' : '2rightarrow.png', |
||
6400 | get_lang('Details') |
||
6401 | ), |
||
6402 | api_get_self().'?session_id='.$my_session_id.'#course_session_list' |
||
6403 | ), |
||
6404 | ], |
||
6405 | ['style' => $filterBySession ? 'background-color: #FBF09D;' : ''] |
||
6406 | ); |
||
6407 | } |
||
6408 | |||
6409 | if ($allowCareerUser) { |
||
6410 | $diagrams = ''; |
||
6411 | if (!empty($visibleSessions)) { |
||
6412 | $diagrams .= SessionManager::getCareerDiagramPerSessionList($visibleSessions, $user_id); |
||
6413 | } |
||
6414 | $html .= $diagrams.MyStudents::userCareersTable($user_id); |
||
6415 | } |
||
6416 | |||
6417 | $html .= Display::div($sessionsTable->toHtml(), ['class' => 'table-responsive']); |
||
6418 | |||
6419 | if ($showGraph) { |
||
6420 | $html .= Display::div( |
||
6421 | $main_session_graph, |
||
6422 | [ |
||
6423 | 'id' => 'session_graph', |
||
6424 | 'class' => 'chart-session', |
||
6425 | ] |
||
6426 | ); |
||
6427 | } |
||
6428 | |||
6429 | // Checking selected session. |
||
6430 | if (isset($_GET['session_id'])) { |
||
6431 | $session_id_from_get = (int) $_GET['session_id']; |
||
6432 | $session_data = $course_in_session[$session_id_from_get]; |
||
6433 | $course_list = $session_data['course_list']; |
||
6434 | |||
6435 | $html .= '<a name="course_session_list"></a>'; |
||
6436 | $html .= Display::page_subheader($session_data['name'], get_lang('CourseList')); |
||
6437 | |||
6438 | $columnHeaders = array_filter( |
||
6439 | [ |
||
6440 | 'course_title' => get_lang('Course'), |
||
6441 | 'published_exercises' => get_lang('PublishedExercises'), |
||
6442 | 'new_exercises' => get_lang('NewExercises'), |
||
6443 | 'my_average' => get_lang('MyAverage'), |
||
6444 | 'average_exercise_result' => get_lang('AverageExerciseResult'), |
||
6445 | 'time_spent' => get_lang('TimeSpentInTheCourse'), |
||
6446 | 'lp_progress' => get_lang('LPProgress'), |
||
6447 | 'score' => get_lang('Score') |
||
6448 | .Display::return_icon('info3.gif', get_lang('ScormAndLPTestTotalAverage')), |
||
6449 | 'best_score' => get_lang('BestScore'), |
||
6450 | 'last_connection' => get_lang('LastConnexion'), |
||
6451 | 'details' => get_lang('Details'), |
||
6452 | ], |
||
6453 | function ($column, $key) use ($trackingColumns) { |
||
6454 | if (isset($trackingColumns['course_session']) |
||
6455 | && in_array($key, $trackingColumns['course_session']) |
||
6456 | && $trackingColumns['course_session'][$key] |
||
6457 | ) { |
||
6458 | return true; |
||
6459 | } |
||
6460 | |||
6461 | return false; |
||
6462 | }, |
||
6463 | ARRAY_FILTER_USE_BOTH |
||
6464 | ); |
||
6465 | |||
6466 | $sessionCoursesTable = new SortableTableFromArray([], 0, 0, 'session_courses'); |
||
6467 | $sessionCoursesTable->setHeaders($columnHeaders); |
||
6468 | |||
6469 | foreach ($course_list as $course_data) { |
||
6470 | $course_code = $course_data['code']; |
||
6471 | $course_title = $course_data['title']; |
||
6472 | $courseId = $course_data['real_id']; |
||
6473 | |||
6474 | // All exercises in the course @todo change for a real count |
||
6475 | $exercises = ExerciseLib::get_all_exercises( |
||
6476 | $course_data, |
||
6477 | $session_id_from_get |
||
6478 | ); |
||
6479 | $count_exercises = 0; |
||
6480 | if (!empty($exercises)) { |
||
6481 | $count_exercises = count($exercises); |
||
6482 | } |
||
6483 | $answered_exercises = 0; |
||
6484 | foreach ($exercises as $exercise_item) { |
||
6485 | $attempts = Event::count_exercise_attempts_by_user( |
||
6486 | api_get_user_id(), |
||
6487 | $exercise_item['iid'], |
||
6488 | $courseId, |
||
6489 | $session_id_from_get |
||
6490 | ); |
||
6491 | if ($attempts > 1) { |
||
6492 | $answered_exercises++; |
||
6493 | } |
||
6494 | } |
||
6495 | |||
6496 | $unanswered_exercises = $count_exercises - $answered_exercises; |
||
6497 | |||
6498 | // Average |
||
6499 | $average = ExerciseLib::get_average_score_by_course( |
||
6500 | $courseId, |
||
6501 | $session_id_from_get |
||
6502 | ); |
||
6503 | $my_average = ExerciseLib::get_average_score_by_course_by_user( |
||
6504 | api_get_user_id(), |
||
6505 | $courseId, |
||
6506 | $session_id_from_get |
||
6507 | ); |
||
6508 | |||
6509 | $bestScore = self::get_avg_student_score( |
||
6510 | $user_id, |
||
6511 | $course_code, |
||
6512 | [], |
||
6513 | $session_id_from_get, |
||
6514 | false, |
||
6515 | false, |
||
6516 | true |
||
6517 | ); |
||
6518 | |||
6519 | $stats_array[$course_code] = [ |
||
6520 | 'exercises' => $count_exercises, |
||
6521 | 'unanswered_exercises_by_user' => $unanswered_exercises, |
||
6522 | 'done_exercises' => $done_exercises, |
||
6523 | 'average' => $average, |
||
6524 | 'my_average' => $my_average, |
||
6525 | 'best_score' => $bestScore, |
||
6526 | ]; |
||
6527 | |||
6528 | $last_connection = self::get_last_connection_date_on_the_course( |
||
6529 | $user_id, |
||
6530 | $course_data, |
||
6531 | $session_id_from_get |
||
6532 | ); |
||
6533 | |||
6534 | $progress = self::get_avg_student_progress( |
||
6535 | $user_id, |
||
6536 | $course_code, |
||
6537 | [], |
||
6538 | $session_id_from_get, |
||
6539 | false, |
||
6540 | false, |
||
6541 | $lpShowMaxProgress |
||
6542 | ); |
||
6543 | |||
6544 | $total_time_login = self::get_time_spent_on_the_course( |
||
6545 | $user_id, |
||
6546 | $courseId, |
||
6547 | $session_id_from_get |
||
6548 | ); |
||
6549 | $time = api_time_to_hms($total_time_login); |
||
6550 | |||
6551 | $percentage_score = self::get_avg_student_score( |
||
6552 | $user_id, |
||
6553 | $course_code, |
||
6554 | [], |
||
6555 | $session_id_from_get |
||
6556 | ); |
||
6557 | $courseCodeFromGet = $_GET['course'] ?? null; |
||
6558 | |||
6559 | $filterByCourse = $course_code == $courseCodeFromGet && $_GET['session_id'] == $session_id_from_get; |
||
6560 | |||
6561 | $url = api_get_course_url($course_code, $session_id_from_get); |
||
6562 | $course_url = Display::url( |
||
6563 | $course_title, |
||
6564 | $url, |
||
6565 | ['target' => SESSION_LINK_TARGET] |
||
6566 | ); |
||
6567 | |||
6568 | if (is_numeric($progress)) { |
||
6569 | $progress = $progress.'%'; |
||
6570 | } else { |
||
6571 | $progress = '0%'; |
||
6572 | } |
||
6573 | if (is_numeric($percentage_score)) { |
||
6574 | $percentage_score = $percentage_score.'%'; |
||
6575 | } else { |
||
6576 | $percentage_score = '0%'; |
||
6577 | } |
||
6578 | |||
6579 | if (is_numeric($stats_array[$course_code]['best_score'])) { |
||
6580 | $bestScore = $stats_array[$course_code]['best_score'].'%'; |
||
6581 | } else { |
||
6582 | $bestScore = '-'; |
||
6583 | } |
||
6584 | |||
6585 | if (empty($last_connection) || is_bool($last_connection)) { |
||
6586 | $last_connection = ''; |
||
6587 | } |
||
6588 | |||
6589 | if ($course_code == $courseCodeFromGet |
||
6590 | && $_GET['session_id'] == $session_id_from_get |
||
6591 | ) { |
||
6592 | $details = Display::url( |
||
6593 | Display::return_icon('2rightarrow_na.png', get_lang('Details')), |
||
6594 | '#course_session_data' |
||
6595 | ); |
||
6596 | } else { |
||
6597 | $url = api_get_self().'?course='.$course_code.'&session_id='.$session_id_from_get.$extra_params.'#course_session_data'; |
||
6598 | $details = Display::url( |
||
6599 | Display::return_icon( |
||
6600 | '2rightarrow.png', |
||
6601 | get_lang('Details') |
||
6602 | ), |
||
6603 | $url |
||
6604 | ); |
||
6605 | } |
||
6606 | |||
6607 | $data = array_filter( |
||
6608 | [ |
||
6609 | 'course_title' => $course_url, |
||
6610 | 'published_exercises' => $stats_array[$course_code]['exercises'], // exercise available |
||
6611 | 'new_exercises' => $stats_array[$course_code]['unanswered_exercises_by_user'], |
||
6612 | 'my_average' => ExerciseLib::convert_to_percentage($stats_array[$course_code]['my_average']), |
||
6613 | 'average_exercise_result' => $stats_array[$course_code]['average'] == 0 ? '-' : '('.ExerciseLib::convert_to_percentage($stats_array[$course_code]['average']).')', |
||
6614 | 'time_spent' => $time, |
||
6615 | 'lp_progress' => $progress, |
||
6616 | 'score' => $percentage_score, |
||
6617 | 'best_score' => $bestScore, |
||
6618 | 'last_connection' => $last_connection, |
||
6619 | 'details' => $details, |
||
6620 | ], |
||
6621 | function ($value, $key) use ($trackingColumns) { |
||
6622 | if (in_array($key, $trackingColumns['course_session']) && $trackingColumns['course_session'][$key]) { |
||
6623 | return true; |
||
6624 | } |
||
6625 | |||
6626 | return false; |
||
6627 | }, |
||
6628 | ARRAY_FILTER_USE_BOTH |
||
6629 | ); |
||
6630 | |||
6631 | $sessionCoursesTable->addRow( |
||
6632 | array_values($data), |
||
6633 | ['style' => $filterByCourse ? 'background-color: #FBF09D;' : ''] |
||
6634 | ); |
||
6635 | } |
||
6636 | |||
6637 | $html .= Display::div($sessionCoursesTable->toHtml(), ['class' => 'table-responsive']); |
||
6638 | } |
||
6639 | } |
||
6640 | |||
6641 | $pluginCalendar = api_get_plugin_setting('learning_calendar', 'enabled') === 'true'; |
||
6642 | if ($pluginCalendar) { |
||
6643 | $course_in_session[0] = $courseIdList; |
||
6644 | $plugin = LearningCalendarPlugin::create(); |
||
6645 | $html .= $plugin->getUserStatsPanel($user_id, $course_in_session); |
||
6646 | } |
||
6647 | |||
6648 | return $html; |
||
6649 | } |
||
6650 | |||
6651 | /** |
||
6652 | * Shows the user detail progress (when clicking in the details link). |
||
6653 | * |
||
6654 | * @param int $user_id |
||
6655 | * @param string $course_code |
||
6656 | * @param int $session_id |
||
6657 | */ |
||
6658 | public static function show_course_detail($user_id, $course_code, $session_id, $isAllowedToEdit = true): string |
||
6659 | { |
||
6660 | if (empty($user_id) || empty($course_code)) { |
||
6661 | return ''; |
||
6662 | } |
||
6663 | |||
6664 | $course_info = api_get_course_info($course_code); |
||
6665 | if (empty($course_info)) { |
||
6666 | return ''; |
||
6667 | } |
||
6668 | |||
6669 | $user_id = (int) $user_id; |
||
6670 | $user = api_get_user_entity($user_id); |
||
6671 | $session_id = (int) $session_id; |
||
6672 | |||
6673 | $html = '<a name="course_session_data"></a>'; |
||
6674 | $html .= Display::page_subheader2($course_info['title']); |
||
6675 | // Show exercise results of invisible exercises? see BT#4091 |
||
6676 | $quizzesHtml = self::generateQuizzesTable($course_info, $session_id); |
||
6677 | // LP table results |
||
6678 | $learningPathsHtml = self::generateLearningPathsTable($user, $course_info, $session_id, $isAllowedToEdit); |
||
6679 | $skillsHtml = self::displayUserSkills($user_id, $course_info['id'], $session_id); |
||
6680 | |||
6681 | $toolsHtml = [ |
||
6682 | 'quizzes' => $quizzesHtml, |
||
6683 | 'learning_paths' => $learningPathsHtml, |
||
6684 | 'skills' => $skillsHtml, |
||
6685 | ]; |
||
6686 | |||
6687 | $toolsOrder = api_get_configuration_value('my_progress_course_tools_order'); |
||
6688 | |||
6689 | if (empty($toolsOrder)) { |
||
6690 | $html .= implode(PHP_EOL, $toolsHtml); |
||
6691 | } else { |
||
6692 | foreach ($toolsOrder['order'] as $tool) { |
||
6693 | $html .= $toolsHtml[$tool].PHP_EOL; |
||
6694 | } |
||
6695 | } |
||
6696 | |||
6697 | return $html; |
||
6698 | } |
||
6699 | |||
6700 | /** |
||
6701 | * Generates an histogram. |
||
6702 | * |
||
6703 | * @param array $names list of exercise names |
||
6704 | * @param array $my_results my results 0 to 100 |
||
6705 | * @param array $average average scores 0-100 |
||
6706 | * |
||
6707 | * @return string |
||
6708 | */ |
||
6709 | public static function generate_session_exercise_graph($names, $my_results, $average) |
||
6710 | { |
||
6711 | $html = api_get_js('chartjs/Chart.js'); |
||
6712 | $canvas = Display::tag('canvas', '', ['id' => 'session_graph_chart']); |
||
6713 | $html .= Display::tag('div', $canvas, ['style' => 'width:100%']); |
||
6714 | $jsStr = " var data = { |
||
6715 | labels:".json_encode($names).", |
||
6716 | datasets: [ |
||
6717 | { |
||
6718 | label: '".get_lang('MyResults')."', |
||
6719 | backgroundColor: 'rgb(255, 99, 132)', |
||
6720 | stack: 'Stack1', |
||
6721 | data: ".json_encode($my_results).", |
||
6722 | }, |
||
6723 | { |
||
6724 | label: '".get_lang('AverageScore')."', |
||
6725 | backgroundColor: 'rgb(75, 192, 192)', |
||
6726 | stack: 'Stack2', |
||
6727 | data: ".json_encode($average).", |
||
6728 | }, |
||
6729 | ], |
||
6730 | }; |
||
6731 | var ctx = document.getElementById('session_graph_chart').getContext('2d'); |
||
6732 | var myBarChart = new Chart(ctx, { |
||
6733 | type: 'bar', |
||
6734 | data: data, |
||
6735 | options: { |
||
6736 | title: { |
||
6737 | display: true, |
||
6738 | text: '".get_lang('ExercisesInTimeProgressChart')."' |
||
6739 | }, |
||
6740 | tooltips: { |
||
6741 | mode: 'index', |
||
6742 | intersect: false |
||
6743 | }, |
||
6744 | responsive: true, |
||
6745 | scales: { |
||
6746 | yAxes: [{ |
||
6747 | ticks: { |
||
6748 | // Include a dollar sign in the ticks |
||
6749 | callback: function(value, index, values) { |
||
6750 | return value + '%'; |
||
6751 | } |
||
6752 | } |
||
6753 | }] |
||
6754 | } |
||
6755 | } |
||
6756 | });"; |
||
6757 | $html .= Display::tag('script', $jsStr); |
||
6758 | |||
6759 | return $html; |
||
6760 | } |
||
6761 | |||
6762 | /** |
||
6763 | * Returns a thumbnail of the function generate_exercise_result_graph. |
||
6764 | * |
||
6765 | * @param array $attempts |
||
6766 | */ |
||
6767 | public static function generate_exercise_result_thumbnail_graph($attempts) |
||
6768 | { |
||
6769 | // $exercise_title = $attempts['title']; |
||
6770 | $attempts = $attempts['data']; |
||
6771 | $my_exercise_result_array = $exercise_result = []; |
||
6772 | if (empty($attempts)) { |
||
6773 | return null; |
||
6774 | } |
||
6775 | |||
6776 | foreach ($attempts as $attempt) { |
||
6777 | if (api_get_user_id() == $attempt['exe_user_id']) { |
||
6778 | if ($attempt['exe_weighting'] != 0) { |
||
6779 | $my_exercise_result_array[] = $attempt['exe_result'] / $attempt['exe_weighting']; |
||
6780 | } |
||
6781 | } else { |
||
6782 | if ($attempt['exe_weighting'] != 0) { |
||
6783 | $exercise_result[] = $attempt['exe_result'] / $attempt['exe_weighting']; |
||
6784 | } |
||
6785 | } |
||
6786 | } |
||
6787 | |||
6788 | // Getting best result |
||
6789 | rsort($my_exercise_result_array); |
||
6790 | $my_exercise_result = 0; |
||
6791 | if (isset($my_exercise_result_array[0])) { |
||
6792 | $my_exercise_result = $my_exercise_result_array[0] * 100; |
||
6793 | } |
||
6794 | |||
6795 | $max = 100; |
||
6796 | $pieces = 5; |
||
6797 | $part = round($max / $pieces); |
||
6798 | $x_axis = []; |
||
6799 | $final_array = []; |
||
6800 | $my_final_array = []; |
||
6801 | |||
6802 | for ($i = 1; $i <= $pieces; $i++) { |
||
6803 | $sum = 1; |
||
6804 | if ($i == 1) { |
||
6805 | $sum = 0; |
||
6806 | } |
||
6807 | $min = ($i - 1) * $part + $sum; |
||
6808 | $max = $i * $part; |
||
6809 | $x_axis[] = $min." - ".$max; |
||
6810 | $count = 0; |
||
6811 | foreach ($exercise_result as $result) { |
||
6812 | $percentage = $result * 100; |
||
6813 | if ($percentage >= $min && $percentage <= $max) { |
||
6814 | // echo ' is > '; |
||
6815 | $count++; |
||
6816 | } |
||
6817 | } |
||
6818 | // echo '<br />'; |
||
6819 | $final_array[] = $count; |
||
6820 | |||
6821 | if ($my_exercise_result >= $min && $my_exercise_result <= $max) { |
||
6822 | $my_final_array[] = 1; |
||
6823 | } else { |
||
6824 | $my_final_array[] = 0; |
||
6825 | } |
||
6826 | } |
||
6827 | |||
6828 | // Fix to remove the data of the user with my data |
||
6829 | for ($i = 0; $i <= count($my_final_array); $i++) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
6830 | if (!empty($my_final_array[$i])) { |
||
6831 | $my_final_array[$i] = $final_array[$i] + 1; // Add my result |
||
6832 | $final_array[$i] = 0; |
||
6833 | } |
||
6834 | } |
||
6835 | |||
6836 | // Dataset definition |
||
6837 | $dataSet = new pData(); |
||
6838 | $dataSet->addPoints($final_array, 'Serie1'); |
||
6839 | $dataSet->addPoints($my_final_array, 'Serie2'); |
||
6840 | $dataSet->normalize(100, "%"); |
||
6841 | $dataSet->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true); |
||
6842 | |||
6843 | // Cache definition |
||
6844 | $cachePath = api_get_path(SYS_ARCHIVE_PATH); |
||
6845 | $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]); |
||
6846 | $chartHash = $myCache->getHash($dataSet); |
||
6847 | if ($myCache->isInCache($chartHash)) { |
||
6848 | $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash; |
||
6849 | $myCache->saveFromCache($chartHash, $imgPath); |
||
6850 | $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash; |
||
6851 | } else { |
||
6852 | /* Create the pChart object */ |
||
6853 | $widthSize = 80; |
||
6854 | $heightSize = 35; |
||
6855 | $fontSize = 2; |
||
6856 | |||
6857 | $myPicture = new pImage($widthSize, $heightSize, $dataSet); |
||
6858 | |||
6859 | /* Turn of Antialiasing */ |
||
6860 | $myPicture->Antialias = false; |
||
6861 | |||
6862 | /* Add a border to the picture */ |
||
6863 | $myPicture->drawRectangle( |
||
6864 | 0, |
||
6865 | 0, |
||
6866 | $widthSize - 1, |
||
6867 | $heightSize - 1, |
||
6868 | ['R' => 0, 'G' => 0, 'B' => 0] |
||
6869 | ); |
||
6870 | |||
6871 | /* Set the default font */ |
||
6872 | $myPicture->setFontProperties( |
||
6873 | [ |
||
6874 | 'FontName' => api_get_path( |
||
6875 | SYS_FONTS_PATH |
||
6876 | ).'opensans/OpenSans-Regular.ttf', |
||
6877 | 'FontSize' => $fontSize, |
||
6878 | ] |
||
6879 | ); |
||
6880 | |||
6881 | /* Do not write the chart title */ |
||
6882 | /* Define the chart area */ |
||
6883 | $myPicture->setGraphArea(5, 5, $widthSize - 5, $heightSize - 5); |
||
6884 | |||
6885 | /* Draw the scale */ |
||
6886 | $scaleSettings = [ |
||
6887 | 'GridR' => 200, |
||
6888 | 'GridG' => 200, |
||
6889 | 'GridB' => 200, |
||
6890 | 'DrawSubTicks' => true, |
||
6891 | 'CycleBackground' => true, |
||
6892 | 'Mode' => SCALE_MODE_MANUAL, |
||
6893 | 'ManualScale' => [ |
||
6894 | '0' => [ |
||
6895 | 'Min' => 0, |
||
6896 | 'Max' => 100, |
||
6897 | ], |
||
6898 | ], |
||
6899 | ]; |
||
6900 | $myPicture->drawScale($scaleSettings); |
||
6901 | |||
6902 | /* Turn on shadow computing */ |
||
6903 | $myPicture->setShadow( |
||
6904 | true, |
||
6905 | [ |
||
6906 | 'X' => 1, |
||
6907 | 'Y' => 1, |
||
6908 | 'R' => 0, |
||
6909 | 'G' => 0, |
||
6910 | 'B' => 0, |
||
6911 | 'Alpha' => 10, |
||
6912 | ] |
||
6913 | ); |
||
6914 | |||
6915 | /* Draw the chart */ |
||
6916 | $myPicture->setShadow( |
||
6917 | true, |
||
6918 | [ |
||
6919 | 'X' => 1, |
||
6920 | 'Y' => 1, |
||
6921 | 'R' => 0, |
||
6922 | 'G' => 0, |
||
6923 | 'B' => 0, |
||
6924 | 'Alpha' => 10, |
||
6925 | ] |
||
6926 | ); |
||
6927 | $settings = [ |
||
6928 | 'DisplayValues' => true, |
||
6929 | 'DisplaySize' => $fontSize, |
||
6930 | 'DisplayR' => 0, |
||
6931 | 'DisplayG' => 0, |
||
6932 | 'DisplayB' => 0, |
||
6933 | 'DisplayOrientation' => ORIENTATION_HORIZONTAL, |
||
6934 | 'Gradient' => false, |
||
6935 | 'Surrounding' => 5, |
||
6936 | 'InnerSurrounding' => 5, |
||
6937 | ]; |
||
6938 | $myPicture->drawStackedBarChart($settings); |
||
6939 | |||
6940 | /* Save and write in cache */ |
||
6941 | $myCache->writeToCache($chartHash, $myPicture); |
||
6942 | $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash; |
||
6943 | $myCache->saveFromCache($chartHash, $imgPath); |
||
6944 | $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash; |
||
6945 | } |
||
6946 | |||
6947 | return $imgPath; |
||
6948 | } |
||
6949 | |||
6950 | /** |
||
6951 | * Generates a big graph with the number of best results. |
||
6952 | * |
||
6953 | * @param array |
||
6954 | */ |
||
6955 | public static function generate_exercise_result_graph($attempts) |
||
6956 | { |
||
6957 | $exercise_title = strip_tags($attempts['title']); |
||
6958 | $attempts = $attempts['data']; |
||
6959 | $my_exercise_result_array = $exercise_result = []; |
||
6960 | if (empty($attempts)) { |
||
6961 | return null; |
||
6962 | } |
||
6963 | foreach ($attempts as $attempt) { |
||
6964 | if (api_get_user_id() == $attempt['exe_user_id']) { |
||
6965 | if ($attempt['exe_weighting'] != 0) { |
||
6966 | $my_exercise_result_array[] = $attempt['exe_result'] / $attempt['exe_weighting']; |
||
6967 | } |
||
6968 | } else { |
||
6969 | if ($attempt['exe_weighting'] != 0) { |
||
6970 | $exercise_result[] = $attempt['exe_result'] / $attempt['exe_weighting']; |
||
6971 | } |
||
6972 | } |
||
6973 | } |
||
6974 | |||
6975 | // Getting best result |
||
6976 | rsort($my_exercise_result_array); |
||
6977 | $my_exercise_result = 0; |
||
6978 | if (isset($my_exercise_result_array[0])) { |
||
6979 | $my_exercise_result = $my_exercise_result_array[0] * 100; |
||
6980 | } |
||
6981 | |||
6982 | $max = 100; |
||
6983 | $pieces = 5; |
||
6984 | $part = round($max / $pieces); |
||
6985 | $x_axis = []; |
||
6986 | $final_array = []; |
||
6987 | $my_final_array = []; |
||
6988 | |||
6989 | for ($i = 1; $i <= $pieces; $i++) { |
||
6990 | $sum = 1; |
||
6991 | if ($i == 1) { |
||
6992 | $sum = 0; |
||
6993 | } |
||
6994 | $min = ($i - 1) * $part + $sum; |
||
6995 | $max = $i * $part; |
||
6996 | $x_axis[] = $min." - ".$max; |
||
6997 | $count = 0; |
||
6998 | foreach ($exercise_result as $result) { |
||
6999 | $percentage = $result * 100; |
||
7000 | if ($percentage >= $min && $percentage <= $max) { |
||
7001 | $count++; |
||
7002 | } |
||
7003 | } |
||
7004 | $final_array[] = $count; |
||
7005 | |||
7006 | if ($my_exercise_result >= $min && $my_exercise_result <= $max) { |
||
7007 | $my_final_array[] = 1; |
||
7008 | } else { |
||
7009 | $my_final_array[] = 0; |
||
7010 | } |
||
7011 | } |
||
7012 | |||
7013 | // Fix to remove the data of the user with my data |
||
7014 | |||
7015 | for ($i = 0; $i <= count($my_final_array); $i++) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
7016 | if (!empty($my_final_array[$i])) { |
||
7017 | $my_final_array[$i] = $final_array[$i] + 1; // Add my result |
||
7018 | $final_array[$i] = 0; |
||
7019 | } |
||
7020 | } |
||
7021 | |||
7022 | // Dataset definition |
||
7023 | $dataSet = new pData(); |
||
7024 | $dataSet->addPoints($final_array, 'Serie1'); |
||
7025 | $dataSet->addPoints($my_final_array, 'Serie2'); |
||
7026 | $dataSet->addPoints($x_axis, 'Serie3'); |
||
7027 | |||
7028 | $dataSet->setSerieDescription('Serie1', get_lang('Score')); |
||
7029 | $dataSet->setSerieDescription('Serie2', get_lang('MyResults')); |
||
7030 | $dataSet->setAbscissa('Serie3'); |
||
7031 | |||
7032 | $dataSet->setXAxisName(get_lang('Score')); |
||
7033 | $dataSet->normalize(100, "%"); |
||
7034 | |||
7035 | $dataSet->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true); |
||
7036 | |||
7037 | // Cache definition |
||
7038 | $cachePath = api_get_path(SYS_ARCHIVE_PATH); |
||
7039 | $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]); |
||
7040 | $chartHash = $myCache->getHash($dataSet); |
||
7041 | |||
7042 | if ($myCache->isInCache($chartHash)) { |
||
7043 | $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash; |
||
7044 | $myCache->saveFromCache($chartHash, $imgPath); |
||
7045 | $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash; |
||
7046 | } else { |
||
7047 | /* Create the pChart object */ |
||
7048 | $widthSize = 480; |
||
7049 | $heightSize = 250; |
||
7050 | $fontSize = 8; |
||
7051 | $myPicture = new pImage($widthSize, $heightSize, $dataSet); |
||
7052 | |||
7053 | /* Turn of Antialiasing */ |
||
7054 | $myPicture->Antialias = false; |
||
7055 | |||
7056 | /* Add a border to the picture */ |
||
7057 | $myPicture->drawRectangle(0, 0, $widthSize - 1, $heightSize - 1, ['R' => 0, 'G' => 0, 'B' => 0]); |
||
7058 | |||
7059 | /* Set the default font */ |
||
7060 | $myPicture->setFontProperties( |
||
7061 | [ |
||
7062 | 'FontName' => api_get_path( |
||
7063 | SYS_FONTS_PATH |
||
7064 | ).'opensans/OpenSans-Regular.ttf', |
||
7065 | 'FontSize' => 10, |
||
7066 | ] |
||
7067 | ); |
||
7068 | |||
7069 | /* Write the chart title */ |
||
7070 | $myPicture->drawText( |
||
7071 | 250, |
||
7072 | 20, |
||
7073 | $exercise_title, |
||
7074 | [ |
||
7075 | 'FontSize' => 12, |
||
7076 | 'Align' => TEXT_ALIGN_BOTTOMMIDDLE, |
||
7077 | ] |
||
7078 | ); |
||
7079 | |||
7080 | /* Define the chart area */ |
||
7081 | $myPicture->setGraphArea(50, 50, $widthSize - 20, $heightSize - 30); |
||
7082 | |||
7083 | /* Draw the scale */ |
||
7084 | $scaleSettings = [ |
||
7085 | 'GridR' => 200, |
||
7086 | 'GridG' => 200, |
||
7087 | 'GridB' => 200, |
||
7088 | 'DrawSubTicks' => true, |
||
7089 | 'CycleBackground' => true, |
||
7090 | 'Mode' => SCALE_MODE_MANUAL, |
||
7091 | 'ManualScale' => [ |
||
7092 | '0' => [ |
||
7093 | 'Min' => 0, |
||
7094 | 'Max' => 100, |
||
7095 | ], |
||
7096 | ], |
||
7097 | ]; |
||
7098 | $myPicture->drawScale($scaleSettings); |
||
7099 | |||
7100 | /* Turn on shadow computing */ |
||
7101 | $myPicture->setShadow(true, ['X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10]); |
||
7102 | |||
7103 | /* Draw the chart */ |
||
7104 | $myPicture->setShadow(true, ['X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10]); |
||
7105 | $settings = [ |
||
7106 | 'DisplayValues' => true, |
||
7107 | 'DisplaySize' => $fontSize, |
||
7108 | 'DisplayR' => 0, |
||
7109 | 'DisplayG' => 0, |
||
7110 | 'DisplayB' => 0, |
||
7111 | 'DisplayOrientation' => ORIENTATION_HORIZONTAL, |
||
7112 | 'Gradient' => false, |
||
7113 | 'Surrounding' => 30, |
||
7114 | 'InnerSurrounding' => 25, |
||
7115 | ]; |
||
7116 | $myPicture->drawStackedBarChart($settings); |
||
7117 | |||
7118 | $legendSettings = [ |
||
7119 | 'Mode' => LEGEND_HORIZONTAL, |
||
7120 | 'Style' => LEGEND_NOBORDER, |
||
7121 | ]; |
||
7122 | $myPicture->drawLegend($widthSize / 2, 30, $legendSettings); |
||
7123 | |||
7124 | /* Write and save into cache */ |
||
7125 | $myCache->writeToCache($chartHash, $myPicture); |
||
7126 | $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash; |
||
7127 | $myCache->saveFromCache($chartHash, $imgPath); |
||
7128 | $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash; |
||
7129 | } |
||
7130 | |||
7131 | return $imgPath; |
||
7132 | } |
||
7133 | |||
7134 | /** |
||
7135 | * @param FormValidator $form |
||
7136 | */ |
||
7137 | public static function setUserSearchForm($form, $displayExtraFields = false) |
||
7138 | { |
||
7139 | global $_configuration; |
||
7140 | $form->addElement('text', 'keyword', get_lang('Keyword')); |
||
7141 | $form->addElement( |
||
7142 | 'select', |
||
7143 | 'active', |
||
7144 | get_lang('Status'), |
||
7145 | [1 => get_lang('Active'), 0 => get_lang('Inactive')] |
||
7146 | ); |
||
7147 | |||
7148 | $form->addElement( |
||
7149 | 'select', |
||
7150 | 'sleeping_days', |
||
7151 | get_lang('InactiveDays'), |
||
7152 | [ |
||
7153 | '', |
||
7154 | 1 => 1, |
||
7155 | 5 => 5, |
||
7156 | 15 => 15, |
||
7157 | 30 => 30, |
||
7158 | 60 => 60, |
||
7159 | 90 => 90, |
||
7160 | 120 => 120, |
||
7161 | ] |
||
7162 | ); |
||
7163 | |||
7164 | if ($displayExtraFields) { |
||
7165 | $extraField = new ExtraField('user'); |
||
7166 | $extraField->addElements($form, 0, [], true, false, [], [], [], false, true); |
||
7167 | } |
||
7168 | |||
7169 | $form->addButtonSearch(get_lang('Search')); |
||
7170 | |||
7171 | return $form; |
||
7172 | } |
||
7173 | |||
7174 | /** |
||
7175 | * Get the progress of a exercise. |
||
7176 | * |
||
7177 | * @param int $sessionId The session ID (session.id) |
||
7178 | * @param int $courseId The course ID (course.id) |
||
7179 | * @param int $exerciseId The quiz ID (c_quiz.id) |
||
7180 | * @param string $date_from |
||
7181 | * @param string $date_to |
||
7182 | * @param array $options An array of options you can pass to the query (limit, where and order) |
||
7183 | * |
||
7184 | * @return array An array with the data of exercise(s) progress |
||
7185 | */ |
||
7186 | public static function get_exercise_progress( |
||
7187 | $sessionId = 0, |
||
7188 | $courseId = 0, |
||
7189 | $exerciseId = 0, |
||
7190 | $date_from = null, |
||
7191 | $date_to = null, |
||
7192 | $options = [] |
||
7193 | ) { |
||
7194 | $sessionId = intval($sessionId); |
||
7195 | $courseId = intval($courseId); |
||
7196 | $exerciseId = intval($exerciseId); |
||
7197 | $date_from = Database::escape_string($date_from); |
||
7198 | $date_to = Database::escape_string($date_to); |
||
7199 | /* |
||
7200 | * This method gets the data by blocks, as previous attempts at one single |
||
7201 | * query made it take ages. The logic of query division is described below |
||
7202 | */ |
||
7203 | // Get tables names |
||
7204 | $tuser = Database::get_main_table(TABLE_MAIN_USER); |
||
7205 | $tquiz = Database::get_course_table(TABLE_QUIZ_TEST); |
||
7206 | $tquiz_answer = Database::get_course_table(TABLE_QUIZ_ANSWER); |
||
7207 | $tquiz_question = Database::get_course_table(TABLE_QUIZ_QUESTION); |
||
7208 | $tquiz_rel_question = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION); |
||
7209 | $ttrack_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
7210 | $ttrack_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
7211 | |||
7212 | $sessions = []; |
||
7213 | $courses = []; |
||
7214 | // if session ID is defined but course ID is empty, get all the courses |
||
7215 | // from that session |
||
7216 | if (!empty($sessionId) && empty($courseId)) { |
||
7217 | // $courses is an array of course int id as index and course details hash as value |
||
7218 | $courses = SessionManager::get_course_list_by_session_id($sessionId); |
||
7219 | $sessions[$sessionId] = api_get_session_info($sessionId); |
||
7220 | } elseif (empty($sessionId) && !empty($courseId)) { |
||
7221 | // if, to the contrary, course is defined but not sessions, get the sessions that include this course |
||
7222 | // $sessions is an array like: [0] => ('id' => 3, 'name' => 'Session 35'), [1] => () etc; |
||
7223 | $course = api_get_course_info_by_id($courseId); |
||
7224 | $sessionsTemp = SessionManager::get_session_by_course($courseId); |
||
7225 | $courses[$courseId] = $course; |
||
7226 | foreach ($sessionsTemp as $sessionItem) { |
||
7227 | $sessions[$sessionItem['id']] = $sessionItem; |
||
7228 | } |
||
7229 | } elseif (!empty($courseId) && !empty($sessionId)) { |
||
7230 | // none is empty |
||
7231 | $course = api_get_course_info_by_id($courseId); |
||
7232 | $courses[$courseId] = [$course['code']]; |
||
7233 | $courses[$courseId]['code'] = $course['code']; |
||
7234 | $sessions[$sessionId] = api_get_session_info($sessionId); |
||
7235 | } else { |
||
7236 | // both are empty, not enough data, return an empty array |
||
7237 | return []; |
||
7238 | } |
||
7239 | // Now we have two arrays of courses and sessions with enough data to proceed |
||
7240 | // If no course could be found, we shouldn't return anything. |
||
7241 | // Sessions can be empty (then we only return the pure-course-context results) |
||
7242 | if (count($courses) < 1) { |
||
7243 | return []; |
||
7244 | } |
||
7245 | |||
7246 | $data = []; |
||
7247 | // The following loop is less expensive than what it seems: |
||
7248 | // - if a course was defined, then we only loop through sessions |
||
7249 | // - if a session was defined, then we only loop through courses |
||
7250 | // - if a session and a course were defined, then we only loop once |
||
7251 | foreach ($courses as $courseIdx => $courseData) { |
||
7252 | $where = ''; |
||
7253 | $whereParams = []; |
||
7254 | $whereSessionParams = ''; |
||
7255 | if (count($sessions > 0)) { |
||
7256 | foreach ($sessions as $sessionIdx => $sessionData) { |
||
7257 | if (!empty($sessionIdx)) { |
||
7258 | $whereSessionParams .= $sessionIdx.','; |
||
7259 | } |
||
7260 | } |
||
7261 | $whereSessionParams = substr($whereSessionParams, 0, -1); |
||
7262 | } |
||
7263 | |||
7264 | if (!empty($exerciseId)) { |
||
7265 | $exerciseId = intval($exerciseId); |
||
7266 | $where .= ' AND q.id = %d '; |
||
7267 | $whereParams[] = $exerciseId; |
||
7268 | } |
||
7269 | |||
7270 | /* |
||
7271 | * This feature has been disabled for now, to avoid having to |
||
7272 | * join two very large tables |
||
7273 | //2 = show all questions (wrong and correct answered) |
||
7274 | if ($answer != 2) { |
||
7275 | $answer = intval($answer); |
||
7276 | //$where .= ' AND qa.correct = %d'; |
||
7277 | //$whereParams[] = $answer; |
||
7278 | } |
||
7279 | */ |
||
7280 | |||
7281 | $limit = ''; |
||
7282 | if (!empty($options['limit'])) { |
||
7283 | $limit = " LIMIT ".$options['limit']; |
||
7284 | } |
||
7285 | |||
7286 | if (!empty($options['where'])) { |
||
7287 | $where .= ' AND '.Database::escape_string($options['where']); |
||
7288 | } |
||
7289 | |||
7290 | $order = ''; |
||
7291 | if (!empty($options['order'])) { |
||
7292 | $order = " ORDER BY ".$options['order']; |
||
7293 | } |
||
7294 | |||
7295 | if (!empty($date_to) && !empty($date_from)) { |
||
7296 | $where .= sprintf(" AND (te.start_date BETWEEN '%s 00:00:00' AND '%s 23:59:59')", $date_from, $date_to); |
||
7297 | } |
||
7298 | |||
7299 | $sql = "SELECT |
||
7300 | te.session_id, |
||
7301 | ta.id as attempt_id, |
||
7302 | te.exe_user_id as user_id, |
||
7303 | te.exe_id as exercise_attempt_id, |
||
7304 | ta.question_id, |
||
7305 | ta.answer as answer_id, |
||
7306 | ta.tms as time, |
||
7307 | te.exe_exo_id as quiz_id, |
||
7308 | CONCAT ('c', q.c_id, '_e', q.iid) as exercise_id, |
||
7309 | q.title as quiz_title, |
||
7310 | qq.description as description |
||
7311 | FROM $ttrack_exercises te |
||
7312 | INNER JOIN $ttrack_attempt ta |
||
7313 | ON ta.exe_id = te.exe_id |
||
7314 | INNER JOIN $tquiz q |
||
7315 | ON q.iid = te.exe_exo_id |
||
7316 | INNER JOIN $tquiz_rel_question rq |
||
7317 | ON rq.exercice_id = q.iid AND rq.c_id = q.c_id |
||
7318 | INNER JOIN $tquiz_question qq |
||
7319 | ON |
||
7320 | qq.iid = rq.question_id AND |
||
7321 | qq.position = rq.question_order AND |
||
7322 | ta.question_id = rq.question_id |
||
7323 | WHERE |
||
7324 | te.c_id = $courseIdx ".(empty($whereSessionParams) ? '' : "AND te.session_id IN ($whereSessionParams)")." |
||
7325 | AND q.c_id = $courseIdx |
||
7326 | $where $order $limit"; |
||
7327 | $sql_query = vsprintf($sql, $whereParams); |
||
7328 | |||
7329 | // Now browse through the results and get the data |
||
7330 | $rs = Database::query($sql_query); |
||
7331 | $userIds = []; |
||
7332 | $questionIds = []; |
||
7333 | $answerIds = []; |
||
7334 | while ($row = Database::fetch_array($rs)) { |
||
7335 | // only show if exercise is visible |
||
7336 | if (api_get_item_visibility($courseData, 'quiz', $row['exercise_id'])) { |
||
7337 | $userIds[$row['user_id']] = $row['user_id']; |
||
7338 | $questionIds[$row['question_id']] = $row['question_id']; |
||
7339 | $answerIds[$row['question_id']][$row['answer_id']] = $row['answer_id']; |
||
7340 | $row['session'] = $sessions[$row['session_id']]; |
||
7341 | $data[] = $row; |
||
7342 | } |
||
7343 | } |
||
7344 | // Now fill questions data. Query all questions and answers for this test to avoid |
||
7345 | $sqlQuestions = "SELECT tq.c_id, tq.iid as question_id, tq.question, tqa.id_auto, |
||
7346 | tqa.answer, tqa.correct, tq.position, tqa.id_auto as answer_id |
||
7347 | FROM $tquiz_question tq, $tquiz_answer tqa |
||
7348 | WHERE |
||
7349 | tqa.question_id = tq.iid AND |
||
7350 | tq.c_id = $courseIdx AND |
||
7351 | tq.id IN (".implode(',', $questionIds).")"; |
||
7352 | |||
7353 | $resQuestions = Database::query($sqlQuestions); |
||
7354 | $answer = []; |
||
7355 | $question = []; |
||
7356 | while ($rowQuestion = Database::fetch_assoc($resQuestions)) { |
||
7357 | $questionId = $rowQuestion['question_id']; |
||
7358 | $answerId = $rowQuestion['answer_id']; |
||
7359 | $answer[$questionId][$answerId] = [ |
||
7360 | 'position' => $rowQuestion['position'], |
||
7361 | 'question' => $rowQuestion['question'], |
||
7362 | 'answer' => $rowQuestion['answer'], |
||
7363 | 'correct' => $rowQuestion['correct'], |
||
7364 | ]; |
||
7365 | $question[$questionId]['question'] = $rowQuestion['question']; |
||
7366 | } |
||
7367 | |||
7368 | // Now fill users data |
||
7369 | $sqlUsers = "SELECT user_id, username, lastname, firstname |
||
7370 | FROM $tuser |
||
7371 | WHERE user_id IN (".implode(',', $userIds).")"; |
||
7372 | $resUsers = Database::query($sqlUsers); |
||
7373 | while ($rowUser = Database::fetch_assoc($resUsers)) { |
||
7374 | $users[$rowUser['user_id']] = $rowUser; |
||
7375 | } |
||
7376 | |||
7377 | foreach ($data as $id => $row) { |
||
7378 | $rowQuestId = $row['question_id']; |
||
7379 | $rowAnsId = $row['answer_id']; |
||
7380 | $data[$id]['session'] = $sessions[$row['session_id']]['name']; |
||
7381 | $data[$id]['firstname'] = $users[$row['user_id']]['firstname']; |
||
7382 | $data[$id]['lastname'] = $users[$row['user_id']]['lastname']; |
||
7383 | $data[$id]['username'] = $users[$row['user_id']]['username']; |
||
7384 | $data[$id]['answer'] = $answer[$rowQuestId][$rowAnsId]['answer']; |
||
7385 | $data[$id]['correct'] = ($answer[$rowQuestId][$rowAnsId]['correct'] == 0 ? get_lang('No') : get_lang('Yes')); |
||
7386 | $data[$id]['question'] = $question[$rowQuestId]['question']; |
||
7387 | $data[$id]['question_id'] = $rowQuestId; |
||
7388 | $data[$id]['description'] = $row['description']; |
||
7389 | } |
||
7390 | |||
7391 | /* |
||
7392 | The minimum expected array structure at the end is: |
||
7393 | attempt_id, |
||
7394 | session name, |
||
7395 | exercise_id, |
||
7396 | quiz_title, |
||
7397 | username, |
||
7398 | lastname, |
||
7399 | firstname, |
||
7400 | time, |
||
7401 | question_id, |
||
7402 | question, |
||
7403 | answer, |
||
7404 | */ |
||
7405 | } |
||
7406 | |||
7407 | return $data; |
||
7408 | } |
||
7409 | |||
7410 | /** |
||
7411 | * @param string $tool |
||
7412 | * @param sessionEntity|null $session Optional |
||
7413 | * |
||
7414 | * @throws \Doctrine\ORM\NonUniqueResultException |
||
7415 | * |
||
7416 | * @return \Chamilo\CourseBundle\Entity\CStudentPublication|null |
||
7417 | */ |
||
7418 | public static function getLastStudentPublication( |
||
7419 | User $user, |
||
7420 | $tool, |
||
7421 | Course $course, |
||
7422 | SessionEntity $session = null |
||
7423 | ) { |
||
7424 | return Database::getManager() |
||
7425 | ->createQuery(" |
||
7426 | SELECT csp |
||
7427 | FROM ChamiloCourseBundle:CStudentPublication csp |
||
7428 | INNER JOIN ChamiloCourseBundle:CItemProperty cip |
||
7429 | WITH ( |
||
7430 | csp.iid = cip.ref AND |
||
7431 | csp.session = cip.session AND |
||
7432 | csp.cId = cip.course AND |
||
7433 | csp.userId = cip.lasteditUserId |
||
7434 | ) |
||
7435 | WHERE |
||
7436 | cip.session = :session AND cip.course = :course AND cip.lasteditUserId = :user AND cip.tool = :tool |
||
7437 | ORDER BY csp.iid DESC |
||
7438 | ") |
||
7439 | ->setMaxResults(1) |
||
7440 | ->setParameters([ |
||
7441 | 'tool' => $tool, |
||
7442 | 'session' => $session, |
||
7443 | 'course' => $course, |
||
7444 | 'user' => $user, |
||
7445 | ]) |
||
7446 | ->getOneOrNullResult(); |
||
7447 | } |
||
7448 | |||
7449 | /** |
||
7450 | * Get the HTML code for show a block with the achieved user skill on course/session. |
||
7451 | * |
||
7452 | * @param int $userId |
||
7453 | * @param int $courseId |
||
7454 | * @param int $sessionId |
||
7455 | * @param bool $forceView forces the view of the skills, not checking for deeper access |
||
7456 | * |
||
7457 | * @return string |
||
7458 | */ |
||
7459 | public static function displayUserSkills($userId, $courseId = 0, $sessionId = 0, $forceView = false) |
||
7460 | { |
||
7461 | if (Skill::isAllowed($userId, false) === false && $forceView == false) { |
||
7462 | return ''; |
||
7463 | } |
||
7464 | $skillManager = new Skill(); |
||
7465 | $html = $skillManager->getUserSkillsTable($userId, $courseId, $sessionId)['table']; |
||
7466 | |||
7467 | return $html; |
||
7468 | } |
||
7469 | |||
7470 | /** |
||
7471 | * @param int $userId |
||
7472 | * @param int $courseId |
||
7473 | * @param int $sessionId |
||
7474 | * |
||
7475 | * @return array |
||
7476 | */ |
||
7477 | public static function getCalculateTime($userId, $courseId, $sessionId) |
||
7478 | { |
||
7479 | $userId = (int) $userId; |
||
7480 | $courseId = (int) $courseId; |
||
7481 | $sessionId = (int) $sessionId; |
||
7482 | |||
7483 | if (empty($userId) || empty($courseId)) { |
||
7484 | return []; |
||
7485 | } |
||
7486 | |||
7487 | $sql = "SELECT MIN(date_reg) min, MAX(date_reg) max |
||
7488 | FROM track_e_access_complete |
||
7489 | WHERE |
||
7490 | user_id = $userId AND |
||
7491 | c_id = $courseId AND |
||
7492 | session_id = $sessionId AND |
||
7493 | login_as = 0 |
||
7494 | ORDER BY date_reg ASC |
||
7495 | LIMIT 1"; |
||
7496 | $rs = Database::query($sql); |
||
7497 | |||
7498 | $firstConnection = ''; |
||
7499 | $lastConnection = ''; |
||
7500 | if (Database::num_rows($rs) > 0) { |
||
7501 | $value = Database::fetch_array($rs); |
||
7502 | $firstConnection = $value['min']; |
||
7503 | $lastConnection = $value['max']; |
||
7504 | } |
||
7505 | |||
7506 | $sql = "SELECT * FROM track_e_access_complete |
||
7507 | WHERE |
||
7508 | user_id = $userId AND |
||
7509 | c_id = $courseId AND |
||
7510 | session_id = $sessionId AND |
||
7511 | login_as = 0 AND current_id <> 0"; |
||
7512 | |||
7513 | $res = Database::query($sql); |
||
7514 | $reg = []; |
||
7515 | while ($row = Database::fetch_assoc($res)) { |
||
7516 | $reg[$row['id']] = $row; |
||
7517 | $reg[$row['id']]['date_reg'] = strtotime($row['date_reg']); |
||
7518 | } |
||
7519 | |||
7520 | $sessions = []; |
||
7521 | foreach ($reg as $key => $value) { |
||
7522 | $sessions[$value['current_id']][$value['tool']][] = $value; |
||
7523 | } |
||
7524 | |||
7525 | $quizTime = 0; |
||
7526 | $result = []; |
||
7527 | $totalTime = 0; |
||
7528 | $lpTime = []; |
||
7529 | $lpDetailTime = []; |
||
7530 | foreach ($sessions as $listPerTool) { |
||
7531 | $min = 0; |
||
7532 | $max = 0; |
||
7533 | $sessionDiff = 0; |
||
7534 | foreach ($listPerTool as $tool => $results) { |
||
7535 | $beforeItem = []; |
||
7536 | foreach ($results as $item) { |
||
7537 | if (empty($beforeItem)) { |
||
7538 | $beforeItem = $item; |
||
7539 | if (empty($min)) { |
||
7540 | $min = $item['date_reg']; |
||
7541 | } |
||
7542 | |||
7543 | if (empty($max)) { |
||
7544 | $max = $item['date_reg']; |
||
7545 | } |
||
7546 | continue; |
||
7547 | } |
||
7548 | |||
7549 | $partialTime = $item['date_reg'] - $beforeItem['date_reg']; |
||
7550 | if ($item['date_reg'] > $max) { |
||
7551 | $max = $item['date_reg']; |
||
7552 | } |
||
7553 | |||
7554 | if (empty($min)) { |
||
7555 | $min = $item['date_reg']; |
||
7556 | } |
||
7557 | |||
7558 | if ($item['date_reg'] < $min) { |
||
7559 | $min = $item['date_reg']; |
||
7560 | } |
||
7561 | |||
7562 | switch ($tool) { |
||
7563 | case TOOL_AGENDA: |
||
7564 | case TOOL_FORUM: |
||
7565 | case TOOL_ANNOUNCEMENT: |
||
7566 | case TOOL_COURSE_DESCRIPTION: |
||
7567 | case TOOL_SURVEY: |
||
7568 | case TOOL_NOTEBOOK: |
||
7569 | case TOOL_GRADEBOOK: |
||
7570 | case TOOL_DROPBOX: |
||
7571 | case 'Reports': |
||
7572 | case 'Videoconference': |
||
7573 | case TOOL_LINK: |
||
7574 | case TOOL_CHAT: |
||
7575 | case 'course-main': |
||
7576 | if (!isset($result[$tool])) { |
||
7577 | $result[$tool] = 0; |
||
7578 | } |
||
7579 | $result[$tool] += $partialTime; |
||
7580 | break; |
||
7581 | case TOOL_LEARNPATH: |
||
7582 | if ($item['tool_id'] != $beforeItem['tool_id']) { |
||
7583 | break; |
||
7584 | } |
||
7585 | if (!isset($lpTime[$item['tool_id']])) { |
||
7586 | $lpTime[$item['tool_id']] = 0; |
||
7587 | } |
||
7588 | |||
7589 | // Saving the attempt id "action_details" |
||
7590 | if (!empty($item['tool_id'])) { |
||
7591 | if (!empty($item['tool_id_detail'])) { |
||
7592 | if (!isset($lpDetailTime[$item['tool_id']][$item['tool_id_detail']][$item['action_details']])) { |
||
7593 | $lpDetailTime[$item['tool_id']][$item['tool_id_detail']][$item['action_details']] = 0; |
||
7594 | } |
||
7595 | $lpDetailTime[$item['tool_id']][$item['tool_id_detail']][$item['action_details']] += $partialTime; |
||
7596 | } |
||
7597 | $lpTime[$item['tool_id']] += $partialTime; |
||
7598 | } |
||
7599 | break; |
||
7600 | case TOOL_QUIZ: |
||
7601 | if (!isset($lpTime[$item['action_details']])) { |
||
7602 | $lpTime[$item['action_details']] = 0; |
||
7603 | } |
||
7604 | if ($beforeItem['action'] === 'learnpath_id') { |
||
7605 | $lpTime[$item['action_details']] += $partialTime; |
||
7606 | } else { |
||
7607 | $quizTime += $partialTime; |
||
7608 | } |
||
7609 | break; |
||
7610 | } |
||
7611 | $beforeItem = $item; |
||
7612 | } |
||
7613 | } |
||
7614 | |||
7615 | $sessionDiff += $max - $min; |
||
7616 | if ($sessionDiff > 0) { |
||
7617 | $totalTime += $sessionDiff; |
||
7618 | } |
||
7619 | } |
||
7620 | |||
7621 | $totalLp = 0; |
||
7622 | foreach ($lpTime as $value) { |
||
7623 | $totalLp += $value; |
||
7624 | } |
||
7625 | |||
7626 | $result['learnpath_detailed'] = $lpDetailTime; |
||
7627 | $result[TOOL_LEARNPATH] = $lpTime; |
||
7628 | $result[TOOL_QUIZ] = $quizTime; |
||
7629 | $result['total_learnpath'] = $totalLp; |
||
7630 | $result['total_time'] = $totalTime; |
||
7631 | $result['number_connections'] = count($sessions); |
||
7632 | $result['first'] = $firstConnection; |
||
7633 | $result['last'] = $lastConnection; |
||
7634 | |||
7635 | return $result; |
||
7636 | } |
||
7637 | |||
7638 | /** |
||
7639 | * Gets the IP of a given user, using the last login before the given date. |
||
7640 | * |
||
7641 | * @param int User ID |
||
7642 | * @param string Datetime |
||
7643 | * @param bool Whether to return the IP as a link or just as an IP |
||
7644 | * @param string If defined and return_as_link if true, will be used as the text to be shown as the link |
||
7645 | * |
||
7646 | * @return string IP address (or false on error) |
||
7647 | * |
||
7648 | * @assert (0,0) === false |
||
7649 | */ |
||
7650 | public static function get_ip_from_user_event( |
||
7651 | $user_id, |
||
7652 | $event_date, |
||
7653 | $return_as_link = false, |
||
7654 | $body_replace = null |
||
7655 | ) { |
||
7656 | if (empty($user_id) || empty($event_date)) { |
||
7657 | return false; |
||
7658 | } |
||
7659 | $user_id = intval($user_id); |
||
7660 | $event_date = Database::escape_string($event_date); |
||
7661 | $table_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN); |
||
7662 | $sql_ip = "SELECT login_date, user_ip |
||
7663 | FROM $table_login |
||
7664 | WHERE login_user_id = $user_id AND login_date < '$event_date' |
||
7665 | ORDER BY login_date DESC LIMIT 1"; |
||
7666 | $ip = ''; |
||
7667 | $res_ip = Database::query($sql_ip); |
||
7668 | if ($res_ip !== false && Database::num_rows($res_ip) > 0) { |
||
7669 | $row_ip = Database::fetch_row($res_ip); |
||
7670 | if ($return_as_link) { |
||
7671 | $ip = Display::url( |
||
7672 | empty($body_replace) ? $row_ip[1] : $body_replace, |
||
7673 | 'http://www.whatsmyip.org/ip-geo-location/?ip='.$row_ip[1], |
||
7674 | ['title' => get_lang('TraceIP'), 'target' => '_blank'] |
||
7675 | ); |
||
7676 | } else { |
||
7677 | $ip = $row_ip[1]; |
||
7678 | } |
||
7679 | } |
||
7680 | |||
7681 | return $ip; |
||
7682 | } |
||
7683 | |||
7684 | /** |
||
7685 | * @param int $userId |
||
7686 | * @param array $courseInfo |
||
7687 | * @param int $sessionId |
||
7688 | * |
||
7689 | * @return array |
||
7690 | */ |
||
7691 | public static function getToolInformation( |
||
7692 | $userId, |
||
7693 | $courseInfo, |
||
7694 | $sessionId = 0 |
||
7695 | ) { |
||
7696 | $csvContent = []; |
||
7697 | $courseToolInformation = ''; |
||
7698 | $headerTool = [ |
||
7699 | [get_lang('Title')], |
||
7700 | [get_lang('CreatedAt')], |
||
7701 | [get_lang('UpdatedAt')], |
||
7702 | ]; |
||
7703 | |||
7704 | $headerListForCSV = []; |
||
7705 | foreach ($headerTool as $item) { |
||
7706 | $headerListForCSV[] = $item[0]; |
||
7707 | } |
||
7708 | |||
7709 | $courseForumInformationArray = getForumCreatedByUser( |
||
7710 | $userId, |
||
7711 | $courseInfo, |
||
7712 | $sessionId |
||
7713 | ); |
||
7714 | |||
7715 | if (!empty($courseForumInformationArray)) { |
||
7716 | $csvContent[] = []; |
||
7717 | $csvContent[] = [get_lang('Forums')]; |
||
7718 | $csvContent[] = $headerListForCSV; |
||
7719 | foreach ($courseForumInformationArray as $row) { |
||
7720 | $csvContent[] = $row; |
||
7721 | } |
||
7722 | |||
7723 | $courseToolInformation .= Display::page_subheader2( |
||
7724 | get_lang('Forums') |
||
7725 | ); |
||
7726 | $courseToolInformation .= Display::return_sortable_table( |
||
7727 | $headerTool, |
||
7728 | $courseForumInformationArray |
||
7729 | ); |
||
7730 | } |
||
7731 | |||
7732 | $courseWorkInformationArray = getWorkCreatedByUser( |
||
7733 | $userId, |
||
7734 | $courseInfo['real_id'], |
||
7735 | $sessionId |
||
7736 | ); |
||
7737 | |||
7738 | if (!empty($courseWorkInformationArray)) { |
||
7739 | $csvContent[] = null; |
||
7740 | $csvContent[] = [get_lang('Works')]; |
||
7741 | $csvContent[] = $headerListForCSV; |
||
7742 | |||
7743 | foreach ($courseWorkInformationArray as $row) { |
||
7744 | $csvContent[] = $row; |
||
7745 | } |
||
7746 | $csvContent[] = null; |
||
7747 | |||
7748 | $courseToolInformation .= Display::page_subheader2( |
||
7749 | get_lang('Works') |
||
7750 | ); |
||
7751 | $courseToolInformation .= Display::return_sortable_table( |
||
7752 | $headerTool, |
||
7753 | $courseWorkInformationArray |
||
7754 | ); |
||
7755 | } |
||
7756 | |||
7757 | $courseToolInformationTotal = null; |
||
7758 | if (!empty($courseToolInformation)) { |
||
7759 | $sessionTitle = null; |
||
7760 | if (!empty($sessionId)) { |
||
7761 | $sessionTitle = ' ('.api_get_session_name($sessionId).')'; |
||
7762 | } |
||
7763 | |||
7764 | $courseToolInformationTotal .= Display::page_subheader( |
||
7765 | $courseInfo['title'].$sessionTitle |
||
7766 | ); |
||
7767 | $courseToolInformationTotal .= $courseToolInformation; |
||
7768 | } |
||
7769 | |||
7770 | return [ |
||
7771 | 'array' => $csvContent, |
||
7772 | 'html' => $courseToolInformationTotal, |
||
7773 | ]; |
||
7774 | } |
||
7775 | |||
7776 | /** |
||
7777 | * @param int $sessionId |
||
7778 | * |
||
7779 | * @return bool |
||
7780 | */ |
||
7781 | public static function isAllowToTrack($sessionId) |
||
7782 | { |
||
7783 | return |
||
7784 | api_is_platform_admin(true, true) |
||
7785 | || SessionManager::user_is_general_coach(api_get_user_id(), $sessionId) |
||
7786 | || api_is_allowed_to_create_course() |
||
7787 | || api_is_course_tutor() |
||
7788 | || api_is_course_admin(); |
||
7789 | } |
||
7790 | |||
7791 | public static function getCourseLpProgress($userId, $sessionId) |
||
7792 | { |
||
7793 | $controller = new IndexManager(get_lang('MyCourses')); |
||
7794 | $data = $controller->returnCoursesAndSessions($userId); |
||
7795 | $courseList = $data['courses']; |
||
7796 | $result = []; |
||
7797 | if ($courseList) { |
||
7798 | // $counter = 1; |
||
7799 | foreach ($courseList as $course) { |
||
7800 | $courseId = $course['course_id']; |
||
7801 | $courseInfo = api_get_course_info_by_id($courseId); |
||
7802 | if (empty($courseInfo)) { |
||
7803 | continue; |
||
7804 | } |
||
7805 | $courseCode = $courseInfo['code']; |
||
7806 | $lpTimeList = self::getCalculateTime($userId, $courseId, $sessionId); |
||
7807 | |||
7808 | // total progress |
||
7809 | $list = new LearnpathList( |
||
7810 | $userId, |
||
7811 | $courseInfo, |
||
7812 | 0, |
||
7813 | 'lp.publicatedOn ASC', |
||
7814 | true, |
||
7815 | null, |
||
7816 | true |
||
7817 | ); |
||
7818 | |||
7819 | $list = $list->get_flat_list(); |
||
7820 | $totalProgress = 0; |
||
7821 | $totalTime = 0; |
||
7822 | if (!empty($list)) { |
||
7823 | foreach ($list as $lp_id => $learnpath) { |
||
7824 | if (!$learnpath['lp_visibility']) { |
||
7825 | continue; |
||
7826 | } |
||
7827 | $lpProgress = self::get_avg_student_progress($userId, $courseCode, [$lp_id], $sessionId); |
||
7828 | $time = isset($lpTimeList[TOOL_LEARNPATH][$lp_id]) ? $lpTimeList[TOOL_LEARNPATH][$lp_id] : 0; |
||
7829 | if ($lpProgress == 100) { |
||
7830 | if (!empty($time)) { |
||
7831 | $timeInMinutes = $time / 60; |
||
7832 | $min = (int) learnpath::getAccumulateWorkTimePrerequisite($lp_id, $courseId); |
||
7833 | if ($timeInMinutes >= $min) { |
||
7834 | $totalProgress++; |
||
7835 | } |
||
7836 | } |
||
7837 | } |
||
7838 | $totalTime += $time; |
||
7839 | } |
||
7840 | |||
7841 | if (!empty($totalProgress)) { |
||
7842 | $totalProgress = (float) api_number_format($totalProgress / count($list) * 100, 2); |
||
7843 | } |
||
7844 | } |
||
7845 | |||
7846 | $progress = self::get_avg_student_progress($userId, $courseCode, [], $sessionId); |
||
7847 | |||
7848 | $result[] = [ |
||
7849 | 'module' => $courseInfo['name'], |
||
7850 | 'progress' => $progress, |
||
7851 | 'qualification' => $totalProgress, |
||
7852 | 'activeTime' => $totalTime, |
||
7853 | ]; |
||
7854 | } |
||
7855 | } |
||
7856 | |||
7857 | return $result; |
||
7858 | } |
||
7859 | |||
7860 | /** |
||
7861 | * @param int $userId |
||
7862 | * @param int $courseId |
||
7863 | * @param int $sessionId |
||
7864 | * |
||
7865 | * @return int |
||
7866 | */ |
||
7867 | public static function getNumberOfCourseAccessDates($userId, $courseId, $sessionId) |
||
7868 | { |
||
7869 | $tblTrackCourseAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
7870 | $sessionCondition = api_get_session_condition($sessionId); |
||
7871 | $courseId = (int) $courseId; |
||
7872 | $userId = (int) $userId; |
||
7873 | |||
7874 | $sql = "SELECT COUNT(DISTINCT (DATE(login_course_date))) AS c |
||
7875 | FROM $tblTrackCourseAccess |
||
7876 | WHERE c_id = $courseId $sessionCondition AND user_id = $userId"; |
||
7877 | |||
7878 | $result = Database::fetch_assoc(Database::query($sql)); |
||
7879 | |||
7880 | return (int) $result['c']; |
||
7881 | } |
||
7882 | |||
7883 | public static function processUserDataMove( |
||
7884 | $user_id, |
||
7885 | $course_info, |
||
7886 | $origin_session_id, |
||
7887 | $new_session_id, |
||
7888 | $update_database, |
||
7889 | $debug = false |
||
7890 | ) { |
||
7891 | // Begin with the import process |
||
7892 | $origin_course_code = $course_info['code']; |
||
7893 | $course_id = $course_info['real_id']; |
||
7894 | $user_id = (int) $user_id; |
||
7895 | $origin_session_id = (int) $origin_session_id; |
||
7896 | $new_session_id = (int) $new_session_id; |
||
7897 | $session = api_get_session_entity($new_session_id); |
||
7898 | $em = Database::getManager(); |
||
7899 | |||
7900 | $TABLETRACK_EXERCICES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
7901 | $TBL_TRACK_ATTEMPT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
7902 | $attemptRecording = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING); |
||
7903 | $TBL_TRACK_E_COURSE_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
7904 | $TBL_TRACK_E_LAST_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS); |
||
7905 | $TBL_LP_VIEW = Database::get_course_table(TABLE_LP_VIEW); |
||
7906 | $TBL_NOTEBOOK = Database::get_course_table(TABLE_NOTEBOOK); |
||
7907 | $TBL_STUDENT_PUBLICATION = Database::get_course_table(TABLE_STUDENT_PUBLICATION); |
||
7908 | $TBL_STUDENT_PUBLICATION_ASSIGNMENT = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT); |
||
7909 | $TBL_ITEM_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY); |
||
7910 | |||
7911 | $TBL_DROPBOX_FILE = Database::get_course_table(TABLE_DROPBOX_FILE); |
||
7912 | $TBL_DROPBOX_POST = Database::get_course_table(TABLE_DROPBOX_POST); |
||
7913 | $TBL_AGENDA = Database::get_course_table(TABLE_AGENDA); |
||
7914 | |||
7915 | // 1. track_e_exercises |
||
7916 | // ORIGINAL COURSE |
||
7917 | $sql = "SELECT * FROM $TABLETRACK_EXERCICES |
||
7918 | WHERE c_id = $course_id AND session_id = $origin_session_id AND exe_user_id = $user_id "; |
||
7919 | $res = Database::query($sql); |
||
7920 | $list = []; |
||
7921 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
7922 | $list[$row['exe_id']] = $row; |
||
7923 | } |
||
7924 | |||
7925 | $result_message = []; |
||
7926 | $result_message_compare = []; |
||
7927 | if (!empty($list)) { |
||
7928 | foreach ($list as $exe_id => $data) { |
||
7929 | if ($update_database) { |
||
7930 | $sql = "UPDATE $TABLETRACK_EXERCICES SET session_id = '$new_session_id' WHERE exe_id = $exe_id"; |
||
7931 | Database::query($sql); |
||
7932 | |||
7933 | $sql = "UPDATE $TBL_TRACK_ATTEMPT SET session_id = '$new_session_id' WHERE exe_id = $exe_id"; |
||
7934 | Database::query($sql); |
||
7935 | |||
7936 | $sql = "UPDATE $attemptRecording SET session_id = '$new_session_id' WHERE exe_id = $exe_id"; |
||
7937 | Database::query($sql); |
||
7938 | |||
7939 | if (!isset($result_message[$TABLETRACK_EXERCICES])) { |
||
7940 | $result_message[$TABLETRACK_EXERCICES] = 0; |
||
7941 | } |
||
7942 | $result_message[$TABLETRACK_EXERCICES]++; |
||
7943 | } else { |
||
7944 | if (!empty($data['orig_lp_id']) && !empty($data['orig_lp_item_id'])) { |
||
7945 | $result_message['TRACK_E_EXERCISES'][$exe_id] = $data; |
||
7946 | } else { |
||
7947 | $result_message['TRACK_E_EXERCISES_IN_LP'][$exe_id] = $data; |
||
7948 | } |
||
7949 | } |
||
7950 | } |
||
7951 | } |
||
7952 | |||
7953 | // DESTINY COURSE |
||
7954 | if (!$update_database) { |
||
7955 | $sql = "SELECT * FROM $TABLETRACK_EXERCICES |
||
7956 | WHERE |
||
7957 | c_id = $course_id AND |
||
7958 | session_id = $new_session_id AND |
||
7959 | exe_user_id = $user_id "; |
||
7960 | $res = Database::query($sql); |
||
7961 | $list = []; |
||
7962 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
7963 | $list[$row['exe_id']] = $row; |
||
7964 | } |
||
7965 | |||
7966 | if (!empty($list)) { |
||
7967 | foreach ($list as $exe_id => $data) { |
||
7968 | if ($update_database) { |
||
7969 | $sql = "UPDATE $TABLETRACK_EXERCICES |
||
7970 | SET session_id = '$new_session_id' |
||
7971 | WHERE exe_id = $exe_id"; |
||
7972 | Database::query($sql); |
||
7973 | $result_message[$TABLETRACK_EXERCICES]++; |
||
7974 | } else { |
||
7975 | if (!empty($data['orig_lp_id']) && !empty($data['orig_lp_item_id'])) { |
||
7976 | $result_message_compare['TRACK_E_EXERCISES'][$exe_id] = $data; |
||
7977 | } else { |
||
7978 | $result_message_compare['TRACK_E_EXERCISES_IN_LP'][$exe_id] = $data; |
||
7979 | } |
||
7980 | } |
||
7981 | } |
||
7982 | } |
||
7983 | } |
||
7984 | |||
7985 | // 2.track_e_attempt, track_e_attempt_recording, track_e_downloads |
||
7986 | // Nothing to do because there are not relationship with a session |
||
7987 | // 3. track_e_course_access |
||
7988 | $sql = "SELECT * FROM $TBL_TRACK_E_COURSE_ACCESS |
||
7989 | WHERE c_id = $course_id AND session_id = $origin_session_id AND user_id = $user_id "; |
||
7990 | $res = Database::query($sql); |
||
7991 | $list = []; |
||
7992 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
7993 | $list[$row['course_access_id']] = $row; |
||
7994 | } |
||
7995 | |||
7996 | if (!empty($list)) { |
||
7997 | foreach ($list as $id => $data) { |
||
7998 | if ($update_database) { |
||
7999 | $sql = "UPDATE $TBL_TRACK_E_COURSE_ACCESS |
||
8000 | SET session_id = $new_session_id |
||
8001 | WHERE course_access_id = $id"; |
||
8002 | if ($debug) { |
||
8003 | echo $sql; |
||
8004 | } |
||
8005 | Database::query($sql); |
||
8006 | if (!isset($result_message[$TBL_TRACK_E_COURSE_ACCESS])) { |
||
8007 | $result_message[$TBL_TRACK_E_COURSE_ACCESS] = 0; |
||
8008 | } |
||
8009 | $result_message[$TBL_TRACK_E_COURSE_ACCESS]++; |
||
8010 | } |
||
8011 | } |
||
8012 | } |
||
8013 | |||
8014 | // 4. track_e_lastaccess |
||
8015 | $sql = "SELECT access_id FROM $TBL_TRACK_E_LAST_ACCESS |
||
8016 | WHERE |
||
8017 | c_id = $course_id AND |
||
8018 | access_session_id = $origin_session_id AND |
||
8019 | access_user_id = $user_id "; |
||
8020 | $res = Database::query($sql); |
||
8021 | $list = []; |
||
8022 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
8023 | $list[] = $row['access_id']; |
||
8024 | } |
||
8025 | |||
8026 | if (!empty($list)) { |
||
8027 | foreach ($list as $id) { |
||
8028 | if ($update_database) { |
||
8029 | $sql = "UPDATE $TBL_TRACK_E_LAST_ACCESS |
||
8030 | SET access_session_id = $new_session_id |
||
8031 | WHERE access_id = $id"; |
||
8032 | if ($debug) { |
||
8033 | echo $sql; |
||
8034 | } |
||
8035 | Database::query($sql); |
||
8036 | if (!isset($result_message[$TBL_TRACK_E_LAST_ACCESS])) { |
||
8037 | $result_message[$TBL_TRACK_E_LAST_ACCESS] = 0; |
||
8038 | } |
||
8039 | $result_message[$TBL_TRACK_E_LAST_ACCESS]++; |
||
8040 | } |
||
8041 | } |
||
8042 | } |
||
8043 | |||
8044 | // 5. lp_item_view |
||
8045 | // CHECK ORIGIN |
||
8046 | $sql = "SELECT * FROM $TBL_LP_VIEW |
||
8047 | WHERE user_id = $user_id AND session_id = $origin_session_id AND c_id = $course_id "; |
||
8048 | $res = Database::query($sql); |
||
8049 | |||
8050 | // Getting the list of LPs in the new session |
||
8051 | $lp_list = new LearnpathList($user_id, $course_info, $new_session_id); |
||
8052 | $flat_list = $lp_list->get_flat_list(); |
||
8053 | $list = []; |
||
8054 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
8055 | // Checking if the LP exist in the new session |
||
8056 | // if (in_array($row['lp_id'], array_keys($flat_list))) { |
||
8057 | $list[$row['id']] = $row; |
||
8058 | // } |
||
8059 | } |
||
8060 | |||
8061 | if (!empty($list)) { |
||
8062 | foreach ($list as $id => $data) { |
||
8063 | if ($update_database) { |
||
8064 | $sql = "UPDATE $TBL_LP_VIEW |
||
8065 | SET session_id = $new_session_id |
||
8066 | WHERE c_id = $course_id AND id = $id "; |
||
8067 | if ($debug) { |
||
8068 | var_dump($sql); |
||
0 ignored issues
–
show
|
|||
8069 | } |
||
8070 | $res = Database::query($sql); |
||
8071 | if ($debug) { |
||
8072 | var_dump($res); |
||
8073 | } |
||
8074 | if (!isset($result_message[$TBL_LP_VIEW])) { |
||
8075 | $result_message[$TBL_LP_VIEW] = 0; |
||
8076 | } |
||
8077 | $result_message[$TBL_LP_VIEW]++; |
||
8078 | } else { |
||
8079 | // Getting all information of that lp_item_id |
||
8080 | $score = self::get_avg_student_score( |
||
8081 | $user_id, |
||
8082 | $origin_course_code, |
||
8083 | [$data['lp_id']], |
||
8084 | $origin_session_id |
||
8085 | ); |
||
8086 | $progress = self::get_avg_student_progress( |
||
8087 | $user_id, |
||
8088 | $origin_course_code, |
||
8089 | [$data['lp_id']], |
||
8090 | $origin_session_id |
||
8091 | ); |
||
8092 | $result_message['LP_VIEW'][$data['lp_id']] = [ |
||
8093 | 'score' => $score, |
||
8094 | 'progress' => $progress, |
||
8095 | ]; |
||
8096 | } |
||
8097 | } |
||
8098 | } |
||
8099 | |||
8100 | // Check destination. |
||
8101 | if (!$update_database) { |
||
8102 | $sql = "SELECT * FROM $TBL_LP_VIEW |
||
8103 | WHERE user_id = $user_id AND session_id = $new_session_id AND c_id = $course_id"; |
||
8104 | $res = Database::query($sql); |
||
8105 | |||
8106 | // Getting the list of LPs in the new session |
||
8107 | $lp_list = new LearnpathList($user_id, $course_info, $new_session_id); |
||
8108 | $flat_list = $lp_list->get_flat_list(); |
||
8109 | |||
8110 | $list = []; |
||
8111 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
8112 | // Checking if the LP exist in the new session |
||
8113 | // if (in_array($row['lp_id'], array_keys($flat_list))) { |
||
8114 | $list[$row['id']] = $row; |
||
8115 | // } |
||
8116 | } |
||
8117 | |||
8118 | if (!empty($list)) { |
||
8119 | foreach ($list as $id => $data) { |
||
8120 | // Getting all information of that lp_item_id |
||
8121 | $score = self::get_avg_student_score( |
||
8122 | $user_id, |
||
8123 | $origin_course_code, |
||
8124 | [$data['lp_id']], |
||
8125 | $new_session_id |
||
8126 | ); |
||
8127 | $progress = self::get_avg_student_progress( |
||
8128 | $user_id, |
||
8129 | $origin_course_code, |
||
8130 | [$data['lp_id']], |
||
8131 | $new_session_id |
||
8132 | ); |
||
8133 | $result_message_compare['LP_VIEW'][$data['lp_id']] = [ |
||
8134 | 'score' => $score, |
||
8135 | 'progress' => $progress, |
||
8136 | ]; |
||
8137 | } |
||
8138 | } |
||
8139 | } |
||
8140 | |||
8141 | // 6. Agenda |
||
8142 | // calendar_event_attachment no problems no session_id |
||
8143 | $sql = "SELECT ref FROM $TBL_ITEM_PROPERTY |
||
8144 | WHERE tool = 'calendar_event' AND insert_user_id = $user_id AND c_id = $course_id "; |
||
8145 | $res = Database::query($sql); |
||
8146 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
8147 | $id = $row['ref']; |
||
8148 | if ($update_database) { |
||
8149 | $sql = "UPDATE $TBL_AGENDA SET session_id = $new_session_id WHERE c_id = $course_id AND id = $id "; |
||
8150 | if ($debug) { |
||
8151 | var_dump($sql); |
||
8152 | } |
||
8153 | $res_update = Database::query($sql); |
||
8154 | if ($debug) { |
||
8155 | var_dump($res_update); |
||
8156 | } |
||
8157 | if (!isset($result_message['agenda'])) { |
||
8158 | $result_message['agenda'] = 0; |
||
8159 | } |
||
8160 | $result_message['agenda']++; |
||
8161 | } |
||
8162 | } |
||
8163 | |||
8164 | // 7. Forum ?? So much problems when trying to import data |
||
8165 | // 8. Student publication - Works |
||
8166 | $sql = "SELECT ref FROM $TBL_ITEM_PROPERTY |
||
8167 | WHERE tool = 'work' AND insert_user_id = $user_id AND c_id = $course_id"; |
||
8168 | if ($debug) { |
||
8169 | echo $sql; |
||
8170 | } |
||
8171 | $res = Database::query($sql); |
||
8172 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
8173 | $id = $row['ref']; |
||
8174 | $sql = "SELECT * FROM $TBL_STUDENT_PUBLICATION |
||
8175 | WHERE id = $id AND session_id = $origin_session_id AND c_id = $course_id"; |
||
8176 | if ($debug) { |
||
8177 | var_dump($sql); |
||
8178 | } |
||
8179 | $sub_res = Database::query($sql); |
||
8180 | if (Database::num_rows($sub_res) > 0) { |
||
8181 | $data = Database::fetch_array($sub_res, 'ASSOC'); |
||
8182 | if ($debug) { |
||
8183 | var_dump($data); |
||
8184 | } |
||
8185 | $parent_id = $data['parent_id']; |
||
8186 | if (isset($data['parent_id']) && !empty($data['parent_id'])) { |
||
8187 | $sql = "SELECT * FROM $TBL_STUDENT_PUBLICATION |
||
8188 | WHERE id = $parent_id AND c_id = $course_id"; |
||
8189 | $select_res = Database::query($sql); |
||
8190 | $parent_data = Database::fetch_array($select_res, 'ASSOC'); |
||
8191 | if ($debug) { |
||
8192 | var_dump($parent_data); |
||
8193 | } |
||
8194 | |||
8195 | $sys_course_path = api_get_path(SYS_COURSE_PATH); |
||
8196 | $course_dir = $sys_course_path.$course_info['path']; |
||
8197 | $base_work_dir = $course_dir.'/work'; |
||
8198 | |||
8199 | // Creating the parent folder in the session if does not exists already |
||
8200 | // @todo ugly fix |
||
8201 | $search_this = "folder_moved_from_session_id_$origin_session_id"; |
||
8202 | $search_this2 = $parent_data['url']; |
||
8203 | $sql = "SELECT * FROM $TBL_STUDENT_PUBLICATION |
||
8204 | WHERE description like '%$search_this%' AND |
||
8205 | url LIKE '%$search_this2%' AND |
||
8206 | session_id = $new_session_id AND |
||
8207 | c_id = $course_id |
||
8208 | ORDER BY id desc LIMIT 1"; |
||
8209 | if ($debug) { |
||
8210 | echo $sql; |
||
8211 | } |
||
8212 | $sub_res = Database::query($sql); |
||
8213 | $num_rows = Database::num_rows($sub_res); |
||
8214 | $new_parent_id = 0; |
||
8215 | if ($num_rows > 0) { |
||
8216 | $new_result = Database::fetch_array($sub_res, 'ASSOC'); |
||
8217 | $created_dir = $new_result['url']; |
||
8218 | $new_parent_id = $new_result['id']; |
||
8219 | } else { |
||
8220 | if ($update_database) { |
||
8221 | $dir_name = substr($parent_data['url'], 1); |
||
8222 | $created_dir = create_unexisting_work_directory($base_work_dir, $dir_name); |
||
8223 | $created_dir = '/'.$created_dir; |
||
8224 | $now = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC')); |
||
8225 | // Creating directory |
||
8226 | $publication = new \Chamilo\CourseBundle\Entity\CStudentPublication(); |
||
8227 | $publication |
||
8228 | ->setUrl($created_dir) |
||
8229 | ->setCId($course_id) |
||
8230 | ->setTitle($parent_data['title']) |
||
8231 | ->setDescription( |
||
8232 | $parent_data['description']."folder_moved_from_session_id_$origin_session_id" |
||
8233 | ) |
||
8234 | ->setActive(false) |
||
8235 | ->setAccepted(true) |
||
8236 | ->setPostGroupId(0) |
||
8237 | ->setHasProperties($parent_data['has_properties']) |
||
8238 | ->setWeight($parent_data['weight']) |
||
8239 | ->setContainsFile($parent_data['contains_file']) |
||
8240 | ->setFiletype('folder') |
||
8241 | ->setSentDate($now) |
||
8242 | ->setQualification($parent_data['qualification']) |
||
8243 | ->setParentId(0) |
||
8244 | ->setQualificatorId(0) |
||
8245 | ->setUserId($parent_data['user_id']) |
||
8246 | ->setAllowTextAssignment($parent_data['allow_text_assignment']) |
||
8247 | ->setSession($session); |
||
8248 | |||
8249 | $publication->setDocumentId($parent_data['document_id']); |
||
8250 | |||
8251 | Database::getManager()->persist($publication); |
||
8252 | Database::getManager()->flush(); |
||
8253 | $id = $publication->getIid(); |
||
8254 | // Folder created |
||
8255 | api_item_property_update( |
||
8256 | $course_info, |
||
8257 | 'work', |
||
8258 | $id, |
||
8259 | 'DirectoryCreated', |
||
8260 | api_get_user_id(), |
||
8261 | null, |
||
8262 | null, |
||
8263 | null, |
||
8264 | null, |
||
8265 | $new_session_id |
||
8266 | ); |
||
8267 | $new_parent_id = $id; |
||
8268 | if (!isset($result_message[$TBL_STUDENT_PUBLICATION.' - new folder created called: '.$created_dir])) { |
||
8269 | $result_message[$TBL_STUDENT_PUBLICATION.' - new folder created called: '.$created_dir] = 0; |
||
8270 | } |
||
8271 | $result_message[$TBL_STUDENT_PUBLICATION.' - new folder created called: '.$created_dir]++; |
||
8272 | } |
||
8273 | } |
||
8274 | |||
8275 | // Creating student_publication_assignment if exists |
||
8276 | $sql = "SELECT * FROM $TBL_STUDENT_PUBLICATION_ASSIGNMENT |
||
8277 | WHERE publication_id = $parent_id AND c_id = $course_id"; |
||
8278 | if ($debug) { |
||
8279 | var_dump($sql); |
||
8280 | } |
||
8281 | $rest_select = Database::query($sql); |
||
8282 | if (Database::num_rows($rest_select) > 0) { |
||
8283 | if ($update_database && $new_parent_id) { |
||
8284 | $assignment_data = Database::fetch_array($rest_select, 'ASSOC'); |
||
8285 | $sql_add_publication = "INSERT INTO ".$TBL_STUDENT_PUBLICATION_ASSIGNMENT." SET |
||
8286 | c_id = '$course_id', |
||
8287 | expires_on = '".$assignment_data['expires_on']."', |
||
8288 | ends_on = '".$assignment_data['ends_on']."', |
||
8289 | add_to_calendar = '".$assignment_data['add_to_calendar']."', |
||
8290 | enable_qualification = '".$assignment_data['enable_qualification']."', |
||
8291 | publication_id = '".$new_parent_id."'"; |
||
8292 | if ($debug) { |
||
8293 | echo $sql_add_publication; |
||
8294 | } |
||
8295 | Database::query($sql_add_publication); |
||
8296 | $id = (int) Database::insert_id(); |
||
8297 | if ($id) { |
||
8298 | $sql_update = "UPDATE $TBL_STUDENT_PUBLICATION |
||
8299 | SET has_properties = '".$id."', |
||
8300 | view_properties = '1' |
||
8301 | WHERE id = ".$new_parent_id; |
||
8302 | if ($debug) { |
||
8303 | echo $sql_update; |
||
8304 | } |
||
8305 | Database::query($sql_update); |
||
8306 | if (!isset($result_message[$TBL_STUDENT_PUBLICATION_ASSIGNMENT])) { |
||
8307 | $result_message[$TBL_STUDENT_PUBLICATION_ASSIGNMENT] = 0; |
||
8308 | } |
||
8309 | $result_message[$TBL_STUDENT_PUBLICATION_ASSIGNMENT]++; |
||
8310 | } |
||
8311 | } |
||
8312 | } |
||
8313 | |||
8314 | $doc_url = $data['url']; |
||
8315 | $new_url = str_replace($parent_data['url'], $created_dir, $doc_url); |
||
8316 | |||
8317 | if ($update_database) { |
||
8318 | // Creating a new work |
||
8319 | $data['sent_date'] = new DateTime($data['sent_date'], new DateTimeZone('UTC')); |
||
8320 | $data['post_group_id'] = (int) $data['post_group_id']; |
||
8321 | $publication = new \Chamilo\CourseBundle\Entity\CStudentPublication(); |
||
8322 | $publication |
||
8323 | ->setUrl($new_url) |
||
8324 | ->setCId($course_id) |
||
8325 | ->setTitle($data['title']) |
||
8326 | ->setDescription($data['description'].' file moved') |
||
8327 | ->setActive($data['active']) |
||
8328 | ->setAccepted($data['accepted']) |
||
8329 | ->setPostGroupId($data['post_group_id']) |
||
8330 | ->setSentDate($data['sent_date']) |
||
8331 | ->setParentId($new_parent_id) |
||
8332 | ->setWeight($data['weight']) |
||
8333 | ->setHasProperties(0) |
||
8334 | ->setWeight($data['weight']) |
||
8335 | ->setContainsFile($data['contains_file']) |
||
8336 | ->setSession($session) |
||
8337 | ->setUserId($data['user_id']) |
||
8338 | ->setFiletype('file') |
||
8339 | ->setDocumentId(0) |
||
8340 | ; |
||
8341 | |||
8342 | $em->persist($publication); |
||
8343 | $em->flush(); |
||
8344 | |||
8345 | $id = $publication->getIid(); |
||
8346 | api_item_property_update( |
||
8347 | $course_info, |
||
8348 | 'work', |
||
8349 | $id, |
||
8350 | 'DocumentAdded', |
||
8351 | $user_id, |
||
8352 | null, |
||
8353 | null, |
||
8354 | null, |
||
8355 | null, |
||
8356 | $new_session_id |
||
8357 | ); |
||
8358 | if (!isset($result_message[$TBL_STUDENT_PUBLICATION])) { |
||
8359 | $result_message[$TBL_STUDENT_PUBLICATION] = 0; |
||
8360 | } |
||
8361 | $result_message[$TBL_STUDENT_PUBLICATION]++; |
||
8362 | $full_file_name = $course_dir.'/'.$doc_url; |
||
8363 | $new_file = $course_dir.'/'.$new_url; |
||
8364 | |||
8365 | if (file_exists($full_file_name)) { |
||
8366 | // deleting old assignment |
||
8367 | $result = copy($full_file_name, $new_file); |
||
8368 | if ($result) { |
||
8369 | unlink($full_file_name); |
||
8370 | if (isset($data['id'])) { |
||
8371 | $sql = "DELETE FROM $TBL_STUDENT_PUBLICATION WHERE id= ".$data['id']; |
||
8372 | if ($debug) { |
||
8373 | var_dump($sql); |
||
8374 | } |
||
8375 | Database::query($sql); |
||
8376 | } |
||
8377 | api_item_property_update( |
||
8378 | $course_info, |
||
8379 | 'work', |
||
8380 | $data['id'], |
||
8381 | 'DocumentDeleted', |
||
8382 | api_get_user_id() |
||
8383 | ); |
||
8384 | } |
||
8385 | } |
||
8386 | } |
||
8387 | } |
||
8388 | } |
||
8389 | } |
||
8390 | |||
8391 | // 9. Survey Pending |
||
8392 | // 10. Dropbox - not neccesary to move categories (no presence of session_id) |
||
8393 | $sql = "SELECT id FROM $TBL_DROPBOX_FILE |
||
8394 | WHERE uploader_id = $user_id AND session_id = $origin_session_id AND c_id = $course_id"; |
||
8395 | if ($debug) { |
||
8396 | var_dump($sql); |
||
8397 | } |
||
8398 | $res = Database::query($sql); |
||
8399 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
8400 | $id = (int) $row['id']; |
||
8401 | if ($update_database) { |
||
8402 | $sql = "UPDATE $TBL_DROPBOX_FILE SET session_id = $new_session_id WHERE c_id = $course_id AND id = $id"; |
||
8403 | if ($debug) { |
||
8404 | var_dump($sql); |
||
8405 | } |
||
8406 | Database::query($sql); |
||
8407 | if ($debug) { |
||
8408 | var_dump($res); |
||
8409 | } |
||
8410 | |||
8411 | $sql = "UPDATE $TBL_DROPBOX_POST SET session_id = $new_session_id WHERE file_id = $id"; |
||
8412 | if ($debug) { |
||
8413 | var_dump($sql); |
||
8414 | } |
||
8415 | Database::query($sql); |
||
8416 | if ($debug) { |
||
8417 | var_dump($res); |
||
8418 | } |
||
8419 | if (!isset($result_message[$TBL_DROPBOX_FILE])) { |
||
8420 | $result_message[$TBL_DROPBOX_FILE] = 0; |
||
8421 | } |
||
8422 | $result_message[$TBL_DROPBOX_FILE]++; |
||
8423 | } |
||
8424 | } |
||
8425 | |||
8426 | // 11. Notebook |
||
8427 | /*$sql = "SELECT notebook_id FROM $TBL_NOTEBOOK |
||
8428 | WHERE |
||
8429 | user_id = $user_id AND |
||
8430 | session_id = $origin_session_id AND |
||
8431 | course = '$origin_course_code' AND |
||
8432 | c_id = $course_id"; |
||
8433 | if ($debug) { |
||
8434 | var_dump($sql); |
||
8435 | } |
||
8436 | $res = Database::query($sql); |
||
8437 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
8438 | $id = $row['notebook_id']; |
||
8439 | if ($update_database) { |
||
8440 | $sql = "UPDATE $TBL_NOTEBOOK |
||
8441 | SET session_id = $new_session_id |
||
8442 | WHERE c_id = $course_id AND notebook_id = $id"; |
||
8443 | if ($debug) { |
||
8444 | var_dump($sql); |
||
8445 | } |
||
8446 | $res = Database::query($sql); |
||
8447 | if ($debug) { |
||
8448 | var_dump($res); |
||
8449 | } |
||
8450 | } |
||
8451 | }*/ |
||
8452 | |||
8453 | if ($update_database) { |
||
8454 | echo Display::return_message(get_lang('StatsMoved')); |
||
8455 | if (is_array($result_message)) { |
||
8456 | foreach ($result_message as $table => $times) { |
||
8457 | echo 'Table '.$table.' - '.$times.' records updated <br />'; |
||
8458 | } |
||
8459 | } |
||
8460 | } else { |
||
8461 | echo '<p class="lead">'.get_lang('UserInformationOfThisCourse').'</p>'; |
||
8462 | echo '<table class="table" width="100%">'; |
||
8463 | echo '<tr>'; |
||
8464 | echo '<th width="50%" valign="top">'; |
||
8465 | if ($origin_session_id == 0) { |
||
8466 | echo '<p><strong>'.get_lang('OriginCourse').'</strong></p>'; |
||
8467 | } else { |
||
8468 | echo '<p><strong>'.get_lang('OriginSession').' #'.$origin_session_id.'</strong></p>'; |
||
8469 | } |
||
8470 | echo '</th>'; |
||
8471 | echo '<th width="50%" valign="top">'; |
||
8472 | if ($new_session_id == 0) { |
||
8473 | echo '<p><strong>'.get_lang('DestinyCourse').'</strong></p>'; |
||
8474 | } else { |
||
8475 | echo '<p><strong>'.get_lang('DestinySession').' #'.$new_session_id.'</strong></p>'; |
||
8476 | } |
||
8477 | echo '</th>'; |
||
8478 | echo '</tr>'; |
||
8479 | echo '<tr>'; |
||
8480 | echo '<td>'; |
||
8481 | self::compareUserData($result_message); |
||
8482 | echo '</td>'; |
||
8483 | echo '<td>'; |
||
8484 | self::compareUserData($result_message_compare); |
||
8485 | echo '</td>'; |
||
8486 | echo '</tr>'; |
||
8487 | echo '</table>'; |
||
8488 | } |
||
8489 | } |
||
8490 | |||
8491 | public static function compareUserData($result_message) |
||
8492 | { |
||
8493 | foreach ($result_message as $table => $data) { |
||
8494 | $title = $table; |
||
8495 | if ($table === 'TRACK_E_EXERCISES') { |
||
8496 | $title = get_lang('Exercises'); |
||
8497 | } elseif ($table === 'TRACK_E_EXERCISES_IN_LP') { |
||
8498 | $title = get_lang('ExercisesInLp'); |
||
8499 | } elseif ($table === 'LP_VIEW') { |
||
8500 | $title = get_lang('LearningPaths'); |
||
8501 | } |
||
8502 | echo '<h3 class="page-header">'.get_lang($title).' </h3>'; |
||
8503 | |||
8504 | if (is_array($data)) { |
||
8505 | echo '<ul>'; |
||
8506 | foreach ($data as $id => $item) { |
||
8507 | echo '<li>'; |
||
8508 | if ($table === 'TRACK_E_EXERCISES' || $table === 'TRACK_E_EXERCISES_IN_LP') { |
||
8509 | echo '<p class="lead">'; |
||
8510 | echo get_lang('Exercise').' #'.$item['exe_exo_id']; |
||
8511 | if (!empty($item['orig_lp_id'])) { |
||
8512 | echo PHP_EOL.'<small>('; |
||
8513 | echo get_lang('LearningPath').' #'.$item['orig_lp_id']; |
||
8514 | echo ')</small>'; |
||
8515 | } |
||
8516 | echo '</p>'; |
||
8517 | echo "<p><strong>".get_lang('Attempt')." #$id</strong></p>"; |
||
8518 | // Process data. |
||
8519 | $array = [ |
||
8520 | 'exe_date' => get_lang('Date'), |
||
8521 | 'exe_result' => get_lang('Score'), |
||
8522 | 'exe_weighting' => get_lang('Weighting'), |
||
8523 | ]; |
||
8524 | foreach ($item as $key => $value) { |
||
8525 | if (in_array($key, array_keys($array))) { |
||
8526 | $key = $array[$key]; |
||
8527 | echo "<p>$key = $value </p>"; |
||
8528 | } |
||
8529 | } |
||
8530 | } else { |
||
8531 | echo '<p class="lead">'.get_lang('Id')." #$id</p>"; |
||
8532 | // process data |
||
8533 | foreach ($item as $key => $value) { |
||
8534 | echo "<p>$key = $value</p>"; |
||
8535 | } |
||
8536 | } |
||
8537 | echo '</li>'; |
||
8538 | } |
||
8539 | echo '</ul>'; |
||
8540 | } else { |
||
8541 | echo '<p>'.get_lang('NoResults').'</p>'; |
||
8542 | } |
||
8543 | } |
||
8544 | } |
||
8545 | |||
8546 | public static function updateUserLastLogin($userId) |
||
8547 | { |
||
8548 | $tblTrackLogin = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN); |
||
8549 | $sql = "SELECT login_id, login_date |
||
8550 | FROM $tblTrackLogin |
||
8551 | WHERE |
||
8552 | login_user_id='".$userId."' |
||
8553 | ORDER BY login_date DESC |
||
8554 | LIMIT 0,1"; |
||
8555 | |||
8556 | $qLastConnection = Database::query($sql); |
||
8557 | if (Database::num_rows($qLastConnection) > 0) { |
||
8558 | $now = api_get_utc_datetime(); |
||
8559 | $iIdLastConnection = Database::result($qLastConnection, 0, 'login_id'); |
||
8560 | |||
8561 | // is the latest logout_date still relevant? |
||
8562 | $sql = "SELECT logout_date FROM $tblTrackLogin |
||
8563 | WHERE login_id = $iIdLastConnection"; |
||
8564 | $qLogoutDate = Database::query($sql); |
||
8565 | $resLogoutDate = convert_sql_date(Database::result($qLogoutDate, 0, 'logout_date')); |
||
8566 | $lifeTime = api_get_configuration_value('session_lifetime'); |
||
8567 | |||
8568 | if ($resLogoutDate < time() - $lifeTime) { |
||
8569 | // it isn't, we should create a fresh entry |
||
8570 | Event::eventLogin($userId); |
||
8571 | // now that it's created, we can get its ID and carry on |
||
8572 | } else { |
||
8573 | $sql = "UPDATE $tblTrackLogin SET logout_date = '$now' |
||
8574 | WHERE login_id = '$iIdLastConnection'"; |
||
8575 | Database::query($sql); |
||
8576 | } |
||
8577 | |||
8578 | $tableUser = Database::get_main_table(TABLE_MAIN_USER); |
||
8579 | $sql = "UPDATE $tableUser SET last_login = '$now' |
||
8580 | WHERE user_id = ".$userId; |
||
8581 | Database::query($sql); |
||
8582 | } |
||
8583 | } |
||
8584 | |||
8585 | /** |
||
8586 | * Get results of user in exercises by dates. |
||
8587 | * |
||
8588 | * @return array |
||
8589 | */ |
||
8590 | public static function getUserTrackExerciseByDates( |
||
8591 | int $userId, |
||
8592 | int $courseId, |
||
8593 | string $startDate, |
||
8594 | string $endDate |
||
8595 | ) { |
||
8596 | $startDate = Database::escape_string($startDate); |
||
8597 | $endDate = Database::escape_string($endDate); |
||
8598 | |||
8599 | $tblTrackExercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
8600 | $tblQuiz = Database::get_course_table(TABLE_QUIZ_TEST); |
||
8601 | $sql = "SELECT |
||
8602 | te.exe_exo_id, |
||
8603 | q.title, |
||
8604 | MAX((te.exe_result/te.exe_weighting) * 100) as score |
||
8605 | FROM |
||
8606 | $tblTrackExercises te |
||
8607 | INNER JOIN |
||
8608 | $tblQuiz q ON (q.iid = te.exe_exo_id AND q.c_id = te.c_id) |
||
8609 | WHERE |
||
8610 | te.exe_user_id = $userId AND |
||
8611 | te.c_id = $courseId AND |
||
8612 | te.status = '' AND |
||
8613 | te.start_date BETWEEN '$startDate 00:00:00' AND '$endDate 23:59:59' |
||
8614 | GROUP BY |
||
8615 | te.exe_exo_id, |
||
8616 | q.title |
||
8617 | "; |
||
8618 | $rs = Database::query($sql); |
||
8619 | $result = []; |
||
8620 | if (Database::num_rows($rs) > 0) { |
||
8621 | while ($row = Database::fetch_array($rs)) { |
||
8622 | $result[] = $row; |
||
8623 | } |
||
8624 | } |
||
8625 | |||
8626 | return $result; |
||
8627 | } |
||
8628 | |||
8629 | /** |
||
8630 | * Generates a report based on the specified type and selected users within a date range. |
||
8631 | * |
||
8632 | * @param string $reportType The type of report to generate ('time_report' or 'billing_report'). |
||
8633 | * @param array $selectedUserList An array of user IDs to include in the report. |
||
8634 | * @param string $startDate The start date for the report in 'Y-m-d H:i:s' format. |
||
8635 | * @param string $endDate The end date for the report in 'Y-m-d H:i:s' format. |
||
8636 | * |
||
8637 | * @throws Exception Throws an exception if an invalid report type is provided. |
||
8638 | * |
||
8639 | * @return array An array containing the report data. The first element is an array of headers, |
||
8640 | * followed by the rows of data. |
||
8641 | */ |
||
8642 | public static function generateReport(string $reportType, array $selectedUserList, string $startDate, string $endDate): array |
||
8643 | { |
||
8644 | if (empty($selectedUserList)) { |
||
8645 | return ['headers' => [], 'rows' => []]; |
||
8646 | } |
||
8647 | |||
8648 | $tblTrackCourseAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
8649 | $tblLpView = Database::get_course_table(TABLE_LP_VIEW); |
||
8650 | $tblLpItemView = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
8651 | $tblLpItem = Database::get_course_table(TABLE_LP_ITEM); |
||
8652 | $tblLp = Database::get_course_table(TABLE_LP_MAIN); |
||
8653 | |||
8654 | switch ($reportType) { |
||
8655 | case 'time_report': |
||
8656 | $headers = [ |
||
8657 | get_lang('LastName'), |
||
8658 | get_lang('FirstName'), |
||
8659 | get_lang('SessionName'), |
||
8660 | get_lang('CourseName'), |
||
8661 | get_lang('StartingAccessDate'), |
||
8662 | get_lang('EndingAccessDate'), |
||
8663 | get_lang('TimeSpent'), |
||
8664 | ]; |
||
8665 | $sql = "SELECT user_id, session_id, c_id, login_course_date, logout_course_date, (UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) AS time |
||
8666 | FROM $tblTrackCourseAccess |
||
8667 | WHERE login_course_date >= '".api_get_utc_datetime($startDate.' 00:00:00')."' |
||
8668 | AND login_course_date <= '".api_get_utc_datetime($endDate.' 23:59:59')."' |
||
8669 | AND logout_course_date >= '".api_get_utc_datetime($startDate.' 00:00:00')."' |
||
8670 | AND logout_course_date <= '".api_get_utc_datetime($endDate.' 23:59:59')."' |
||
8671 | AND user_id IN (".implode(',', $selectedUserList).") |
||
8672 | ORDER BY user_id, login_course_date"; |
||
8673 | break; |
||
8674 | |||
8675 | case 'billing_report': |
||
8676 | $extraFieldVariable = api_get_configuration_value('billing_report_lp_extra_field'); |
||
8677 | $extraField = (new ExtraField('lp'))->get_handler_field_info_by_field_variable($extraFieldVariable); |
||
8678 | $headers = [ |
||
8679 | get_lang('LastName'), |
||
8680 | get_lang('FirstName'), |
||
8681 | get_lang('SessionName'), |
||
8682 | get_lang('CourseName'), |
||
8683 | get_lang('LearningpathName'), |
||
8684 | get_lang('ValidationDate'), |
||
8685 | $extraField['display_text'], |
||
8686 | ]; |
||
8687 | $sql = "SELECT lv.user_id, lv.session_id, lv.c_id, lv.lp_id, liv.start_time, l.name AS lp_name |
||
8688 | FROM $tblLpView lv |
||
8689 | INNER JOIN $tblLpItemView liv ON lv.iid = liv.lp_view_id |
||
8690 | INNER JOIN $tblLpItem li ON li.iid = liv.lp_item_id |
||
8691 | INNER JOIN $tblLp l ON l.id = li.lp_id |
||
8692 | WHERE lv.user_id IN (".implode(',', $selectedUserList).") |
||
8693 | AND liv.start_time >= UNIX_TIMESTAMP('".api_get_utc_datetime($startDate.' 00:00:00')."') |
||
8694 | AND liv.start_time <= UNIX_TIMESTAMP('".api_get_utc_datetime($endDate.' 23:59:59')."') |
||
8695 | AND lv.progress = 100 |
||
8696 | AND li.item_type = '".TOOL_LP_FINAL_ITEM."' |
||
8697 | ORDER BY lv.user_id, liv.start_time"; |
||
8698 | break; |
||
8699 | |||
8700 | default: |
||
8701 | throw new Exception('Invalid report type'); |
||
8702 | } |
||
8703 | |||
8704 | $result = Database::query($sql); |
||
8705 | $rows = []; |
||
8706 | |||
8707 | while ($row = Database::fetch_array($result, 'ASSOC')) { |
||
8708 | $user = api_get_user_info($row['user_id']); |
||
8709 | $session = api_get_session_info($row['session_id']); |
||
8710 | $course = api_get_course_info_by_id($row['c_id']); |
||
8711 | |||
8712 | if ($reportType == 'time_report') { |
||
8713 | $rows[] = [ |
||
8714 | $user['lastname'], |
||
8715 | $user['firstname'], |
||
8716 | $session['name'], |
||
8717 | $course['title'], |
||
8718 | api_get_local_time($row['login_course_date']), |
||
8719 | api_get_local_time($row['logout_course_date']), |
||
8720 | gmdate('H:i:s', $row['time']), |
||
8721 | ]; |
||
8722 | } elseif ($reportType == 'billing_report') { |
||
8723 | $extraFieldValue = (new ExtraFieldValue('lp'))->get_values_by_handler_and_field_variable($row['lp_id'], $extraFieldVariable); |
||
8724 | $rows[] = [ |
||
8725 | $user['lastname'], |
||
8726 | $user['firstname'], |
||
8727 | $session['name'], |
||
8728 | $course['title'], |
||
8729 | $row['lp_name'], |
||
8730 | api_get_local_time(date('Y-m-d H:i:s', $row['start_time'])), |
||
8731 | $extraFieldValue['value'] ?? '', |
||
8732 | ]; |
||
8733 | } |
||
8734 | } |
||
8735 | |||
8736 | return ['headers' => $headers, 'rows' => $rows]; |
||
8737 | } |
||
8738 | |||
8739 | private static function generateQuizzesTable(array $courseInfo, int $sessionId = 0): string |
||
8740 | { |
||
8741 | if (empty($sessionId)) { |
||
8742 | $userList = CourseManager::get_user_list_from_course_code( |
||
8743 | $courseInfo['code'], |
||
8744 | $sessionId, |
||
8745 | null, |
||
8746 | null, |
||
8747 | STUDENT |
||
8748 | ); |
||
8749 | } else { |
||
8750 | $userList = CourseManager::get_user_list_from_course_code($courseInfo['code'], $sessionId, null, null, 0); |
||
8751 | } |
||
8752 | |||
8753 | $active = 3; |
||
8754 | if (true === api_get_configuration_value('tracking_my_progress_show_deleted_exercises')) { |
||
8755 | $active = 2; |
||
8756 | } |
||
8757 | |||
8758 | $exerciseList = ExerciseLib::get_all_exercises($courseInfo, $sessionId, false, null, false, $active); |
||
8759 | |||
8760 | if (empty($exerciseList)) { |
||
8761 | return Display::return_message(get_lang('NoEx')); |
||
8762 | } |
||
8763 | |||
8764 | $toGraphExerciseResult = []; |
||
8765 | |||
8766 | $quizzesTable = new SortableTableFromArray([], 0, 0, 'quizzes'); |
||
8767 | $quizzesTable->setHeaders( |
||
8768 | [ |
||
8769 | get_lang('Title'), |
||
8770 | get_lang('InLp'), |
||
8771 | get_lang('Attempts'), |
||
8772 | get_lang('BestAttempt'), |
||
8773 | get_lang('Ranking'), |
||
8774 | get_lang('BestResultInCourse'), |
||
8775 | get_lang('Statistics').Display::return_icon('info3.gif', get_lang('OnlyBestResultsPerStudent')), |
||
8776 | ] |
||
8777 | ); |
||
8778 | |||
8779 | $webCodePath = api_get_path(WEB_CODE_PATH); |
||
8780 | |||
8781 | foreach ($exerciseList as $exercices) { |
||
8782 | $objExercise = new Exercise($courseInfo['real_id']); |
||
8783 | $objExercise->read($exercices['iid']); |
||
8784 | $visibleReturn = $objExercise->is_visible(); |
||
8785 | |||
8786 | // Getting count of attempts by user |
||
8787 | $attempts = Event::count_exercise_attempts_by_user( |
||
8788 | api_get_user_id(), |
||
8789 | $exercices['iid'], |
||
8790 | $courseInfo['real_id'], |
||
8791 | $sessionId, |
||
8792 | false |
||
8793 | ); |
||
8794 | |||
8795 | $url = $webCodePath.'exercise/overview.php?' |
||
8796 | .http_build_query( |
||
8797 | ['cidReq' => $courseInfo['code'], 'id_session' => $sessionId, 'exerciseId' => $exercices['iid']] |
||
8798 | ); |
||
8799 | |||
8800 | if ($visibleReturn['value'] == true) { |
||
8801 | $exercices['title'] = Display::url( |
||
8802 | $exercices['title'], |
||
8803 | $url, |
||
8804 | ['target' => SESSION_LINK_TARGET] |
||
8805 | ); |
||
8806 | } elseif ($exercices['active'] == -1) { |
||
8807 | $exercices['title'] = sprintf(get_lang('XParenthesisDeleted'), $exercices['title']); |
||
8808 | } |
||
8809 | |||
8810 | $lpList = Exercise::getLpListFromExercise($exercices['iid'], $courseInfo['real_id']); |
||
8811 | $inLp = !empty($lpList) ? get_lang('Yes') : get_lang('No'); |
||
8812 | |||
8813 | $quizData = [ |
||
8814 | $exercices['title'], |
||
8815 | $inLp, |
||
8816 | $attempts, |
||
8817 | '-', |
||
8818 | '-', |
||
8819 | '-', |
||
8820 | '-', |
||
8821 | ]; |
||
8822 | |||
8823 | // Exercise configuration show results or show only score |
||
8824 | if (!in_array($exercices['results_disabled'], [0, 2]) |
||
8825 | || empty($attempts) |
||
8826 | ) { |
||
8827 | $quizzesTable->addRow($quizData); |
||
8828 | |||
8829 | continue; |
||
8830 | } |
||
8831 | |||
8832 | // For graphics |
||
8833 | $bestExerciseAttempts = Event::get_best_exercise_results_by_user( |
||
8834 | $exercices['iid'], |
||
8835 | $courseInfo['real_id'], |
||
8836 | $sessionId, |
||
8837 | 0, |
||
8838 | false |
||
8839 | ); |
||
8840 | |||
8841 | $toGraphExerciseResult[$exercices['iid']] = [ |
||
8842 | 'title' => $exercices['title'], |
||
8843 | 'data' => $bestExerciseAttempts, |
||
8844 | ]; |
||
8845 | |||
8846 | // Getting best results |
||
8847 | $bestScoreData = ExerciseLib::get_best_attempt_in_course( |
||
8848 | $exercices['iid'], |
||
8849 | $courseInfo['real_id'], |
||
8850 | $sessionId, |
||
8851 | false |
||
8852 | ); |
||
8853 | |||
8854 | if (!empty($bestScoreData)) { |
||
8855 | $quizData[6] = ExerciseLib::show_score( |
||
8856 | $bestScoreData['exe_result'], |
||
8857 | $bestScoreData['exe_weighting'] |
||
8858 | ); |
||
8859 | } |
||
8860 | |||
8861 | $exerciseAttempt = ExerciseLib::get_best_attempt_by_user( |
||
8862 | api_get_user_id(), |
||
8863 | $exercices['iid'], |
||
8864 | $courseInfo['real_id'], |
||
8865 | $sessionId, |
||
8866 | false |
||
8867 | ); |
||
8868 | |||
8869 | if (!empty($exerciseAttempt)) { |
||
8870 | // Always getting the BEST attempt |
||
8871 | $score = $exerciseAttempt['exe_result']; |
||
8872 | $weighting = $exerciseAttempt['exe_weighting']; |
||
8873 | $exeId = $exerciseAttempt['exe_id']; |
||
8874 | |||
8875 | $latestAttemptUrl = $webCodePath.'exercise/result.php?' |
||
8876 | .http_build_query( |
||
8877 | [ |
||
8878 | 'id' => $exeId, |
||
8879 | 'cidReq' => $courseInfo['code'], |
||
8880 | 'show_headers' => 1, |
||
8881 | 'id_session' => $sessionId, |
||
8882 | ] |
||
8883 | ); |
||
8884 | |||
8885 | $quizData[4] = Display::url( |
||
8886 | ExerciseLib::show_score($score, $weighting), |
||
8887 | $latestAttemptUrl |
||
8888 | ); |
||
8889 | |||
8890 | $myScore = !empty($weighting) && intval($weighting) != 0 ? $score / $weighting : 0; |
||
8891 | |||
8892 | // @todo this function slows the page |
||
8893 | if (is_int($userList)) { |
||
8894 | $userList = [$userList]; |
||
8895 | } |
||
8896 | |||
8897 | $quizData[5] = ExerciseLib::get_exercise_result_ranking( |
||
8898 | $myScore, |
||
8899 | $exeId, |
||
8900 | $exercices['iid'], |
||
8901 | $courseInfo['code'], |
||
8902 | $sessionId, |
||
8903 | $userList, |
||
8904 | true, |
||
8905 | false |
||
8906 | ); |
||
8907 | $graph = self::generate_exercise_result_thumbnail_graph($toGraphExerciseResult[$exercices['iid']]); |
||
8908 | $normalGraph = self::generate_exercise_result_graph($toGraphExerciseResult[$exercices['iid']]); |
||
8909 | |||
8910 | $quizData[7] = Display::url( |
||
8911 | Display::img($graph, '', [], false), |
||
8912 | $normalGraph, |
||
8913 | ['id' => $exercices['iid'], 'class' => 'expand-image'] |
||
8914 | ); |
||
8915 | } |
||
8916 | |||
8917 | $quizzesTable->addRow($quizData); |
||
8918 | } |
||
8919 | |||
8920 | return Display::page_subheader2(get_lang('Exercises')) |
||
8921 | .Display::div( |
||
8922 | $quizzesTable->toHtml(), |
||
8923 | ['class' => 'table-responsive'] |
||
8924 | ); |
||
8925 | } |
||
8926 | |||
8927 | private static function generateLearningPathsTable( |
||
8928 | User $user, |
||
8929 | array $courseInfo, |
||
8930 | int $sessionId = 0, |
||
8931 | bool $isAllowedToEdit = true |
||
8932 | ): string { |
||
8933 | $html = []; |
||
8934 | |||
8935 | $columnHeaders = [ |
||
8936 | 'lp' => get_lang('LearningPath'), |
||
8937 | 'time' => get_lang('LatencyTimeSpent'), |
||
8938 | 'progress' => get_lang('Progress'), |
||
8939 | 'score' => get_lang('Score'), |
||
8940 | 'best_score' => get_lang('BestScore'), |
||
8941 | 'last_connection' => get_lang('LastConnexion'), |
||
8942 | ]; |
||
8943 | |||
8944 | $trackingColumns = api_get_configuration_value('tracking_columns'); |
||
8945 | |||
8946 | if (isset($trackingColumns['my_progress_lp'])) { |
||
8947 | $columnHeaders = array_filter( |
||
8948 | $columnHeaders, |
||
8949 | function ($columHeader, $key) use ($trackingColumns) { |
||
8950 | if (!isset($trackingColumns['my_progress_lp'][$key]) |
||
8951 | || $trackingColumns['my_progress_lp'][$key] == false |
||
8952 | ) { |
||
8953 | return false; |
||
8954 | } |
||
8955 | |||
8956 | return true; |
||
8957 | }, |
||
8958 | ARRAY_FILTER_USE_BOTH |
||
8959 | ); |
||
8960 | } |
||
8961 | |||
8962 | if (true === api_get_configuration_value('student_follow_page_add_LP_subscription_info')) { |
||
8963 | $columnHeaders['student_follow_page_add_LP_subscription_info'] = get_lang('Unlock'); |
||
8964 | } |
||
8965 | |||
8966 | if (true === api_get_configuration_value('student_follow_page_add_LP_acquisition_info')) { |
||
8967 | $columnHeaders['student_follow_page_add_LP_acquisition_info'] = get_lang('Acquisition'); |
||
8968 | } |
||
8969 | |||
8970 | $addLpInvisibleCheckbox = api_get_configuration_value('student_follow_page_add_LP_invisible_checkbox'); |
||
8971 | $includeNotsubscribedLp = api_get_configuration_value('student_follow_page_include_not_subscribed_lp_students'); |
||
8972 | |||
8973 | $columnHeadersKeys = array_keys($columnHeaders); |
||
8974 | |||
8975 | $categories = learnpath::getCategories($courseInfo['real_id'], true); |
||
8976 | $countCategories = count($categories); |
||
8977 | |||
8978 | $webCodePath = api_get_path(WEB_CODE_PATH); |
||
8979 | |||
8980 | /** @var CLpCategory $category */ |
||
8981 | foreach ($categories as $category) { |
||
8982 | // LP table results |
||
8983 | $objLearnpathList = new LearnpathList( |
||
8984 | $user->getId(), |
||
8985 | $courseInfo, |
||
8986 | $sessionId, |
||
8987 | null, |
||
8988 | true, |
||
8989 | $category->getId(), |
||
8990 | false, |
||
8991 | false, |
||
8992 | $includeNotsubscribedLp === false |
||
8993 | ); |
||
8994 | $lpList = $objLearnpathList->get_flat_list(); |
||
8995 | |||
8996 | $learningpathsTable = new SortableTableFromArray([], 0, 0, 'learningpaths'); |
||
8997 | $learningpathsTable->setHeaders($columnHeaders); |
||
8998 | |||
8999 | foreach ($lpList as $lpId => $learnpath) { |
||
9000 | $learningpathData = []; |
||
9001 | |||
9002 | if (!$learnpath['lp_visibility']) { |
||
9003 | continue; |
||
9004 | } |
||
9005 | |||
9006 | if ($addLpInvisibleCheckbox) { |
||
9007 | if (!StudentFollowPage::isViewVisible($lpId, $user->getId(), $courseInfo['real_id'], $sessionId)) { |
||
9008 | continue; |
||
9009 | } |
||
9010 | } |
||
9011 | |||
9012 | $url = $webCodePath.'lp/lp_controller.php?' |
||
9013 | .http_build_query( |
||
9014 | ['cidReq' => $courseInfo['code'], 'id_session' => $sessionId, 'lp_id' => $lpId, 'action' => 'view'] |
||
9015 | ); |
||
9016 | |||
9017 | if (in_array('lp', $columnHeadersKeys)) { |
||
9018 | if ($learnpath['lp_visibility'] == 0) { |
||
9019 | $learningpathData[] = $learnpath['lp_name']; |
||
9020 | } else { |
||
9021 | $learningpathData[] = Display::url( |
||
9022 | $learnpath['lp_name'], |
||
9023 | $url, |
||
9024 | ['target' => SESSION_LINK_TARGET] |
||
9025 | ); |
||
9026 | } |
||
9027 | } |
||
9028 | |||
9029 | if (in_array('time', $columnHeadersKeys)) { |
||
9030 | $time_spent_in_lp = self::get_time_spent_in_lp( |
||
9031 | $user->getId(), |
||
9032 | $courseInfo['code'], |
||
9033 | [$lpId], |
||
9034 | $sessionId |
||
9035 | ); |
||
9036 | |||
9037 | $learningpathData[] = api_time_to_hms($time_spent_in_lp); |
||
9038 | } |
||
9039 | |||
9040 | if (in_array('progress', $columnHeadersKeys)) { |
||
9041 | $progress = self::get_avg_student_progress( |
||
9042 | $user->getId(), |
||
9043 | $courseInfo['code'], |
||
9044 | [$lpId], |
||
9045 | $sessionId |
||
9046 | ); |
||
9047 | |||
9048 | if (is_numeric($progress)) { |
||
9049 | $progress = sprintf(get_lang('XPercent'), $progress); |
||
9050 | } |
||
9051 | |||
9052 | $learningpathData[] = $progress; |
||
9053 | } |
||
9054 | |||
9055 | if (in_array('score', $columnHeadersKeys)) { |
||
9056 | $percentage_score = self::get_avg_student_score( |
||
9057 | $user->getId(), |
||
9058 | $courseInfo['code'], |
||
9059 | [$lpId], |
||
9060 | $sessionId |
||
9061 | ); |
||
9062 | |||
9063 | if (is_numeric($percentage_score)) { |
||
9064 | $percentage_score = sprintf(get_lang('XPercent'), $percentage_score); |
||
9065 | } else { |
||
9066 | $percentage_score = sprintf(get_lang('XPercent'), 0); |
||
9067 | } |
||
9068 | |||
9069 | $learningpathData[] = $percentage_score; |
||
9070 | } |
||
9071 | |||
9072 | if (in_array('best_score', $columnHeadersKeys)) { |
||
9073 | $bestScore = self::get_avg_student_score( |
||
9074 | $user->getId(), |
||
9075 | $courseInfo['code'], |
||
9076 | [$lpId], |
||
9077 | $sessionId, |
||
9078 | false, |
||
9079 | false, |
||
9080 | true |
||
9081 | ); |
||
9082 | |||
9083 | if (is_numeric($bestScore)) { |
||
9084 | $bestScore = sprintf(get_lang('XPercent'), $bestScore); |
||
9085 | } else { |
||
9086 | $bestScore = '-'; |
||
9087 | } |
||
9088 | |||
9089 | $learningpathData[] = $bestScore; |
||
9090 | } |
||
9091 | |||
9092 | if (in_array('last_connection', $columnHeadersKeys)) { |
||
9093 | $lastConnectionInLp = self::get_last_connection_time_in_lp( |
||
9094 | $user->getId(), |
||
9095 | $courseInfo['code'], |
||
9096 | $lpId, |
||
9097 | $sessionId |
||
9098 | ); |
||
9099 | |||
9100 | $lastConnection = '-'; |
||
9101 | |||
9102 | if (!empty($lastConnectionInLp)) { |
||
9103 | $lastConnection = api_convert_and_format_date($lastConnectionInLp, DATE_TIME_FORMAT_LONG); |
||
9104 | } |
||
9105 | |||
9106 | $learningpathData[] = $lastConnection; |
||
9107 | } |
||
9108 | |||
9109 | if (in_array('student_follow_page_add_LP_subscription_info', $columnHeadersKeys)) { |
||
9110 | $learningpathData[] = StudentFollowPage::getLpSubscription( |
||
9111 | $learnpath, |
||
9112 | $user->getId(), |
||
9113 | $courseInfo['real_id'], |
||
9114 | $sessionId, |
||
9115 | $isAllowedToEdit |
||
9116 | ); |
||
9117 | } |
||
9118 | |||
9119 | if (in_array('student_follow_page_add_LP_acquisition_info', $columnHeadersKeys)) { |
||
9120 | $learningpathData[] = StudentFollowPage::getLpAcquisition( |
||
9121 | $learnpath, |
||
9122 | $user->getId(), |
||
9123 | $courseInfo['real_id'], |
||
9124 | $sessionId |
||
9125 | ); |
||
9126 | } |
||
9127 | |||
9128 | $learningpathsTable->addRow($learningpathData); |
||
9129 | } |
||
9130 | |||
9131 | if ($learningpathsTable->getRowCount() < 2) { |
||
9132 | continue; |
||
9133 | } |
||
9134 | |||
9135 | if ($countCategories > 1) { |
||
9136 | $html[] = Display::tag('h5', $category->getName()); |
||
9137 | } |
||
9138 | |||
9139 | $html[] = Display::div( |
||
9140 | $learningpathsTable->toHtml(), |
||
9141 | ['class' => 'table-responsive'] |
||
9142 | ); |
||
9143 | } |
||
9144 | |||
9145 | return implode(PHP_EOL, $html); |
||
9146 | } |
||
9147 | |||
9148 | private static function countSubscribedCoursesPerUser() |
||
9149 | { |
||
9150 | } |
||
9151 | } |
||
9152 |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.