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\CoreBundle\Entity\TrackEAttemptQualify; |
||
8 | use Chamilo\CoreBundle\Entity\TrackEDownloads; |
||
9 | use Chamilo\CoreBundle\Entity\User; |
||
10 | use Chamilo\CoreBundle\Enums\ActionIcon; |
||
11 | use Chamilo\CoreBundle\Enums\StateIcon; |
||
12 | use Chamilo\CoreBundle\Framework\Container; |
||
13 | use Chamilo\CourseBundle\Entity\CLp; |
||
14 | use Chamilo\CourseBundle\Entity\CQuiz; |
||
15 | use Chamilo\CourseBundle\Entity\CStudentPublication; |
||
16 | use ChamiloSession as Session; |
||
17 | use CpChart\Cache as pCache; |
||
18 | use CpChart\Data as pData; |
||
19 | use CpChart\Image as pImage; |
||
20 | use ExtraField as ExtraFieldModel; |
||
21 | |||
22 | /** |
||
23 | * Class Tracking. |
||
24 | * |
||
25 | * @author Julio Montoya <[email protected]> |
||
26 | */ |
||
27 | class Tracking |
||
28 | { |
||
29 | /** |
||
30 | * Get group reporting. |
||
31 | * |
||
32 | * @param int $course_id |
||
33 | * @param int $sessionId |
||
34 | * @param int $group_id |
||
35 | * @param string $type |
||
36 | * @param int $start |
||
37 | * @param int $limit |
||
38 | * @param int $sidx |
||
39 | * @param string $sord |
||
40 | * @param array $where_condition |
||
41 | * |
||
42 | * @return array|null |
||
43 | */ |
||
44 | public static function get_group_reporting( |
||
45 | $courseId, |
||
46 | $sessionId = 0, |
||
47 | $group_id = 0, |
||
48 | $type = 'all', |
||
49 | $start = 0, |
||
50 | $limit = 1000, |
||
51 | $sidx = 1, |
||
52 | $sord = 'desc', |
||
53 | $where_condition = [] |
||
54 | ) { |
||
55 | $courseId = (int) $courseId; |
||
56 | $sessionId = (int) $sessionId; |
||
57 | |||
58 | if (empty($courseId)) { |
||
59 | return null; |
||
60 | } |
||
61 | $course = api_get_course_entity($courseId); |
||
62 | |||
63 | $session = api_get_session_entity($sessionId); |
||
64 | if ('count' === $type) { |
||
65 | return GroupManager::get_group_list(null, $course, null, $sessionId, true); |
||
66 | } |
||
67 | |||
68 | $groupList = GroupManager::get_group_list(null, $course, null, $sessionId, false, null, true); |
||
69 | $parsedResult = []; |
||
70 | if (!empty($groupList)) { |
||
71 | foreach ($groupList as $group) { |
||
72 | $users = GroupManager::get_users($group->getIid(), true, null, null, false, $courseId); |
||
73 | $time = 0; |
||
74 | $avg_student_score = 0; |
||
75 | $avg_student_progress = 0; |
||
76 | $work = 0; |
||
77 | $messages = 0; |
||
78 | foreach ($users as $user_data) { |
||
79 | $user = api_get_user_entity($user_data['user_id']); |
||
80 | $time += self::get_time_spent_on_the_course( |
||
81 | $user_data['user_id'], |
||
82 | $courseId, |
||
83 | $sessionId |
||
84 | ); |
||
85 | $average = self::get_avg_student_score( |
||
86 | $user_data['user_id'], |
||
87 | $course, |
||
88 | [], |
||
89 | $session |
||
90 | ); |
||
91 | if (is_numeric($average)) { |
||
92 | $avg_student_score += $average; |
||
93 | } |
||
94 | $avg_student_progress += self::get_avg_student_progress( |
||
95 | $user_data['user_id'], |
||
96 | $course, |
||
97 | [], |
||
98 | $session |
||
99 | ); |
||
100 | $work += Container::getStudentPublicationRepository()->countUserPublications( |
||
101 | $user, |
||
102 | $course, |
||
103 | $session |
||
104 | ); |
||
105 | $messages += Container::getForumPostRepository()->countUserForumPosts($user, $course, $session); |
||
106 | } |
||
107 | |||
108 | $countUsers = count($users); |
||
109 | $averageProgress = empty($countUsers) ? 0 : round($avg_student_progress / $countUsers, 2); |
||
110 | $averageScore = empty($countUsers) ? 0 : round($avg_student_score / $countUsers, 2); |
||
111 | |||
112 | $groupItem = [ |
||
113 | 'id' => $group->getIid(), |
||
114 | 'title' => $group->getTitle(), |
||
115 | 'time' => api_time_to_hms($time), |
||
116 | 'progress' => $averageProgress, |
||
117 | 'score' => $averageScore, |
||
118 | 'works' => $work, |
||
119 | 'messages' => $messages, |
||
120 | ]; |
||
121 | $parsedResult[] = $groupItem; |
||
122 | } |
||
123 | } |
||
124 | |||
125 | return $parsedResult; |
||
126 | } |
||
127 | |||
128 | /** |
||
129 | * @param int $session_id |
||
130 | * @param string $origin |
||
131 | * @param bool $export_csv |
||
132 | * @param int $lp_id |
||
133 | * @param int $lp_item_id |
||
134 | * @param int $extendId |
||
135 | * @param int $extendAttemptId |
||
136 | * @param string $extendedAttempt |
||
137 | * @param string $extendedAll |
||
138 | * @param string $type classic or simple |
||
139 | * @param bool $allowExtend Optional. Allow or not extend te results |
||
140 | * |
||
141 | * @return string |
||
142 | */ |
||
143 | public static function getLpStats( |
||
144 | int $user_id, |
||
145 | Course $course, |
||
146 | ?SessionEntity $session, |
||
147 | $origin, |
||
148 | $export_csv, |
||
149 | $lp_id, |
||
150 | $lp_item_id = null, |
||
151 | $extendId = null, |
||
152 | $extendAttemptId = null, |
||
153 | $extendedAttempt = null, |
||
154 | $extendedAll = null, |
||
155 | $type = 'classic', |
||
156 | $allowExtend = true |
||
157 | ) { |
||
158 | if (empty($lp_id)) { |
||
159 | return ''; |
||
160 | } |
||
161 | |||
162 | $hideTime = ('true' === api_get_setting('lp.hide_lp_time')); |
||
163 | $lp_id = (int) $lp_id; |
||
164 | |||
165 | $lp_item_id = (int) $lp_item_id; |
||
166 | $user_id = (int) $user_id; |
||
167 | $sessionId = $session ? $session->getId() : 0; |
||
168 | $origin = Security::remove_XSS($origin); |
||
169 | $lp = Container::getLpRepository()->find($lp_id); |
||
170 | $list = learnpath::get_flat_ordered_items_list($lp); |
||
171 | $is_allowed_to_edit = api_is_allowed_to_edit(null, true); |
||
172 | $courseId = $course->getId(); |
||
173 | $session_condition = api_get_session_condition($sessionId); |
||
174 | |||
175 | // Extend all button |
||
176 | $output = ''; |
||
177 | $extra = '<script> |
||
178 | $(function() { |
||
179 | $( "#dialog:ui-dialog" ).dialog( "destroy" ); |
||
180 | $( "#dialog-confirm" ).dialog({ |
||
181 | autoOpen: false, |
||
182 | show: "blind", |
||
183 | resizable: false, |
||
184 | height:300, |
||
185 | modal: true |
||
186 | }); |
||
187 | |||
188 | $(".export").click(function() { |
||
189 | var targetUrl = $(this).attr("href"); |
||
190 | $( "#dialog-confirm" ).dialog({ |
||
191 | width:400, |
||
192 | height:300, |
||
193 | buttons: { |
||
194 | "'.addslashes(get_lang('Download')).'": function() { |
||
195 | var option = $("input[name=add_logo]:checked").val(); |
||
196 | location.href = targetUrl+"&add_logo="+option; |
||
197 | $(this).dialog("close"); |
||
198 | } |
||
199 | } |
||
200 | }); |
||
201 | $("#dialog-confirm").dialog("open"); |
||
202 | |||
203 | return false; |
||
204 | }); |
||
205 | }); |
||
206 | </script>'; |
||
207 | |||
208 | $extra .= '<div id="dialog-confirm" title="'.get_lang('Please confirm your choice').'">'; |
||
209 | $form = new FormValidator('report', 'post', null, null, ['class' => 'form-vertical']); |
||
210 | $form->addCheckBox('add_logo', '', get_lang('AddRightLogo'), ['id' => 'export_format_csv_label']); |
||
211 | $extra .= $form->returnForm(); |
||
212 | $extra .= '</div>'; |
||
213 | $output .= $extra; |
||
214 | |||
215 | $url_suffix = '&lp_id='.$lp_id; |
||
216 | if ('tracking' === $origin) { |
||
217 | $url_suffix = '&sid='.$sessionId.'&cid='.$courseId.'&student_id='.$user_id.'&lp_id='.$lp_id.'&origin='.$origin; |
||
218 | } |
||
219 | |||
220 | $extend_all = 0; |
||
221 | if (!empty($extendedAll)) { |
||
222 | $extend_all_link = Display::url( |
||
223 | Display::getMdiIcon( |
||
224 | ActionIcon::VIEW_LESS, |
||
225 | 'ch-tool-icon', |
||
226 | null, |
||
227 | ICON_SIZE_SMALL, |
||
228 | get_lang('Hide all attempts') |
||
229 | ), |
||
230 | api_get_self().'?action=stats'.$url_suffix |
||
231 | ); |
||
232 | $extend_all = 1; |
||
233 | } else { |
||
234 | $extend_all_link = Display::url( |
||
235 | Display::getMdiIcon( |
||
236 | ActionIcon::VIEW_MORE, |
||
237 | 'ch-tool-icon', |
||
238 | null, |
||
239 | ICON_SIZE_SMALL, |
||
240 | get_lang('Show all attempts') |
||
241 | ), |
||
242 | api_get_self().'?action=stats&extend_all=1'.$url_suffix |
||
243 | ); |
||
244 | } |
||
245 | |||
246 | if ('tracking' !== $origin) { |
||
247 | $output .= '<div class="section-status">'; |
||
248 | $output .= Display::page_header(get_lang('My progress')); |
||
249 | $output .= '</div>'; |
||
250 | } |
||
251 | |||
252 | $actionColumn = null; |
||
253 | if ('classic' === $type) { |
||
254 | $actionColumn = ' <th>'.get_lang('Detail').'</th>'; |
||
255 | } |
||
256 | |||
257 | $timeHeader = '<th class="lp_time" colspan="2">'.get_lang('Time').'</th>'; |
||
258 | if ($hideTime) { |
||
259 | $timeHeader = ''; |
||
260 | } |
||
261 | $output .= '<div class="table-responsive">'; |
||
262 | $output .= '<table id="lp_tracking" class="table tracking"> |
||
263 | <thead> |
||
264 | <tr class="table-header"> |
||
265 | <th width="16">'.(true === $allowExtend ? $extend_all_link : ' ').'</th> |
||
266 | <th colspan="4"> |
||
267 | '.get_lang('Learning object name').' |
||
268 | </th> |
||
269 | <th colspan="2"> |
||
270 | '.get_lang('Status').' |
||
271 | </th> |
||
272 | <th colspan="2"> |
||
273 | '.get_lang('Score').' |
||
274 | </th> |
||
275 | '.$timeHeader.' |
||
276 | '.$actionColumn.' |
||
277 | </tr> |
||
278 | </thead> |
||
279 | <tbody> |
||
280 | '; |
||
281 | |||
282 | // Going through the items using the $items[] array instead of the database order ensures |
||
283 | // we get them in the same order as in the imsmanifest file, which is rather random when using |
||
284 | // the database table. |
||
285 | $TBL_LP_ITEM = Database::get_course_table(TABLE_LP_ITEM); |
||
286 | $TBL_LP_ITEM_VIEW = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
287 | $TBL_LP_VIEW = Database::get_course_table(TABLE_LP_VIEW); |
||
288 | $tbl_quiz_questions = Database::get_course_table(TABLE_QUIZ_QUESTION); |
||
289 | $TBL_QUIZ = Database::get_course_table(TABLE_QUIZ_TEST); |
||
290 | $tbl_stats_exercices = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
291 | $tbl_stats_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
292 | |||
293 | $sql = "SELECT max(view_count) |
||
294 | FROM $TBL_LP_VIEW |
||
295 | WHERE |
||
296 | c_id = $courseId AND |
||
297 | lp_id = $lp_id AND |
||
298 | user_id = $user_id |
||
299 | $session_condition"; |
||
300 | $res = Database::query($sql); |
||
301 | $view = 0; |
||
302 | if (Database::num_rows($res) > 0) { |
||
303 | $myrow = Database::fetch_array($res); |
||
304 | $view = (int) $myrow[0]; |
||
305 | } |
||
306 | |||
307 | $counter = 0; |
||
308 | $total_time = 0; |
||
309 | $h = get_lang('h'); |
||
310 | |||
311 | if (!empty($export_csv)) { |
||
312 | $csvHeaders = [ |
||
313 | get_lang('Learning object name'), |
||
314 | get_lang('Status'), |
||
315 | get_lang('Score'), |
||
316 | ]; |
||
317 | |||
318 | if (false === $hideTime) { |
||
319 | $csvHeaders[] = get_lang('Time'); |
||
320 | } |
||
321 | $csv_content[] = $csvHeaders; |
||
322 | } |
||
323 | |||
324 | $result_disabled_ext_all = true; |
||
325 | $chapterTypes = learnpath::getChapterTypes(); |
||
326 | $accessToPdfExport = api_is_allowed_to_edit(false, false, true); |
||
327 | |||
328 | $minimumAvailable = self::minimumTimeAvailable($sessionId, $courseId); |
||
329 | $timeCourse = []; |
||
330 | if ($minimumAvailable) { |
||
331 | $timeCourse = self::getCalculateTime($user_id, $courseId, $sessionId); |
||
332 | Session::write('trackTimeCourse', $timeCourse); |
||
333 | } |
||
334 | |||
335 | // Show lp items |
||
336 | if (is_array($list) && count($list) > 0) { |
||
337 | foreach ($list as $my_item_id) { |
||
338 | $extend_this = 0; |
||
339 | $order = 'DESC'; |
||
340 | if ((!empty($extendId) && $extendId == $my_item_id) || $extend_all) { |
||
341 | $extend_this = 1; |
||
342 | $order = 'ASC'; |
||
343 | } |
||
344 | |||
345 | // Prepare statement to go through each attempt. |
||
346 | $viewCondition = null; |
||
347 | if (!empty($view)) { |
||
348 | $viewCondition = " AND v.view_count = $view "; |
||
349 | } |
||
350 | |||
351 | $sql = "SELECT |
||
352 | iv.status as mystatus, |
||
353 | v.view_count as mycount, |
||
354 | iv.score as myscore, |
||
355 | iv.total_time as mytime, |
||
356 | i.iid as myid, |
||
357 | i.lp_id as mylpid, |
||
358 | iv.lp_view_id as mylpviewid, |
||
359 | i.title as mytitle, |
||
360 | i.max_score as mymaxscore, |
||
361 | iv.max_score as myviewmaxscore, |
||
362 | i.item_type as item_type, |
||
363 | iv.view_count as iv_view_count, |
||
364 | iv.iid as iv_id, |
||
365 | path |
||
366 | FROM $TBL_LP_ITEM as i |
||
367 | INNER JOIN $TBL_LP_ITEM_VIEW as iv |
||
368 | ON (i.iid = iv.lp_item_id) |
||
369 | INNER JOIN $TBL_LP_VIEW as v |
||
370 | ON (iv.lp_view_id = v.iid) |
||
371 | WHERE |
||
372 | i.iid = $my_item_id AND |
||
373 | i.lp_id = $lp_id AND |
||
374 | v.user_id = $user_id |
||
375 | $session_condition |
||
376 | $viewCondition |
||
377 | ORDER BY iv.view_count $order "; |
||
378 | |||
379 | $result = Database::query($sql); |
||
380 | $num = Database::num_rows($result); |
||
381 | $time_for_total = 0; |
||
382 | $attemptResult = 0; |
||
383 | |||
384 | if ($timeCourse) { |
||
385 | if (isset($timeCourse['learnpath_detailed']) && |
||
386 | isset($timeCourse['learnpath_detailed'][$lp_id]) && |
||
387 | isset($timeCourse['learnpath_detailed'][$lp_id][$my_item_id]) |
||
388 | ) { |
||
389 | $attemptResult = $timeCourse['learnpath_detailed'][$lp_id][$my_item_id][$view]; |
||
390 | } |
||
391 | } |
||
392 | |||
393 | // Extend all |
||
394 | if (($extend_this || $extend_all) && $num > 0) { |
||
395 | $row = Database::fetch_array($result); |
||
396 | $result_disabled_ext_all = false; |
||
397 | if ('quiz' === $row['item_type']) { |
||
398 | // Check results_disabled in quiz table. |
||
399 | $my_path = Database::escape_string($row['path']); |
||
400 | $sql = "SELECT results_disabled |
||
401 | FROM $TBL_QUIZ |
||
402 | WHERE |
||
403 | iid ='".$my_path."'"; |
||
404 | $res_result_disabled = Database::query($sql); |
||
405 | $row_result_disabled = Database::fetch_row($res_result_disabled); |
||
406 | |||
407 | if (Database::num_rows($res_result_disabled) > 0 && |
||
408 | 1 === (int) $row_result_disabled[0] |
||
409 | ) { |
||
410 | $result_disabled_ext_all = true; |
||
411 | } |
||
412 | } |
||
413 | |||
414 | // If there are several attempts, and the link to extend has been clicked, show each attempt... |
||
415 | $oddclass = 'row_even'; |
||
416 | if (0 === ($counter % 2)) { |
||
417 | $oddclass = 'row_odd'; |
||
418 | } |
||
419 | $extend_link = ''; |
||
420 | if (!empty($inter_num)) { |
||
421 | $extend_link = Display::url( |
||
422 | Display::getMdiIcon( |
||
423 | ActionIcon::VISIBLE, |
||
424 | 'ch-tool-icon', |
||
425 | null, |
||
426 | ICON_SIZE_SMALL, |
||
427 | get_lang('Hide attempt view') |
||
428 | ), |
||
429 | api_get_self().'?action=stats&fold_id='.$my_item_id.$url_suffix |
||
430 | ); |
||
431 | } |
||
432 | $title = $row['mytitle']; |
||
433 | |||
434 | if (empty($title)) { |
||
435 | $title = learnpath::rl_get_resource_name($courseInfo['code'], $lp_id, $row['myid']); |
||
436 | } |
||
437 | |||
438 | if (in_array($row['item_type'], $chapterTypes)) { |
||
439 | $title = "<h4> $title </h4>"; |
||
440 | } |
||
441 | $lesson_status = $row['mystatus']; |
||
442 | $title = Security::remove_XSS($title); |
||
443 | $counter++; |
||
444 | |||
445 | $action = null; |
||
446 | if ('classic' === $type) { |
||
447 | $action = '<td></td>'; |
||
448 | } |
||
449 | |||
450 | if (in_array($row['item_type'], $chapterTypes)) { |
||
451 | $output .= '<tr class="'.$oddclass.'"> |
||
452 | <td>'.$extend_link.'</td> |
||
453 | <td colspan="4"> |
||
454 | '.$title.' |
||
455 | </td> |
||
456 | <td colspan="2">'.learnpathItem::humanize_status($lesson_status, true, $type).'</td> |
||
457 | <td colspan="2"></td> |
||
458 | <td colspan="2"></td> |
||
459 | '.$action.' |
||
460 | </tr>'; |
||
461 | continue; |
||
462 | } else { |
||
463 | $output .= '<tr class="'.$oddclass.'"> |
||
464 | <td>'.$extend_link.'</td> |
||
465 | <td colspan="4">'.$title.'</td> |
||
466 | <td colspan="2"></td> |
||
467 | <td colspan="2"></td> |
||
468 | <td colspan="2"></td> |
||
469 | '.$action.' |
||
470 | </tr>'; |
||
471 | } |
||
472 | |||
473 | $attemptCount = 1; |
||
474 | do { |
||
475 | // Check if there are interactions below. |
||
476 | $extend_attempt_link = ''; |
||
477 | $extend_this_attempt = 0; |
||
478 | |||
479 | if ($timeCourse) { |
||
480 | //$attemptResult = 0; |
||
481 | if (isset($timeCourse['learnpath_detailed']) && |
||
482 | isset($timeCourse['learnpath_detailed'][$lp_id]) && |
||
483 | isset($timeCourse['learnpath_detailed'][$lp_id][$my_item_id]) |
||
484 | ) { |
||
485 | $attemptResult = $timeCourse['learnpath_detailed'][$lp_id][$my_item_id][$row['iv_view_count']]; |
||
486 | } |
||
487 | } |
||
488 | if (( |
||
489 | learnpath::get_interactions_count_from_db($row['iv_id'], $courseId) > 0 || |
||
490 | learnpath::get_objectives_count_from_db($row['iv_id'], $courseId) > 0 |
||
491 | ) && |
||
492 | !$extend_all |
||
493 | ) { |
||
494 | if ($extendAttemptId == $row['iv_id']) { |
||
495 | // The extend button for this attempt has been clicked. |
||
496 | $extend_this_attempt = 1; |
||
497 | $extend_attempt_link = Display::url( |
||
498 | Display::getMdiIcon( |
||
499 | ActionIcon::VISIBLE, |
||
500 | 'ch-tool-icon', |
||
501 | null, |
||
502 | ICON_SIZE_SMALL, |
||
503 | get_lang('Hide attempt view') |
||
504 | ), |
||
505 | api_get_self().'?action=stats&extend_id='.$my_item_id.'&fold_attempt_id='.$row['iv_id'].$url_suffix |
||
506 | ); |
||
507 | if ($accessToPdfExport) { |
||
508 | $extend_attempt_link .= ' '. |
||
509 | Display::url( |
||
510 | Display::getMdiIcon( |
||
511 | ActionIcon::EXPORT_PDF, |
||
512 | 'ch-tool-icon', |
||
513 | null, |
||
514 | ICON_SIZE_SMALL, |
||
515 | get_lang('Export to PDF') |
||
516 | ), |
||
517 | api_get_self().'?action=export_stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix, |
||
518 | ['class' => 'export'] |
||
519 | ); |
||
520 | } |
||
521 | } else { // Same case if fold_attempt_id is set, so not implemented explicitly. |
||
522 | // The "extend" button for this attempt has not been clicked. |
||
523 | $extend_attempt_link = Display::url( |
||
524 | Display::getMdiIcon( |
||
525 | ActionIcon::INVISIBLE, |
||
526 | 'ch-tool-icon', |
||
527 | null, |
||
528 | ICON_SIZE_SMALL, |
||
529 | get_lang('Extend attempt view') |
||
530 | ), |
||
531 | api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix |
||
532 | ); |
||
533 | if ($accessToPdfExport) { |
||
534 | $extend_attempt_link .= ' '. |
||
535 | Display::url( |
||
536 | Display::getMdiIcon( |
||
537 | ActionIcon::EXPORT_PDF, |
||
538 | 'ch-tool-icon', |
||
539 | null, |
||
540 | ICON_SIZE_SMALL, |
||
541 | get_lang('Export to PDF') |
||
542 | ), |
||
543 | api_get_self().'?action=export_stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix, |
||
544 | ['class' => 'export'] |
||
545 | ); |
||
546 | } |
||
547 | } |
||
548 | } |
||
549 | |||
550 | $oddclass = 'row_even'; |
||
551 | if (0 == ($counter % 2)) { |
||
552 | $oddclass = 'row_odd'; |
||
553 | } |
||
554 | |||
555 | $lesson_status = $row['mystatus']; |
||
556 | $score = $row['myscore']; |
||
557 | $time_for_total += $row['mytime']; |
||
558 | $attemptTime = $row['mytime']; |
||
559 | |||
560 | if ($minimumAvailable) { |
||
561 | $lp_time = $timeCourse[TOOL_LEARNPATH]; |
||
562 | $lpTime = null; |
||
563 | if (isset($lp_time[$lp_id])) { |
||
564 | $lpTime = (int) $lp_time[$lp_id]; |
||
565 | } |
||
566 | $time_for_total = $lpTime; |
||
567 | |||
568 | if ($timeCourse) { |
||
569 | $time_for_total = (int) $attemptResult; |
||
570 | $attemptTime = (int) $attemptResult; |
||
571 | } |
||
572 | } |
||
573 | |||
574 | $time = learnpathItem::getScormTimeFromParameter('js', $attemptTime); |
||
575 | |||
576 | if (0 == $score) { |
||
577 | $maxscore = $row['mymaxscore']; |
||
578 | } else { |
||
579 | if ('sco' === $row['item_type']) { |
||
580 | if (!empty($row['myviewmaxscore']) && $row['myviewmaxscore'] > 0) { |
||
581 | $maxscore = $row['myviewmaxscore']; |
||
582 | } elseif ('' === $row['myviewmaxscore']) { |
||
583 | $maxscore = 0; |
||
584 | } else { |
||
585 | $maxscore = $row['mymaxscore']; |
||
586 | } |
||
587 | } else { |
||
588 | $maxscore = $row['mymaxscore']; |
||
589 | } |
||
590 | } |
||
591 | |||
592 | // Remove "NaN" if any (@todo: locate the source of these NaN) |
||
593 | $time = str_replace('NaN', '00'.$h.'00\'00"', $time); |
||
594 | |||
595 | if ('dir' !== $row['item_type']) { |
||
596 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
597 | $view_score = Display::getMdiIcon( |
||
598 | ActionIcon::INVISIBLE, |
||
599 | 'ch-tool-icon', |
||
600 | null, |
||
601 | ICON_SIZE_SMALL, |
||
602 | get_lang('Results hidden by the exercise setting') |
||
603 | ); |
||
604 | } else { |
||
605 | switch ($row['item_type']) { |
||
606 | case 'sco': |
||
607 | if (0 == $maxscore) { |
||
608 | $view_score = $score; |
||
609 | } else { |
||
610 | $view_score = ExerciseLib::show_score( |
||
611 | $score, |
||
612 | $maxscore, |
||
613 | false |
||
614 | ); |
||
615 | } |
||
616 | break; |
||
617 | case 'document': |
||
618 | $view_score = (0 == $score ? '/' : ExerciseLib::show_score($score, $maxscore, false)); |
||
619 | break; |
||
620 | default: |
||
621 | $view_score = ExerciseLib::show_score( |
||
622 | $score, |
||
623 | $maxscore, |
||
624 | false |
||
625 | ); |
||
626 | break; |
||
627 | } |
||
628 | } |
||
629 | |||
630 | $action = null; |
||
631 | if ('classic' === $type) { |
||
632 | $action = '<td></td>'; |
||
633 | } |
||
634 | $timeRow = '<td class="lp_time" colspan="2">'.$time.'</td>'; |
||
635 | if ($hideTime) { |
||
636 | $timeRow = ''; |
||
637 | } |
||
638 | $output .= '<tr class="'.$oddclass.'"> |
||
639 | <td></td> |
||
640 | <td style="width:70px;float:left;">'.$extend_attempt_link.'</td> |
||
641 | <td colspan="3">'.get_lang('Attempt').' '.$attemptCount.'</td> |
||
642 | <td colspan="2">'.learnpathItem::humanize_status($lesson_status, true, $type).'</td> |
||
643 | <td colspan="2">'.$view_score.'</td> |
||
644 | '.$timeRow.' |
||
645 | '.$action.' |
||
646 | </tr>'; |
||
647 | $attemptCount++; |
||
648 | if (!empty($export_csv)) { |
||
649 | $temp = []; |
||
650 | $temp[] = $title = Security::remove_XSS($title); |
||
651 | $temp[] = Security::remove_XSS( |
||
652 | learnpathItem::humanize_status($lesson_status, false, $type) |
||
653 | ); |
||
654 | |||
655 | if ('quiz' === $row['item_type']) { |
||
656 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
657 | $temp[] = '/'; |
||
658 | } else { |
||
659 | $temp[] = (0 == $score ? '0/'.$maxscore : (0 == $maxscore ? $score : $score.'/'.float_format($maxscore, 1))); |
||
660 | } |
||
661 | } else { |
||
662 | $temp[] = (0 == $score ? '/' : (0 == $maxscore ? $score : $score.'/'.float_format($maxscore, 1))); |
||
663 | } |
||
664 | |||
665 | if (false === $hideTime) { |
||
666 | $temp[] = $time; |
||
667 | } |
||
668 | $csv_content[] = $temp; |
||
669 | } |
||
670 | } |
||
671 | |||
672 | $counter++; |
||
673 | $action = null; |
||
674 | if ('classic' === $type) { |
||
675 | $action = '<td></td>'; |
||
676 | } |
||
677 | |||
678 | if ($extend_this_attempt || $extend_all) { |
||
679 | $list1 = learnpath::get_iv_interactions_array($row['iv_id'], $courseId); |
||
680 | foreach ($list1 as $id => $interaction) { |
||
681 | $oddclass = 'row_even'; |
||
682 | if (0 == ($counter % 2)) { |
||
683 | $oddclass = 'row_odd'; |
||
684 | } |
||
685 | $timeRow = '<td class="lp_time">'.$interaction['time'].'</td>'; |
||
686 | if ($hideTime) { |
||
687 | $timeRow = ''; |
||
688 | } |
||
689 | |||
690 | $output .= '<tr class="'.$oddclass.'"> |
||
691 | <td></td> |
||
692 | <td></td> |
||
693 | <td></td> |
||
694 | <td>'.$interaction['order_id'].'</td> |
||
695 | <td>'.$interaction['id'].'</td>'; |
||
696 | |||
697 | $output .= ' |
||
698 | <td colspan="2">'.$interaction['type'].'</td> |
||
699 | <td>'.$interaction['student_response_formatted'].'</td> |
||
700 | <td>'.$interaction['result'].'</td> |
||
701 | <td>'.$interaction['latency'].'</td> |
||
702 | '.$timeRow.' |
||
703 | '.$action.' |
||
704 | </tr>'; |
||
705 | $counter++; |
||
706 | } |
||
707 | $list2 = learnpath::get_iv_objectives_array($row['iv_id'], $courseId); |
||
708 | foreach ($list2 as $id => $interaction) { |
||
709 | $oddclass = 'row_even'; |
||
710 | if (0 === ($counter % 2)) { |
||
711 | $oddclass = 'row_odd'; |
||
712 | } |
||
713 | $output .= '<tr class="'.$oddclass.'"> |
||
714 | <td></td> |
||
715 | <td></td> |
||
716 | <td></td> |
||
717 | <td>'.$interaction['order_id'].'</td> |
||
718 | <td colspan="2">'.$interaction['objective_id'].'</td> |
||
719 | <td colspan="2">'.$interaction['status'].'</td> |
||
720 | <td>'.$interaction['score_raw'].'</td> |
||
721 | <td>'.$interaction['score_max'].'</td> |
||
722 | <td>'.$interaction['score_min'].'</td> |
||
723 | '.$action.' |
||
724 | </tr>'; |
||
725 | $counter++; |
||
726 | } |
||
727 | } |
||
728 | } while ($row = Database::fetch_array($result)); |
||
729 | } elseif ($num > 0) { |
||
730 | // Not extended. |
||
731 | $row = Database::fetch_assoc($result); |
||
732 | $my_id = $row['myid']; |
||
733 | $my_lp_id = $row['mylpid']; |
||
734 | $my_lp_view_id = $row['mylpviewid']; |
||
735 | $my_path = $row['path']; |
||
736 | $result_disabled_ext_all = false; |
||
737 | if ('quiz' === $row['item_type']) { |
||
738 | // Check results_disabled in quiz table. |
||
739 | $my_path = Database::escape_string($my_path); |
||
740 | $sql = "SELECT results_disabled |
||
741 | FROM $TBL_QUIZ |
||
742 | WHERE iid = '$my_path' "; |
||
743 | $res_result_disabled = Database::query($sql); |
||
744 | $row_result_disabled = Database::fetch_row($res_result_disabled); |
||
745 | |||
746 | if (Database::num_rows($res_result_disabled) > 0 && |
||
747 | 1 === (int) $row_result_disabled[0] |
||
748 | ) { |
||
749 | $result_disabled_ext_all = true; |
||
750 | } |
||
751 | } |
||
752 | |||
753 | // Check if there are interactions below |
||
754 | $extend_this_attempt = 0; |
||
755 | $inter_num = learnpath::get_interactions_count_from_db($row['iv_id'], $courseId); |
||
756 | $objec_num = learnpath::get_objectives_count_from_db($row['iv_id'], $courseId); |
||
757 | $extend_attempt_link = ''; |
||
758 | if ($inter_num > 0 || $objec_num > 0) { |
||
759 | if (!empty($extendAttemptId) && $extendAttemptId == $row['iv_id']) { |
||
760 | // The extend button for this attempt has been clicked. |
||
761 | $extend_this_attempt = 1; |
||
762 | $extend_attempt_link = Display::url( |
||
763 | Display::getMdiIcon( |
||
764 | ActionIcon::VISIBLE, |
||
765 | 'ch-tool-icon', |
||
766 | null, |
||
767 | ICON_SIZE_SMALL, |
||
768 | get_lang('Hide attempt view') |
||
769 | ), |
||
770 | api_get_self().'?action=stats&extend_id='.$my_item_id.'&fold_attempt_id='.$row['iv_id'].$url_suffix |
||
771 | ); |
||
772 | } else { |
||
773 | // Same case if fold_attempt_id is set, so not implemented explicitly. |
||
774 | // The "Extend" button for this attempt has not been clicked. |
||
775 | $extend_attempt_link = Display::url( |
||
776 | Display::getMdiIcon( |
||
777 | ActionIcon::INVISIBLE, |
||
778 | 'ch-tool-icon', |
||
779 | null, |
||
780 | ICON_SIZE_SMALL, |
||
781 | get_lang('Extend attempt view') |
||
782 | ), |
||
783 | api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix |
||
784 | ); |
||
785 | } |
||
786 | } |
||
787 | |||
788 | $oddclass = 'row_even'; |
||
789 | if (0 == ($counter % 2)) { |
||
790 | $oddclass = 'row_odd'; |
||
791 | } |
||
792 | |||
793 | $extend_link = ''; |
||
794 | if ($inter_num > 1) { |
||
795 | $extend_link = Display::url( |
||
796 | Display::getMdiIcon( |
||
797 | ActionIcon::INVISIBLE, |
||
798 | 'ch-tool-icon', |
||
799 | null, |
||
800 | ICON_SIZE_SMALL, |
||
801 | get_lang('Extend attempt view') |
||
802 | ), |
||
803 | api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix |
||
804 | ); |
||
805 | } |
||
806 | |||
807 | $lesson_status = $row['mystatus']; |
||
808 | $score = $row['myscore']; |
||
809 | $subtotal_time = $row['mytime']; |
||
810 | while ($tmp_row = Database::fetch_array($result)) { |
||
811 | $subtotal_time += $tmp_row['mytime']; |
||
812 | } |
||
813 | |||
814 | $title = $row['mytitle']; |
||
815 | $sessionCondition = api_get_session_condition($sessionId); |
||
816 | // Selecting the exe_id from stats attempts tables in order to look the max score value. |
||
817 | $sql = 'SELECT * FROM '.$tbl_stats_exercices.' |
||
818 | WHERE |
||
819 | exe_exo_id="'.$row['path'].'" AND |
||
820 | exe_user_id="'.$user_id.'" AND |
||
821 | orig_lp_id = "'.$lp_id.'" AND |
||
822 | orig_lp_item_id = "'.$row['myid'].'" AND |
||
823 | c_id = '.$courseId.' AND |
||
824 | status <> "incomplete" |
||
825 | '.$sessionCondition.' |
||
826 | ORDER BY exe_date DESC |
||
827 | LIMIT 1'; |
||
828 | |||
829 | $resultLastAttempt = Database::query($sql); |
||
830 | $num = Database::num_rows($resultLastAttempt); |
||
831 | $id_last_attempt = null; |
||
832 | if ($num > 0) { |
||
833 | while ($rowLA = Database::fetch_array($resultLastAttempt)) { |
||
834 | $id_last_attempt = $rowLA['exe_id']; |
||
835 | } |
||
836 | } |
||
837 | |||
838 | switch ($row['item_type']) { |
||
839 | case 'sco': |
||
840 | if (!empty($row['myviewmaxscore']) && $row['myviewmaxscore'] > 0) { |
||
841 | $maxscore = $row['myviewmaxscore']; |
||
842 | } elseif ('' === $row['myviewmaxscore']) { |
||
843 | $maxscore = 0; |
||
844 | } else { |
||
845 | $maxscore = $row['mymaxscore']; |
||
846 | } |
||
847 | break; |
||
848 | case 'quiz': |
||
849 | // Get score and total time from last attempt of a exercise en lp. |
||
850 | $sql = "SELECT iid, score |
||
851 | FROM $TBL_LP_ITEM_VIEW |
||
852 | WHERE |
||
853 | lp_item_id = '".(int) $my_id."' AND |
||
854 | lp_view_id = '".(int) $my_lp_view_id."' |
||
855 | ORDER BY view_count DESC |
||
856 | LIMIT 1"; |
||
857 | $res_score = Database::query($sql); |
||
858 | $row_score = Database::fetch_array($res_score); |
||
859 | |||
860 | $sql = "SELECT SUM(total_time) as total_time |
||
861 | FROM $TBL_LP_ITEM_VIEW |
||
862 | WHERE |
||
863 | lp_item_id = '".(int) $my_id."' AND |
||
864 | lp_view_id = '".(int) $my_lp_view_id."'"; |
||
865 | $res_time = Database::query($sql); |
||
866 | $row_time = Database::fetch_array($res_time); |
||
867 | |||
868 | $score = 0; |
||
869 | $subtotal_time = 0; |
||
870 | if (Database::num_rows($res_score) > 0 && |
||
871 | Database::num_rows($res_time) > 0 |
||
872 | ) { |
||
873 | $score = (float) $row_score['score']; |
||
874 | $subtotal_time = (int) $row_time['total_time']; |
||
875 | } |
||
876 | // Selecting the max score from an attempt. |
||
877 | $sql = "SELECT SUM(t.ponderation) as maxscore |
||
878 | FROM ( |
||
879 | SELECT DISTINCT |
||
880 | question_id, marks, ponderation |
||
881 | FROM $tbl_stats_attempts as at |
||
882 | INNER JOIN $tbl_quiz_questions as q |
||
883 | ON (q.iid = at.question_id) |
||
884 | WHERE exe_id ='$id_last_attempt' |
||
885 | ) as t"; |
||
886 | |||
887 | $result = Database::query($sql); |
||
888 | $row_max_score = Database::fetch_array($result); |
||
889 | $maxscore = $row_max_score['maxscore']; |
||
890 | |||
891 | // Get duration time from track_e_exercises.exe_duration instead of lp_view_item.total_time |
||
892 | $sql = 'SELECT SUM(exe_duration) exe_duration |
||
893 | FROM '.$tbl_stats_exercices.' |
||
894 | WHERE |
||
895 | exe_exo_id="'.$row['path'].'" AND |
||
896 | exe_user_id="'.$user_id.'" AND |
||
897 | orig_lp_id = "'.$lp_id.'" AND |
||
898 | orig_lp_item_id = "'.$row['myid'].'" AND |
||
899 | c_id = '.$courseId.' AND |
||
900 | status <> "incomplete" AND |
||
901 | session_id = '.$sessionId.' |
||
902 | ORDER BY exe_date DESC '; |
||
903 | $sumScoreResult = Database::query($sql); |
||
904 | $durationRow = Database::fetch_assoc($sumScoreResult); |
||
905 | if (!empty($durationRow['exe_duration'])) { |
||
906 | $exeDuration = $durationRow['exe_duration']; |
||
907 | if ($exeDuration != $subtotal_time && |
||
908 | !empty($row_score['iid']) && |
||
909 | !empty($exeDuration) |
||
910 | ) { |
||
911 | $subtotal_time = $exeDuration; |
||
912 | // Update c_lp_item_view.total_time |
||
913 | $sqlUpdate = "UPDATE $TBL_LP_ITEM_VIEW SET total_time = '$exeDuration' |
||
914 | WHERE iid = ".$row_score['iid']; |
||
915 | Database::query($sqlUpdate); |
||
916 | } |
||
917 | } |
||
918 | break; |
||
919 | default: |
||
920 | $maxscore = $row['mymaxscore']; |
||
921 | break; |
||
922 | } |
||
923 | |||
924 | $time_for_total = $subtotal_time; |
||
925 | $time = learnpathItem::getScormTimeFromParameter('js', $subtotal_time); |
||
926 | if (empty($title)) { |
||
927 | $title = learnpath::rl_get_resource_name( |
||
928 | $courseInfo['code'], |
||
929 | $lp_id, |
||
930 | $row['myid'] |
||
931 | ); |
||
932 | } |
||
933 | |||
934 | $action = null; |
||
935 | if ('classic' === $type) { |
||
936 | $action = '<td></td>'; |
||
937 | } |
||
938 | |||
939 | if (in_array($row['item_type'], $chapterTypes)) { |
||
940 | $title = Security::remove_XSS($title); |
||
941 | $output .= '<tr class="'.$oddclass.'"> |
||
942 | <td>'.$extend_link.'</td> |
||
943 | <td colspan="10"> |
||
944 | <h4>'.$title.'</h4> |
||
945 | </td> |
||
946 | '.$action.' |
||
947 | </tr>'; |
||
948 | } else { |
||
949 | $correct_test_link = '-'; |
||
950 | $showRowspan = false; |
||
951 | if ('quiz' === $row['item_type']) { |
||
952 | $my_url_suffix = '&cid='.$courseId.'&student_id='.$user_id.'&lp_id='.intval($row['mylpid']).'&origin='.$origin; |
||
953 | $sql = 'SELECT * FROM '.$tbl_stats_exercices.' |
||
954 | WHERE |
||
955 | exe_exo_id="'.$row['path'].'" AND |
||
956 | exe_user_id="'.$user_id.'" AND |
||
957 | orig_lp_id = "'.$lp_id.'" AND |
||
958 | orig_lp_item_id = "'.$row['myid'].'" AND |
||
959 | c_id = '.$courseId.' AND |
||
960 | status <> "incomplete" AND |
||
961 | session_id = '.$sessionId.' |
||
962 | ORDER BY exe_date DESC '; |
||
963 | |||
964 | $resultLastAttempt = Database::query($sql); |
||
965 | $num = Database::num_rows($resultLastAttempt); |
||
966 | $showRowspan = false; |
||
967 | if ($num > 0) { |
||
968 | $linkId = 'link_'.$my_id; |
||
969 | if (1 == $extendedAttempt && |
||
970 | $lp_id == $my_lp_id && |
||
971 | $lp_item_id == $my_id |
||
972 | ) { |
||
973 | $showRowspan = true; |
||
974 | $correct_test_link = Display::url( |
||
975 | Display::getMdiIcon( |
||
976 | ActionIcon::VIEW_LESS, |
||
977 | 'ch-tool-icon', |
||
978 | null, |
||
979 | ICON_SIZE_SMALL, |
||
980 | get_lang('Hide all attempts') |
||
981 | ), |
||
982 | api_get_self().'?action=stats'.$my_url_suffix.'&sid='.$sessionId.'&lp_item_id='.$my_id.'#'.$linkId, |
||
983 | ['id' => $linkId] |
||
984 | ); |
||
985 | } else { |
||
986 | $correct_test_link = Display::url( |
||
987 | Display::getMdiIcon( |
||
988 | ActionIcon::VIEW_MORE, |
||
989 | 'ch-tool-icon', |
||
990 | null, |
||
991 | ICON_SIZE_SMALL, |
||
992 | get_lang( |
||
993 | 'Show all attemptsByExercise' |
||
994 | ) |
||
995 | ), |
||
996 | api_get_self().'?action=stats&extend_attempt=1'.$my_url_suffix.'&sid='.$sessionId.'&lp_item_id='.$my_id.'#'.$linkId, |
||
997 | ['id' => $linkId] |
||
998 | ); |
||
999 | } |
||
1000 | } |
||
1001 | } |
||
1002 | |||
1003 | $title = Security::remove_XSS($title); |
||
1004 | $action = null; |
||
1005 | if ('classic' === $type) { |
||
1006 | $action = '<td '.($showRowspan ? 'rowspan="2"' : '').'>'.$correct_test_link.'</td>'; |
||
1007 | } |
||
1008 | |||
1009 | if ($lp_id == $my_lp_id && false) { |
||
1010 | $output .= '<tr class ='.$oddclass.'> |
||
1011 | <td>'.$extend_link.'</td> |
||
1012 | <td colspan="4">'.$title.'</td> |
||
1013 | <td colspan="2"> </td> |
||
1014 | <td colspan="2"> </td> |
||
1015 | <td colspan="2"> </td> |
||
1016 | '.$action.' |
||
1017 | </tr>'; |
||
1018 | $output .= '</tr>'; |
||
1019 | } else { |
||
1020 | if ($lp_id == $my_lp_id && $lp_item_id == $my_id) { |
||
1021 | $output .= "<tr class='$oddclass'>"; |
||
1022 | } else { |
||
1023 | $output .= "<tr class='$oddclass'>"; |
||
1024 | } |
||
1025 | |||
1026 | $scoreItem = null; |
||
1027 | if ('quiz' === $row['item_type']) { |
||
1028 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
1029 | $scoreItem .= Display::getMdiIcon( |
||
1030 | ActionIcon::INVISIBLE, |
||
1031 | 'ch-tool-icon', |
||
1032 | null, |
||
1033 | ICON_SIZE_SMALL, |
||
1034 | get_lang('Results hidden by the exercise setting') |
||
1035 | ); |
||
1036 | } else { |
||
1037 | $scoreItem .= ExerciseLib::show_score($score, $maxscore, false); |
||
1038 | } |
||
1039 | } else { |
||
1040 | $scoreItem .= 0 == $score ? '/' : (0 == $maxscore ? $score : $score.'/'.$maxscore); |
||
1041 | } |
||
1042 | |||
1043 | $timeRow = '<td class="lp_time" colspan="2">'.$time.'</td>'; |
||
1044 | if ($hideTime) { |
||
1045 | $timeRow = ''; |
||
1046 | } |
||
1047 | |||
1048 | $output .= ' |
||
1049 | <td>'.$extend_link.'</td> |
||
1050 | <td colspan="4">'.$title.'</td> |
||
1051 | <td colspan="2">'.learnpathitem::humanize_status($lesson_status).'</td> |
||
1052 | <td colspan="2">'.$scoreItem.'</td> |
||
1053 | '.$timeRow.' |
||
1054 | '.$action.' |
||
1055 | '; |
||
1056 | $output .= '</tr>'; |
||
1057 | } |
||
1058 | |||
1059 | if (!empty($export_csv)) { |
||
1060 | $temp = []; |
||
1061 | $temp[] = api_html_entity_decode($title, ENT_QUOTES); |
||
1062 | $temp[] = api_html_entity_decode($lesson_status, ENT_QUOTES); |
||
1063 | if ('quiz' === $row['item_type']) { |
||
1064 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
1065 | $temp[] = '/'; |
||
1066 | } else { |
||
1067 | $temp[] = (0 == $score ? '0/'.$maxscore : (0 == $maxscore ? $score : $score.'/'.float_format($maxscore, 1))); |
||
1068 | } |
||
1069 | } else { |
||
1070 | $temp[] = (0 == $score ? '/' : (0 == $maxscore ? $score : $score.'/'.float_format($maxscore, 1))); |
||
1071 | } |
||
1072 | |||
1073 | if (false === $hideTime) { |
||
1074 | $temp[] = $time; |
||
1075 | } |
||
1076 | $csv_content[] = $temp; |
||
1077 | } |
||
1078 | } |
||
1079 | |||
1080 | $counter++; |
||
1081 | $action = null; |
||
1082 | if ('classic' === $type) { |
||
1083 | $action = '<td></td>'; |
||
1084 | } |
||
1085 | |||
1086 | if ($extend_this_attempt || $extend_all) { |
||
1087 | $list1 = learnpath::get_iv_interactions_array($row['iv_id'], $courseId); |
||
1088 | foreach ($list1 as $id => $interaction) { |
||
1089 | $oddclass = 'row_even'; |
||
1090 | if (0 == ($counter % 2)) { |
||
1091 | $oddclass = 'row_odd'; |
||
1092 | } |
||
1093 | $timeRow = '<td class="lp_time">'.$interaction['time'].'</td>'; |
||
1094 | if ($hideTime) { |
||
1095 | $timeRow = ''; |
||
1096 | } |
||
1097 | |||
1098 | $output .= '<tr class="'.$oddclass.'"> |
||
1099 | <td></td> |
||
1100 | <td></td> |
||
1101 | <td></td> |
||
1102 | <td>'.$interaction['order_id'].'</td> |
||
1103 | <td>'.$interaction['id'].'</td> |
||
1104 | <td colspan="2">'.$interaction['type'].'</td> |
||
1105 | <td>'.urldecode($interaction['student_response']).'</td> |
||
1106 | <td>'.$interaction['result'].'</td> |
||
1107 | <td>'.$interaction['latency'].'</td> |
||
1108 | '.$timeRow.' |
||
1109 | '.$action.' |
||
1110 | </tr>'; |
||
1111 | $counter++; |
||
1112 | } |
||
1113 | |||
1114 | $list2 = learnpath::get_iv_objectives_array($row['iv_id'], $courseId); |
||
1115 | foreach ($list2 as $id => $interaction) { |
||
1116 | $oddclass = 'row_even'; |
||
1117 | if (0 == ($counter % 2)) { |
||
1118 | $oddclass = 'row_odd'; |
||
1119 | } |
||
1120 | $output .= '<tr class="'.$oddclass.'"> |
||
1121 | <td></td> |
||
1122 | <td></td> |
||
1123 | <td></td> |
||
1124 | <td>'.$interaction['order_id'].'</td> |
||
1125 | <td colspan="2">'.$interaction['objective_id'].'</td> |
||
1126 | <td colspan="2">'.$interaction['status'].'</td> |
||
1127 | <td>'.$interaction['score_raw'].'</td> |
||
1128 | <td>'.$interaction['score_max'].'</td> |
||
1129 | <td>'.$interaction['score_min'].'</td> |
||
1130 | '.$action.' |
||
1131 | </tr>'; |
||
1132 | $counter++; |
||
1133 | } |
||
1134 | } |
||
1135 | |||
1136 | // Attempts listing by exercise. |
||
1137 | if ($lp_id == $my_lp_id && $lp_item_id == $my_id && $extendedAttempt) { |
||
1138 | // Get attempts of a exercise. |
||
1139 | if (!empty($lp_id) && |
||
1140 | !empty($lp_item_id) && |
||
1141 | 'quiz' === $row['item_type'] |
||
1142 | ) { |
||
1143 | $sql = "SELECT path FROM $TBL_LP_ITEM |
||
1144 | WHERE |
||
1145 | iid = '$lp_item_id' AND |
||
1146 | lp_id = '$lp_id'"; |
||
1147 | $res_path = Database::query($sql); |
||
1148 | $row_path = Database::fetch_array($res_path); |
||
1149 | |||
1150 | if (Database::num_rows($res_path) > 0) { |
||
1151 | $sql = 'SELECT * FROM '.$tbl_stats_exercices.' |
||
1152 | WHERE |
||
1153 | exe_exo_id="'.(int) $row_path['path'].'" AND |
||
1154 | status <> "incomplete" AND |
||
1155 | exe_user_id="'.$user_id.'" AND |
||
1156 | orig_lp_id = "'.(int) $lp_id.'" AND |
||
1157 | orig_lp_item_id = "'.(int) $lp_item_id.'" AND |
||
1158 | c_id = '.$courseId.' AND |
||
1159 | session_id = '.$sessionId.' |
||
1160 | ORDER BY exe_date'; |
||
1161 | $res_attempts = Database::query($sql); |
||
1162 | $num_attempts = Database::num_rows($res_attempts); |
||
1163 | if ($num_attempts > 0) { |
||
1164 | $n = 1; |
||
1165 | while ($row_attempts = Database::fetch_array($res_attempts)) { |
||
1166 | $my_score = $row_attempts['score']; |
||
1167 | $my_maxscore = $row_attempts['max_score']; |
||
1168 | $my_exe_id = $row_attempts['exe_id']; |
||
1169 | $mktime_start_date = api_strtotime($row_attempts['start_date'], 'UTC'); |
||
1170 | $mktime_exe_date = api_strtotime($row_attempts['exe_date'], 'UTC'); |
||
1171 | $time_attemp = ' - '; |
||
1172 | if ($mktime_start_date && $mktime_exe_date) { |
||
1173 | $time_attemp = api_format_time($row_attempts['exe_duration'], 'js'); |
||
1174 | } |
||
1175 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
1176 | $view_score = Display::getMdiIcon( |
||
1177 | ActionIcon::INVISIBLE, |
||
1178 | 'ch-tool-icon', |
||
1179 | null, |
||
1180 | ICON_SIZE_SMALL, |
||
1181 | get_lang('Results hidden by the exercise setting') |
||
1182 | ); |
||
1183 | } else { |
||
1184 | // Show only float when need it |
||
1185 | if (0 == $my_score) { |
||
1186 | $view_score = ExerciseLib::show_score( |
||
1187 | 0, |
||
1188 | $my_maxscore, |
||
1189 | false |
||
1190 | ); |
||
1191 | } else { |
||
1192 | if (0 == $my_maxscore) { |
||
1193 | $view_score = $my_score; |
||
1194 | } else { |
||
1195 | $view_score = ExerciseLib::show_score( |
||
1196 | $my_score, |
||
1197 | $my_maxscore, |
||
1198 | false |
||
1199 | ); |
||
1200 | } |
||
1201 | } |
||
1202 | } |
||
1203 | $my_lesson_status = $row_attempts['status']; |
||
1204 | if ('' === $my_lesson_status) { |
||
1205 | $my_lesson_status = learnpathitem::humanize_status('completed'); |
||
1206 | } elseif ('incomplete' === $my_lesson_status) { |
||
1207 | $my_lesson_status = learnpathitem::humanize_status('incomplete'); |
||
1208 | } |
||
1209 | $timeRow = '<td class="lp_time" colspan="2">'.$time_attemp.'</td>'; |
||
1210 | if ($hideTime) { |
||
1211 | $timeRow = ''; |
||
1212 | } |
||
1213 | |||
1214 | $output .= '<tr class="'.$oddclass.'" > |
||
1215 | <td></td> |
||
1216 | <td>'.$extend_attempt_link.'</td> |
||
1217 | <td colspan="3">'.get_lang('Attempt').' '.$n.'</td> |
||
1218 | <td colspan="2">'.$my_lesson_status.'</td> |
||
1219 | <td colspan="2">'.$view_score.'</td> |
||
1220 | '.$timeRow; |
||
1221 | |||
1222 | if ('classic' === $action) { |
||
1223 | if ('tracking' !== $origin) { |
||
1224 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
1225 | $output .= '<td> |
||
1226 | <img |
||
1227 | src="'.Display::returnIconPath('quiz_na.gif').'" |
||
1228 | alt="'.get_lang('Show attempt').'" |
||
1229 | title="'.get_lang('Show attempt').'" /> |
||
1230 | </td>'; |
||
1231 | } else { |
||
1232 | $output .= '<td> |
||
1233 | <a |
||
1234 | href="../exercise/exercise_show.php?origin='.$origin.'&id='.$my_exe_id.'&cid='.$courseId.'" |
||
1235 | target="_parent"> |
||
1236 | <img |
||
1237 | src="'.Display::returnIconPath('quiz.png').'" |
||
1238 | alt="'.get_lang('Show attempt').'" |
||
1239 | title="'.get_lang('Show attempt').'" /> |
||
1240 | </a></td>'; |
||
1241 | } |
||
1242 | } else { |
||
1243 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
1244 | $output .= '<td> |
||
1245 | <img |
||
1246 | src="'.Display::returnIconPath('quiz_na.gif').'" |
||
1247 | alt="'.get_lang('Show and grade attempt').'" |
||
1248 | title="'.get_lang('Show and grade attempt').'" /> |
||
1249 | </td>'; |
||
1250 | } else { |
||
1251 | $output .= '<td> |
||
1252 | <a |
||
1253 | href="../exercise/exercise_show.php?cid='.$courseId.'&origin=correct_exercise_in_lp&id='.$my_exe_id.'" |
||
1254 | target="_parent"> |
||
1255 | <img |
||
1256 | src="'.Display::returnIconPath('quiz.gif').'" |
||
1257 | alt="'.get_lang('Show and grade attempt').'" |
||
1258 | title="'.get_lang('Show and grade attempt').'"> |
||
1259 | </a> |
||
1260 | </td>'; |
||
1261 | } |
||
1262 | } |
||
1263 | } |
||
1264 | $output .= '</tr>'; |
||
1265 | $n++; |
||
1266 | } |
||
1267 | } |
||
1268 | $output .= '<tr><td colspan="12"> </td></tr>'; |
||
1269 | } |
||
1270 | } |
||
1271 | } |
||
1272 | } |
||
1273 | |||
1274 | $total_time += $time_for_total; |
||
1275 | // QUIZZ IN LP |
||
1276 | $a_my_id = []; |
||
1277 | if (!empty($my_lp_id)) { |
||
1278 | $a_my_id[] = $my_lp_id; |
||
1279 | } |
||
1280 | } |
||
1281 | } |
||
1282 | |||
1283 | // NOT Extend all "left green cross" |
||
1284 | if (!empty($a_my_id)) { |
||
1285 | if ($extendedAttempt) { |
||
1286 | // "Right green cross" extended |
||
1287 | $total_score = self::get_avg_student_score( |
||
1288 | $user_id, |
||
1289 | $course, |
||
1290 | $a_my_id, |
||
1291 | $session, |
||
1292 | false, |
||
1293 | false |
||
1294 | ); |
||
1295 | } else { |
||
1296 | // "Left green cross" extended |
||
1297 | $total_score = self::get_avg_student_score( |
||
1298 | $user_id, |
||
1299 | $course, |
||
1300 | $a_my_id, |
||
1301 | $session, |
||
1302 | false, |
||
1303 | true |
||
1304 | ); |
||
1305 | } |
||
1306 | } else { |
||
1307 | // Extend all "left green cross" |
||
1308 | $total_score = self::get_avg_student_score( |
||
1309 | $user_id, |
||
1310 | $course, |
||
1311 | [$lp_id], |
||
1312 | $session, |
||
1313 | false, |
||
1314 | false |
||
1315 | ); |
||
1316 | } |
||
1317 | |||
1318 | $total_time = learnpathItem::getScormTimeFromParameter('js', $total_time); |
||
1319 | $total_time = str_replace('NaN', '00'.$h.'00\'00"', $total_time); |
||
1320 | |||
1321 | if (!$is_allowed_to_edit && $result_disabled_ext_all) { |
||
1322 | $final_score = Display::getMdiIcon( |
||
1323 | ActionIcon::INVISIBLE, |
||
1324 | 'ch-tool-icon', |
||
1325 | null, |
||
1326 | ICON_SIZE_SMALL, |
||
1327 | get_lang('Results hidden by the exercise setting') |
||
1328 | ); |
||
1329 | $finalScoreToCsv = get_lang('Results hidden by the exercise setting'); |
||
1330 | } else { |
||
1331 | if (is_numeric($total_score)) { |
||
1332 | $final_score = $total_score.'%'; |
||
1333 | } else { |
||
1334 | $final_score = $total_score; |
||
1335 | } |
||
1336 | $finalScoreToCsv = $final_score; |
||
1337 | } |
||
1338 | $progress = learnpath::getProgress($lp_id, $user_id, $courseId, $sessionId); |
||
1339 | |||
1340 | $oddclass = 'row_even'; |
||
1341 | if (0 == ($counter % 2)) { |
||
1342 | $oddclass = 'row_odd'; |
||
1343 | } |
||
1344 | |||
1345 | $action = null; |
||
1346 | if ('classic' === $type) { |
||
1347 | $action = '<td></td>'; |
||
1348 | } |
||
1349 | |||
1350 | $timeTotal = '<td class="lp_time" colspan="2">'.$total_time.'</div>'; |
||
1351 | if ($hideTime) { |
||
1352 | $timeTotal = ''; |
||
1353 | } |
||
1354 | |||
1355 | $output .= '<tr class="'.$oddclass.'"> |
||
1356 | <td></td> |
||
1357 | <td colspan="4"> |
||
1358 | <i>'.get_lang('Total of completed learning objects').'</i> |
||
1359 | </td> |
||
1360 | <td colspan="2">'.$progress.'%</td> |
||
1361 | <td colspan="2">'.$final_score.'</td> |
||
1362 | '.$timeTotal.' |
||
1363 | '.$action.' |
||
1364 | </tr>'; |
||
1365 | |||
1366 | $output .= ' |
||
1367 | </tbody> |
||
1368 | </table> |
||
1369 | </div> |
||
1370 | '; |
||
1371 | |||
1372 | if (!empty($export_csv)) { |
||
1373 | $temp = [ |
||
1374 | '', |
||
1375 | '', |
||
1376 | '', |
||
1377 | '', |
||
1378 | ]; |
||
1379 | $csv_content[] = $temp; |
||
1380 | $temp = [ |
||
1381 | get_lang('Total of completed learning objects'), |
||
1382 | '', |
||
1383 | $finalScoreToCsv, |
||
1384 | ]; |
||
1385 | |||
1386 | if (false === $hideTime) { |
||
1387 | $temp[] = $total_time; |
||
1388 | } |
||
1389 | |||
1390 | $csv_content[] = $temp; |
||
1391 | ob_end_clean(); |
||
1392 | Export::arrayToCsv($csv_content, 'reporting_learning_path_details'); |
||
1393 | exit; |
||
0 ignored issues
–
show
|
|||
1394 | } |
||
1395 | |||
1396 | return $output; |
||
1397 | } |
||
1398 | |||
1399 | /** |
||
1400 | * @param int $userId |
||
1401 | * @param bool $getCount |
||
1402 | * |
||
1403 | * @return array |
||
1404 | */ |
||
1405 | public static function getStats($userId, $getCount = false) |
||
1406 | { |
||
1407 | $courses = []; |
||
1408 | $assignedCourses = []; |
||
1409 | $drhCount = 0; |
||
1410 | $teachersCount = 0; |
||
1411 | $studentsCount = 0; |
||
1412 | $studentBossCount = 0; |
||
1413 | $courseCount = 0; |
||
1414 | $sessionCount = 0; |
||
1415 | $assignedCourseCount = 0; |
||
1416 | |||
1417 | if (api_is_drh() && api_drh_can_access_all_session_content()) { |
||
1418 | $studentList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus( |
||
1419 | 'drh_all', |
||
1420 | $userId, |
||
1421 | false, |
||
1422 | null, |
||
1423 | null, |
||
1424 | null, |
||
1425 | null, |
||
1426 | null, |
||
1427 | null, |
||
1428 | null, |
||
1429 | [], |
||
1430 | [], |
||
1431 | STUDENT |
||
1432 | ); |
||
1433 | |||
1434 | $students = []; |
||
1435 | if (is_array($studentList)) { |
||
1436 | foreach ($studentList as $studentData) { |
||
1437 | $students[] = $studentData['user_id']; |
||
1438 | } |
||
1439 | } |
||
1440 | |||
1441 | $studentBossesList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus( |
||
1442 | 'drh_all', |
||
1443 | $userId, |
||
1444 | $getCount, |
||
1445 | null, |
||
1446 | null, |
||
1447 | null, |
||
1448 | null, |
||
1449 | null, |
||
1450 | null, |
||
1451 | null, |
||
1452 | [], |
||
1453 | [], |
||
1454 | STUDENT_BOSS |
||
1455 | ); |
||
1456 | |||
1457 | if ($getCount) { |
||
1458 | $studentBossCount = $studentBossesList; |
||
1459 | } else { |
||
1460 | $studentBosses = []; |
||
1461 | if (is_array($studentBossesList)) { |
||
1462 | foreach ($studentBossesList as $studentBossData) { |
||
1463 | $studentBosses[] = $studentBossData['user_id']; |
||
1464 | } |
||
1465 | } |
||
1466 | } |
||
1467 | |||
1468 | $teacherList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus( |
||
1469 | 'drh_all', |
||
1470 | $userId, |
||
1471 | $getCount, |
||
1472 | null, |
||
1473 | null, |
||
1474 | null, |
||
1475 | null, |
||
1476 | null, |
||
1477 | null, |
||
1478 | null, |
||
1479 | [], |
||
1480 | [], |
||
1481 | COURSEMANAGER |
||
1482 | ); |
||
1483 | |||
1484 | if ($getCount) { |
||
1485 | $teachersCount = $teacherList; |
||
1486 | } else { |
||
1487 | $teachers = []; |
||
1488 | foreach ($teacherList as $teacherData) { |
||
1489 | $teachers[] = $teacherData['user_id']; |
||
1490 | } |
||
1491 | } |
||
1492 | |||
1493 | $humanResources = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus( |
||
1494 | 'drh_all', |
||
1495 | $userId, |
||
1496 | $getCount, |
||
1497 | null, |
||
1498 | null, |
||
1499 | null, |
||
1500 | null, |
||
1501 | null, |
||
1502 | null, |
||
1503 | null, |
||
1504 | [], |
||
1505 | [], |
||
1506 | DRH |
||
1507 | ); |
||
1508 | |||
1509 | if ($getCount) { |
||
1510 | $drhCount = $humanResources; |
||
1511 | } else { |
||
1512 | $humanResourcesList = []; |
||
1513 | if (is_array($humanResources)) { |
||
1514 | foreach ($humanResources as $item) { |
||
1515 | $humanResourcesList[] = $item['user_id']; |
||
1516 | } |
||
1517 | } |
||
1518 | } |
||
1519 | |||
1520 | $platformCourses = SessionManager::getAllCoursesFollowedByUser( |
||
1521 | $userId, |
||
1522 | null, |
||
1523 | null, |
||
1524 | null, |
||
1525 | null, |
||
1526 | null, |
||
1527 | $getCount |
||
1528 | ); |
||
1529 | |||
1530 | if ($getCount) { |
||
1531 | $courseCount = $platformCourses; |
||
1532 | } else { |
||
1533 | foreach ($platformCourses as $course) { |
||
1534 | $courses[$course['code']] = $course['code']; |
||
1535 | } |
||
1536 | } |
||
1537 | |||
1538 | $sessions = SessionManager::get_sessions_followed_by_drh( |
||
1539 | $userId, |
||
1540 | null, |
||
1541 | null, |
||
1542 | false |
||
1543 | ); |
||
1544 | } else { |
||
1545 | $studentList = UserManager::getUsersFollowedByUser( |
||
1546 | $userId, |
||
1547 | STUDENT, |
||
1548 | false, |
||
1549 | false, |
||
1550 | false, |
||
1551 | null, |
||
1552 | null, |
||
1553 | null, |
||
1554 | null, |
||
1555 | null, |
||
1556 | null, |
||
1557 | COURSEMANAGER |
||
1558 | ); |
||
1559 | |||
1560 | $students = []; |
||
1561 | if (is_array($studentList)) { |
||
1562 | foreach ($studentList as $studentData) { |
||
1563 | $students[] = $studentData['user_id']; |
||
1564 | } |
||
1565 | } |
||
1566 | |||
1567 | $studentBossesList = UserManager::getUsersFollowedByUser( |
||
1568 | $userId, |
||
1569 | STUDENT_BOSS, |
||
1570 | false, |
||
1571 | false, |
||
1572 | $getCount, |
||
1573 | null, |
||
1574 | null, |
||
1575 | null, |
||
1576 | null, |
||
1577 | null, |
||
1578 | null, |
||
1579 | COURSEMANAGER |
||
1580 | ); |
||
1581 | |||
1582 | if ($getCount) { |
||
1583 | $studentBossCount = $studentBossesList; |
||
1584 | } else { |
||
1585 | $studentBosses = []; |
||
1586 | if (is_array($studentBossesList)) { |
||
1587 | foreach ($studentBossesList as $studentBossData) { |
||
1588 | $studentBosses[] = $studentBossData['user_id']; |
||
1589 | } |
||
1590 | } |
||
1591 | } |
||
1592 | |||
1593 | $teacherList = UserManager::getUsersFollowedByUser( |
||
1594 | $userId, |
||
1595 | COURSEMANAGER, |
||
1596 | false, |
||
1597 | false, |
||
1598 | $getCount, |
||
1599 | null, |
||
1600 | null, |
||
1601 | null, |
||
1602 | null, |
||
1603 | null, |
||
1604 | null, |
||
1605 | COURSEMANAGER |
||
1606 | ); |
||
1607 | |||
1608 | if ($getCount) { |
||
1609 | $teachersCount = $teacherList; |
||
1610 | } else { |
||
1611 | $teachers = []; |
||
1612 | foreach ($teacherList as $teacherData) { |
||
1613 | $teachers[] = $teacherData['user_id']; |
||
1614 | } |
||
1615 | } |
||
1616 | |||
1617 | $humanResources = UserManager::getUsersFollowedByUser( |
||
1618 | $userId, |
||
1619 | DRH, |
||
1620 | false, |
||
1621 | false, |
||
1622 | $getCount, |
||
1623 | null, |
||
1624 | null, |
||
1625 | null, |
||
1626 | null, |
||
1627 | null, |
||
1628 | null, |
||
1629 | COURSEMANAGER |
||
1630 | ); |
||
1631 | |||
1632 | if ($getCount) { |
||
1633 | $drhCount = $humanResources; |
||
1634 | } else { |
||
1635 | $humanResourcesList = []; |
||
1636 | foreach ($humanResources as $item) { |
||
1637 | $humanResourcesList[] = $item['user_id']; |
||
1638 | } |
||
1639 | } |
||
1640 | |||
1641 | $platformCourses = CourseManager::getCoursesFollowedByUser( |
||
1642 | $userId, |
||
1643 | COURSEMANAGER, |
||
1644 | null, |
||
1645 | null, |
||
1646 | null, |
||
1647 | null, |
||
1648 | $getCount, |
||
1649 | null, |
||
1650 | null, |
||
1651 | true |
||
1652 | ); |
||
1653 | |||
1654 | if ($getCount) { |
||
1655 | $assignedCourseCount = $platformCourses; |
||
1656 | } else { |
||
1657 | foreach ($platformCourses as $course) { |
||
1658 | $assignedCourses[$course['code']] = $course['code']; |
||
1659 | } |
||
1660 | } |
||
1661 | |||
1662 | $platformCourses = CourseManager::getCoursesFollowedByUser( |
||
1663 | $userId, |
||
1664 | COURSEMANAGER, |
||
1665 | null, |
||
1666 | null, |
||
1667 | null, |
||
1668 | null, |
||
1669 | $getCount |
||
1670 | ); |
||
1671 | |||
1672 | if ($getCount) { |
||
1673 | $courseCount = $platformCourses; |
||
1674 | } else { |
||
1675 | foreach ($platformCourses as $course) { |
||
1676 | $courses[$course['code']] = $course['code']; |
||
1677 | } |
||
1678 | } |
||
1679 | |||
1680 | $sessions = SessionManager::getSessionsFollowedByUser( |
||
1681 | $userId, |
||
1682 | COURSEMANAGER, |
||
1683 | null, |
||
1684 | null, |
||
1685 | false |
||
1686 | ); |
||
1687 | } |
||
1688 | |||
1689 | if ($getCount) { |
||
1690 | return [ |
||
1691 | 'drh' => $drhCount, |
||
1692 | 'teachers' => $teachersCount, |
||
1693 | 'student_count' => count($students), |
||
1694 | 'student_list' => $students, |
||
1695 | 'student_bosses' => $studentBossCount, |
||
1696 | 'courses' => $courseCount, |
||
1697 | 'session_count' => count($sessions), |
||
1698 | 'session_list' => $sessions, |
||
1699 | 'assigned_courses' => $assignedCourseCount, |
||
1700 | ]; |
||
1701 | } |
||
1702 | |||
1703 | return [ |
||
1704 | 'drh' => $humanResourcesList, |
||
1705 | 'teachers' => $teachers, |
||
1706 | 'student_list' => $students, |
||
1707 | 'student_bosses' => $studentBosses, |
||
1708 | 'courses' => $courses, |
||
1709 | 'sessions' => $sessions, |
||
1710 | 'assigned_courses' => $assignedCourses, |
||
1711 | ]; |
||
1712 | } |
||
1713 | |||
1714 | /** |
||
1715 | * Calculates the time spent on the platform by a user. |
||
1716 | * |
||
1717 | * @param int|array $userId |
||
1718 | * @param string $timeFilter type of time filter: 'last_week' or 'custom' |
||
1719 | * @param string $start_date start date date('Y-m-d H:i:s') |
||
1720 | * @param string $end_date end date date('Y-m-d H:i:s') |
||
1721 | * @param bool $returnAllRecords |
||
1722 | * |
||
1723 | * @return int|array |
||
1724 | */ |
||
1725 | public static function get_time_spent_on_the_platform( |
||
1726 | $userId, |
||
1727 | $timeFilter = 'last_7_days', |
||
1728 | $start_date = null, |
||
1729 | $end_date = null, |
||
1730 | $returnAllRecords = false |
||
1731 | ) { |
||
1732 | $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN); |
||
1733 | $condition_time = ''; |
||
1734 | |||
1735 | if (is_array($userId)) { |
||
1736 | $userList = array_map('intval', $userId); |
||
1737 | $userCondition = " login_user_id IN ('".implode("','", $userList)."')"; |
||
1738 | } else { |
||
1739 | $userId = (int) $userId; |
||
1740 | $userCondition = " login_user_id = $userId "; |
||
1741 | } |
||
1742 | |||
1743 | $url_condition = null; |
||
1744 | $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); |
||
1745 | $url_table = null; |
||
1746 | $accessUrlUtil = Container::getAccessUrlUtil(); |
||
1747 | if ($accessUrlUtil->isMultiple()) { |
||
1748 | $access_url_id = $accessUrlUtil->getCurrent()->getId(); |
||
1749 | $url_table = ", $tbl_url_rel_user as url_users"; |
||
1750 | $url_condition = " AND u.login_user_id = url_users.user_id AND access_url_id = $access_url_id"; |
||
1751 | } |
||
1752 | |||
1753 | if (empty($timeFilter)) { |
||
1754 | $timeFilter = 'last_week'; |
||
1755 | } |
||
1756 | |||
1757 | $today = new DateTime('now', new DateTimeZone('UTC')); |
||
1758 | |||
1759 | switch ($timeFilter) { |
||
1760 | case 'last_7_days': |
||
1761 | $newDate = new DateTime('-7 day', new DateTimeZone('UTC')); |
||
1762 | $condition_time = " AND (login_date >= '{$newDate->format('Y-m-d H:i:s')}'"; |
||
1763 | $condition_time .= " AND logout_date <= '{$today->format('Y-m-d H:i:s')}') "; |
||
1764 | break; |
||
1765 | case 'last_30_days': |
||
1766 | $newDate = new DateTime('-30 days', new DateTimeZone('UTC')); |
||
1767 | $condition_time = " AND (login_date >= '{$newDate->format('Y-m-d H:i:s')}'"; |
||
1768 | $condition_time .= "AND logout_date <= '{$today->format('Y-m-d H:i:s')}') "; |
||
1769 | break; |
||
1770 | case 'wide': |
||
1771 | if (!empty($start_date) && !empty($end_date)) { |
||
1772 | $start_date = Database::escape_string($start_date); |
||
1773 | $end_date = Database::escape_string($end_date); |
||
1774 | $condition_time = ' AND ( |
||
1775 | (login_date >= "'.$start_date.'" AND login_date <= "'.$end_date.'") OR |
||
1776 | (logout_date >= "'.$start_date.'" AND logout_date <= "'.$end_date.'") OR |
||
1777 | (login_date <= "'.$start_date.'" AND logout_date >= "'.$end_date.'") |
||
1778 | ) '; |
||
1779 | } |
||
1780 | break; |
||
1781 | case 'custom': |
||
1782 | if (!empty($start_date) && !empty($end_date)) { |
||
1783 | $start_date = Database::escape_string($start_date); |
||
1784 | $end_date = Database::escape_string($end_date); |
||
1785 | $condition_time = ' AND (login_date >= "'.$start_date.'" AND logout_date <= "'.$end_date.'" ) '; |
||
1786 | } |
||
1787 | break; |
||
1788 | } |
||
1789 | |||
1790 | if ($returnAllRecords) { |
||
1791 | $sql = "SELECT login_date, logout_date, TIMESTAMPDIFF(SECOND, login_date, logout_date) diff |
||
1792 | FROM $tbl_track_login u $url_table |
||
1793 | WHERE $userCondition $condition_time $url_condition |
||
1794 | ORDER BY login_date"; |
||
1795 | $rs = Database::query($sql); |
||
1796 | |||
1797 | return Database::store_result($rs, 'ASSOC'); |
||
1798 | } |
||
1799 | |||
1800 | $sql = "SELECT SUM(TIMESTAMPDIFF(SECOND, login_date, logout_date)) diff |
||
1801 | FROM $tbl_track_login u $url_table |
||
1802 | WHERE $userCondition $condition_time $url_condition"; |
||
1803 | $rs = Database::query($sql); |
||
1804 | $row = Database::fetch_assoc($rs); |
||
1805 | $diff = $row['diff']; |
||
1806 | |||
1807 | if ($diff >= 0) { |
||
1808 | return $diff; |
||
1809 | } |
||
1810 | |||
1811 | return -1; |
||
1812 | } |
||
1813 | |||
1814 | /** |
||
1815 | * @param string $startDate |
||
1816 | * @param string $endDate |
||
1817 | * |
||
1818 | * @return int |
||
1819 | */ |
||
1820 | public static function getTotalTimeSpentOnThePlatform( |
||
1821 | $startDate = '', |
||
1822 | $endDate = '' |
||
1823 | ) { |
||
1824 | $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN); |
||
1825 | $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); |
||
1826 | |||
1827 | $url_table = null; |
||
1828 | $url_condition = null; |
||
1829 | $accessUrlUtil = Container::getAccessUrlUtil(); |
||
1830 | if ($accessUrlUtil->isMultiple()) { |
||
1831 | $access_url_id = $accessUrlUtil->getCurrent()->getId(); |
||
1832 | $url_table = ", ".$tbl_url_rel_user." as url_users"; |
||
1833 | $url_condition = " AND u.login_user_id = url_users.user_id AND access_url_id='$access_url_id'"; |
||
1834 | } |
||
1835 | |||
1836 | if (!empty($startDate) && !empty($endDate)) { |
||
1837 | $startDate = Database::escape_string($startDate); |
||
1838 | $endDate = Database::escape_string($endDate); |
||
1839 | $condition_time = ' (login_date >= "'.$startDate.'" AND logout_date <= "'.$endDate.'" ) '; |
||
1840 | } |
||
1841 | $sql = "SELECT SUM(TIMESTAMPDIFF(SECOND, login_date, logout_date)) diff |
||
1842 | FROM $tbl_track_login u $url_table |
||
1843 | WHERE $condition_time $url_condition"; |
||
1844 | $rs = Database::query($sql); |
||
1845 | $row = Database::fetch_assoc($rs); |
||
1846 | $diff = $row['diff']; |
||
1847 | |||
1848 | if ($diff >= 0) { |
||
1849 | return $diff; |
||
1850 | } |
||
1851 | |||
1852 | return -1; |
||
1853 | } |
||
1854 | |||
1855 | /** |
||
1856 | * Checks if the "lp_minimum_time" feature is available for the course. |
||
1857 | * |
||
1858 | * @param int $sessionId |
||
1859 | * @param int $courseId |
||
1860 | * |
||
1861 | * @return bool |
||
1862 | */ |
||
1863 | public static function minimumTimeAvailable($sessionId, $courseId) |
||
1864 | { |
||
1865 | if ('true' !== api_get_setting('lp.lp_minimum_time')) { |
||
1866 | return false; |
||
1867 | } |
||
1868 | |||
1869 | if (!empty($sessionId)) { |
||
1870 | $extraFieldValue = new ExtraFieldValue('session'); |
||
1871 | $value = $extraFieldValue->get_values_by_handler_and_field_variable($sessionId, 'new_tracking_system'); |
||
1872 | |||
1873 | if ($value && isset($value['value']) && 1 == $value['value']) { |
||
1874 | return true; |
||
1875 | } |
||
1876 | } else { |
||
1877 | if ($courseId) { |
||
1878 | $extraFieldValue = new ExtraFieldValue('course'); |
||
1879 | $value = $extraFieldValue->get_values_by_handler_and_field_variable($courseId, 'new_tracking_system'); |
||
1880 | if ($value && isset($value['value']) && 1 == $value['value']) { |
||
1881 | return true; |
||
1882 | } |
||
1883 | } |
||
1884 | } |
||
1885 | |||
1886 | return false; |
||
1887 | } |
||
1888 | |||
1889 | /** |
||
1890 | * Calculates the time spent on the course. |
||
1891 | * |
||
1892 | * @param array|int $userId |
||
1893 | * @param int $courseId |
||
1894 | * @param int $sessionId |
||
1895 | * |
||
1896 | * @return int Time in seconds |
||
1897 | */ |
||
1898 | public static function get_time_spent_on_the_course( |
||
1899 | $userId, |
||
1900 | $courseId, |
||
1901 | $sessionId = 0 |
||
1902 | ) { |
||
1903 | $courseId = (int) $courseId; |
||
1904 | |||
1905 | if (empty($courseId) || empty($userId)) { |
||
1906 | return 0; |
||
1907 | } |
||
1908 | |||
1909 | if (self::minimumTimeAvailable($sessionId, $courseId)) { |
||
1910 | $courseTime = self::getCalculateTime($userId, $courseId, $sessionId); |
||
1911 | |||
1912 | return isset($courseTime['total_time']) ? $courseTime['total_time'] : 0; |
||
1913 | } |
||
1914 | |||
1915 | $conditionUser = ''; |
||
1916 | $sessionId = (int) $sessionId; |
||
1917 | if (is_array($userId)) { |
||
1918 | $userId = array_map('intval', $userId); |
||
1919 | $conditionUser = " AND user_id IN (".implode(',', $userId).") "; |
||
1920 | } else { |
||
1921 | if (!empty($userId)) { |
||
1922 | $userId = (int) $userId; |
||
1923 | $conditionUser = " AND user_id = $userId "; |
||
1924 | } |
||
1925 | } |
||
1926 | |||
1927 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
1928 | $sql = "SELECT |
||
1929 | SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as nb_seconds |
||
1930 | FROM $table |
||
1931 | WHERE |
||
1932 | UNIX_TIMESTAMP(logout_course_date) > UNIX_TIMESTAMP(login_course_date) AND |
||
1933 | c_id = '$courseId' "; |
||
1934 | |||
1935 | if (-1 != $sessionId) { |
||
1936 | $sql .= "AND session_id = '$sessionId' "; |
||
1937 | } |
||
1938 | |||
1939 | $sql .= $conditionUser; |
||
1940 | |||
1941 | $rs = Database::query($sql); |
||
1942 | $row = Database::fetch_array($rs); |
||
1943 | |||
1944 | return $row['nb_seconds']; |
||
1945 | } |
||
1946 | |||
1947 | /** |
||
1948 | * Get first connection date for a student. |
||
1949 | * |
||
1950 | * @param int $student_id |
||
1951 | * |
||
1952 | * @return string|bool Date format long without day or false if there are no connections |
||
1953 | */ |
||
1954 | public static function get_first_connection_date($student_id) |
||
1955 | { |
||
1956 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN); |
||
1957 | $sql = 'SELECT login_date |
||
1958 | FROM '.$table.' |
||
1959 | WHERE login_user_id = '.intval($student_id).' |
||
1960 | ORDER BY login_date ASC |
||
1961 | LIMIT 0,1'; |
||
1962 | |||
1963 | $rs = Database::query($sql); |
||
1964 | if (Database::num_rows($rs) > 0) { |
||
1965 | if ($first_login_date = Database::result($rs, 0, 0)) { |
||
1966 | return api_convert_and_format_date( |
||
1967 | $first_login_date, |
||
1968 | DATE_FORMAT_SHORT |
||
1969 | ); |
||
1970 | } |
||
1971 | } |
||
1972 | |||
1973 | return false; |
||
1974 | } |
||
1975 | |||
1976 | /** |
||
1977 | * Get las connection date for a student. |
||
1978 | * |
||
1979 | * @param int $student_id |
||
1980 | * @param bool $warning_message Show a warning message (optional) |
||
1981 | * @param bool $return_timestamp True for returning results in timestamp (optional) |
||
1982 | * |
||
1983 | * @return string|int|bool Date format long without day, false if there are no connections or |
||
1984 | * timestamp if parameter $return_timestamp is true |
||
1985 | */ |
||
1986 | public static function get_last_connection_date( |
||
1987 | $student_id, |
||
1988 | $warning_message = false, |
||
1989 | $return_timestamp = false |
||
1990 | ) { |
||
1991 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN); |
||
1992 | $sql = 'SELECT login_date |
||
1993 | FROM '.$table.' |
||
1994 | WHERE login_user_id = '.intval($student_id).' |
||
1995 | ORDER BY login_date |
||
1996 | DESC LIMIT 0,1'; |
||
1997 | |||
1998 | $rs = Database::query($sql); |
||
1999 | if (Database::num_rows($rs) > 0) { |
||
2000 | if ($last_login_date = Database::result($rs, 0, 0)) { |
||
2001 | $last_login_date = api_get_local_time($last_login_date); |
||
2002 | if ($return_timestamp) { |
||
2003 | return api_strtotime($last_login_date, 'UTC'); |
||
2004 | } else { |
||
2005 | if (!$warning_message) { |
||
2006 | return api_format_date($last_login_date, DATE_FORMAT_SHORT); |
||
2007 | } else { |
||
2008 | $timestamp = api_strtotime($last_login_date, 'UTC'); |
||
2009 | $currentTimestamp = time(); |
||
2010 | |||
2011 | //If the last connection is > than 7 days, the text is red |
||
2012 | //345600 = 7 days in seconds |
||
2013 | if ($currentTimestamp - $timestamp > 604800) { |
||
2014 | return '<em style="color: #F00;">'.api_format_date($last_login_date, DATE_FORMAT_SHORT).'</em>'; |
||
2015 | } else { |
||
2016 | return api_format_date($last_login_date, DATE_FORMAT_SHORT); |
||
2017 | } |
||
2018 | } |
||
2019 | } |
||
2020 | } |
||
2021 | } |
||
2022 | |||
2023 | return false; |
||
2024 | } |
||
2025 | |||
2026 | /** |
||
2027 | * Get first user's connection date on the course. |
||
2028 | * |
||
2029 | * @param int User id |
||
2030 | * @param int $courseId |
||
2031 | * @param int Session id (optional, default=0) |
||
2032 | * @param bool $convert_date |
||
2033 | * |
||
2034 | * @return string|bool Date with format long without day or false if there is no date |
||
2035 | */ |
||
2036 | public static function get_first_connection_date_on_the_course( |
||
2037 | $student_id, |
||
2038 | $courseId, |
||
2039 | $sessionId = 0, |
||
2040 | $convert_date = true |
||
2041 | ) { |
||
2042 | $student_id = (int) $student_id; |
||
2043 | $courseId = (int) $courseId; |
||
2044 | $sessionId = (int) $sessionId; |
||
2045 | |||
2046 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
2047 | $sql = 'SELECT login_course_date |
||
2048 | FROM '.$table.' |
||
2049 | WHERE |
||
2050 | user_id = '.$student_id.' AND |
||
2051 | c_id = '.$courseId.' AND |
||
2052 | session_id = '.$sessionId.' |
||
2053 | ORDER BY login_course_date ASC |
||
2054 | LIMIT 0,1'; |
||
2055 | $rs = Database::query($sql); |
||
2056 | if (Database::num_rows($rs) > 0) { |
||
2057 | if ($first_login_date = Database::result($rs, 0, 0)) { |
||
2058 | if (empty($first_login_date)) { |
||
2059 | return false; |
||
2060 | } |
||
2061 | |||
2062 | if ($convert_date) { |
||
2063 | return api_convert_and_format_date( |
||
2064 | $first_login_date, |
||
2065 | DATE_FORMAT_SHORT |
||
2066 | ); |
||
2067 | } |
||
2068 | |||
2069 | return $first_login_date; |
||
2070 | } |
||
2071 | } |
||
2072 | |||
2073 | return false; |
||
2074 | } |
||
2075 | |||
2076 | /** |
||
2077 | * Get last user's connection date on the course. |
||
2078 | * |
||
2079 | * @param int User id |
||
2080 | * @param array $courseInfo real_id and code are used |
||
2081 | * @param int Session id (optional, default=0) |
||
2082 | * @param bool $convert_date |
||
2083 | * |
||
2084 | * @return string|bool Date with format long without day or false if there is no date |
||
2085 | */ |
||
2086 | public static function get_last_connection_date_on_the_course( |
||
2087 | $student_id, |
||
2088 | $courseInfo, |
||
2089 | $sessionId = 0, |
||
2090 | $convert_date = true |
||
2091 | ) { |
||
2092 | // protect data |
||
2093 | $student_id = (int) $student_id; |
||
2094 | $sessionId = (int) $sessionId; |
||
2095 | |||
2096 | if (empty($courseInfo) || empty($student_id)) { |
||
2097 | return false; |
||
2098 | } |
||
2099 | |||
2100 | $courseId = (int) $courseInfo['real_id']; |
||
2101 | |||
2102 | if (empty($courseId)) { |
||
2103 | return false; |
||
2104 | } |
||
2105 | |||
2106 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
2107 | |||
2108 | if (self::minimumTimeAvailable($sessionId, $courseId)) { |
||
2109 | // Show the last date on which the user acceed the session when it was active |
||
2110 | $where_condition = ''; |
||
2111 | $userInfo = api_get_user_info($student_id); |
||
2112 | if (STUDENT == $userInfo['status'] && !empty($sessionId)) { |
||
2113 | // fin de acceso a la sesión |
||
2114 | $sessionInfo = SessionManager::fetch($sessionId); |
||
2115 | $last_access = $sessionInfo['access_end_date']; |
||
2116 | if (!empty($last_access)) { |
||
2117 | $where_condition = ' AND logout_course_date < "'.$last_access.'" '; |
||
2118 | } |
||
2119 | } |
||
2120 | $sql = "SELECT logout_course_date |
||
2121 | FROM $table |
||
2122 | WHERE user_id = $student_id AND |
||
2123 | c_id = $courseId AND |
||
2124 | session_id = $sessionId $where_condition |
||
2125 | ORDER BY logout_course_date DESC |
||
2126 | LIMIT 0,1"; |
||
2127 | |||
2128 | $rs = Database::query($sql); |
||
2129 | if (Database::num_rows($rs) > 0) { |
||
2130 | if ($last_login_date = Database::result($rs, 0, 0)) { |
||
2131 | if (empty($last_login_date)) { |
||
2132 | return false; |
||
2133 | } |
||
2134 | if ($convert_date) { |
||
2135 | return api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT); |
||
2136 | } |
||
2137 | |||
2138 | return $last_login_date; |
||
2139 | } |
||
2140 | } |
||
2141 | } else { |
||
2142 | $sql = "SELECT logout_course_date |
||
2143 | FROM $table |
||
2144 | WHERE user_id = $student_id AND |
||
2145 | c_id = $courseId AND |
||
2146 | session_id = $sessionId |
||
2147 | ORDER BY logout_course_date DESC |
||
2148 | LIMIT 0,1"; |
||
2149 | |||
2150 | $rs = Database::query($sql); |
||
2151 | if (Database::num_rows($rs) > 0) { |
||
2152 | if ($last_login_date = Database::result($rs, 0, 0)) { |
||
2153 | if (empty($last_login_date)) { |
||
2154 | return false; |
||
2155 | } |
||
2156 | //see #5736 |
||
2157 | $last_login_date_timestamp = api_strtotime($last_login_date); |
||
2158 | $now = time(); |
||
2159 | //If the last connection is > than 7 days, the text is red |
||
2160 | //345600 = 7 days in seconds |
||
2161 | if ($now - $last_login_date_timestamp > 604800) { |
||
2162 | if ($convert_date) { |
||
2163 | $last_login_date = api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT); |
||
2164 | $icon = null; |
||
2165 | if (api_is_allowed_to_edit()) { |
||
2166 | $url = api_get_path(WEB_CODE_PATH). |
||
2167 | 'announcements/announcements.php?action=add&remind_inactive='.$student_id.'&cid='.$courseInfo['real_id']; |
||
2168 | $icon = '<a href="'.$url.'" title="'.get_lang('Remind inactive user').'"> |
||
2169 | '.Display::getMdiIcon( |
||
2170 | StateIcon::WARNING, |
||
2171 | 'ch-tool-icon', |
||
2172 | null, |
||
2173 | ICON_SIZE_SMALL |
||
2174 | ).' |
||
2175 | </a>'; |
||
2176 | } |
||
2177 | |||
2178 | return $icon.Display::label($last_login_date, 'warning'); |
||
2179 | } |
||
2180 | |||
2181 | return $last_login_date; |
||
2182 | } else { |
||
2183 | if ($convert_date) { |
||
2184 | return api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT); |
||
2185 | } |
||
2186 | |||
2187 | return $last_login_date; |
||
2188 | } |
||
2189 | } |
||
2190 | } |
||
2191 | } |
||
2192 | |||
2193 | return false; |
||
2194 | } |
||
2195 | |||
2196 | public static function getLastConnectionInAnyCourse($studentId) |
||
2197 | { |
||
2198 | $studentId = (int) $studentId; |
||
2199 | |||
2200 | if (empty($studentId)) { |
||
2201 | return false; |
||
2202 | } |
||
2203 | |||
2204 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
2205 | $sql = "SELECT logout_course_date |
||
2206 | FROM $table |
||
2207 | WHERE user_id = $studentId |
||
2208 | ORDER BY logout_course_date DESC |
||
2209 | LIMIT 1"; |
||
2210 | $result = Database::query($sql); |
||
2211 | if (Database::num_rows($result)) { |
||
2212 | $row = Database::fetch_array($result); |
||
2213 | |||
2214 | return $row['logout_course_date']; |
||
2215 | } |
||
2216 | |||
2217 | return false; |
||
2218 | } |
||
2219 | |||
2220 | /** |
||
2221 | * Get last course access by course/session. |
||
2222 | */ |
||
2223 | public static function getLastConnectionDateByCourse($courseId, $sessionId = 0) |
||
2224 | { |
||
2225 | $courseId = (int) $courseId; |
||
2226 | $sessionId = (int) $sessionId; |
||
2227 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
2228 | |||
2229 | $sql = "SELECT logout_course_date |
||
2230 | FROM $table |
||
2231 | WHERE |
||
2232 | c_id = $courseId AND |
||
2233 | session_id = $sessionId |
||
2234 | ORDER BY logout_course_date DESC |
||
2235 | LIMIT 0,1"; |
||
2236 | |||
2237 | $result = Database::query($sql); |
||
2238 | if (Database::num_rows($result)) { |
||
2239 | $row = Database::fetch_array($result); |
||
2240 | if ($row) { |
||
2241 | return $row['logout_course_date']; |
||
2242 | } |
||
2243 | } |
||
2244 | |||
2245 | return ''; |
||
2246 | } |
||
2247 | |||
2248 | /** |
||
2249 | * Get count of the connections to the course during a specified period. |
||
2250 | * |
||
2251 | * @param int $courseId |
||
2252 | * @param int Session id (optional) |
||
2253 | * @param int Datetime from which to collect data (defaults to 0) |
||
2254 | * @param int Datetime to which to collect data (defaults to now) |
||
2255 | * |
||
2256 | * @return int count connections |
||
2257 | */ |
||
2258 | public static function get_course_connections_count( |
||
2259 | $courseId, |
||
2260 | $sessionId = 0, |
||
2261 | $start = 0, |
||
2262 | $stop = null |
||
2263 | ) { |
||
2264 | if ($start < 0) { |
||
2265 | $start = 0; |
||
2266 | } |
||
2267 | if (!isset($stop) || $stop < 0) { |
||
2268 | $stop = api_get_utc_datetime(); |
||
2269 | } |
||
2270 | |||
2271 | // Given we're storing in cache, round the start and end times |
||
2272 | // to the lower minute |
||
2273 | $roundedStart = substr($start, 0, -2).'00'; |
||
2274 | $roundedStop = substr($stop, 0, -2).'00'; |
||
2275 | $roundedStart = Database::escape_string($roundedStart); |
||
2276 | $roundedStop = Database::escape_string($roundedStop); |
||
2277 | $month_filter = " AND login_course_date > '$roundedStart' AND login_course_date < '$roundedStop' "; |
||
2278 | $courseId = (int) $courseId; |
||
2279 | $sessionId = (int) $sessionId; |
||
2280 | $count = 0; |
||
2281 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
2282 | $sql = "SELECT count(*) as count_connections |
||
2283 | FROM $table |
||
2284 | WHERE |
||
2285 | c_id = $courseId AND |
||
2286 | session_id = $sessionId |
||
2287 | $month_filter"; |
||
2288 | |||
2289 | //This query can be very slow (several seconds on an indexed table |
||
2290 | // with 14M rows). As such, we'll try to use APCu if it is |
||
2291 | // available to store the resulting value for a few seconds |
||
2292 | $cacheAvailable = api_get_configuration_value('apc'); |
||
2293 | if (true === $cacheAvailable) { |
||
2294 | $apc = apcu_cache_info(true); |
||
2295 | $apc_end = $apc['start_time'] + $apc['ttl']; |
||
2296 | $apc_var = api_get_configuration_value('apc_prefix').'course_access_'.$courseId.'_'.$sessionId.'_'.strtotime($roundedStart).'_'.strtotime($roundedStop); |
||
2297 | if (apcu_exists($apc_var) && (time() < $apc_end) && |
||
2298 | apcu_fetch($apc_var) > 0 |
||
2299 | ) { |
||
2300 | $count = apcu_fetch($apc_var); |
||
2301 | } else { |
||
2302 | $rs = Database::query($sql); |
||
2303 | if (Database::num_rows($rs) > 0) { |
||
2304 | $row = Database::fetch_object($rs); |
||
2305 | $count = $row->count_connections; |
||
2306 | } |
||
2307 | apcu_clear_cache(); |
||
2308 | apcu_store($apc_var, $count, 60); |
||
2309 | } |
||
2310 | } else { |
||
2311 | $rs = Database::query($sql); |
||
2312 | if (Database::num_rows($rs) > 0) { |
||
2313 | $row = Database::fetch_object($rs); |
||
2314 | $count = $row->count_connections; |
||
2315 | } |
||
2316 | } |
||
2317 | |||
2318 | return $count; |
||
2319 | } |
||
2320 | |||
2321 | /** |
||
2322 | * Get count courses per student. |
||
2323 | * |
||
2324 | * @param int $user_id Student id |
||
2325 | * @param bool $include_sessions Include sessions (optional) |
||
2326 | * |
||
2327 | * @return int count courses |
||
2328 | */ |
||
2329 | public static function count_course_per_student($user_id, $include_sessions = true) |
||
2330 | { |
||
2331 | $user_id = (int) $user_id; |
||
2332 | $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER); |
||
2333 | $tbl_session_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
2334 | |||
2335 | $sql = 'SELECT DISTINCT c_id |
||
2336 | FROM '.$tbl_course_rel_user.' |
||
2337 | WHERE user_id = '.$user_id.' AND relation_type<>'.COURSE_RELATION_TYPE_RRHH; |
||
2338 | $rs = Database::query($sql); |
||
2339 | $nb_courses = Database::num_rows($rs); |
||
2340 | |||
2341 | if ($include_sessions) { |
||
2342 | $sql = 'SELECT DISTINCT c_id |
||
2343 | FROM '.$tbl_session_course_rel_user.' |
||
2344 | WHERE user_id = '.$user_id; |
||
2345 | $rs = Database::query($sql); |
||
2346 | $nb_courses += Database::num_rows($rs); |
||
2347 | } |
||
2348 | |||
2349 | return $nb_courses; |
||
2350 | } |
||
2351 | |||
2352 | /** |
||
2353 | * Gets the score average from all tests in a course by student. |
||
2354 | * |
||
2355 | * @param $student_id |
||
2356 | * @param $course_code |
||
2357 | * @param int $exercise_id |
||
2358 | * @param null $sessionId |
||
0 ignored issues
–
show
|
|||
2359 | * @param int $active_filter 2 for consider all tests |
||
2360 | * 1 for active <> -1 |
||
2361 | * 0 for active <> 0 |
||
2362 | * @param int $into_lp 1 for all exercises |
||
2363 | * 0 for without LP |
||
2364 | * @param mixed id |
||
2365 | * @param string code |
||
2366 | * @param int id (optional), filtered by exercise |
||
2367 | * @param int id (optional), if param $sessionId is null |
||
2368 | * it'll return results including sessions, 0 = session is not |
||
2369 | * filtered |
||
2370 | * |
||
2371 | * @return string value (number %) Which represents a round integer about the score average |
||
2372 | */ |
||
2373 | public static function get_avg_student_exercise_score( |
||
2374 | $student_id, |
||
2375 | $course_code, |
||
2376 | $exercise_id = 0, |
||
2377 | $sessionId = null, |
||
2378 | $active_filter = 1, |
||
2379 | $into_lp = 0 |
||
2380 | ) { |
||
2381 | $course_code = Database::escape_string($course_code); |
||
2382 | $course_info = api_get_course_info($course_code); |
||
2383 | if (!empty($course_info)) { |
||
2384 | // table definition |
||
2385 | $tbl_course_quiz = Database::get_course_table(TABLE_QUIZ_TEST); |
||
2386 | $tbl_stats_exercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
2387 | |||
2388 | // Compose a filter based on optional exercise given |
||
2389 | $condition_quiz = ''; |
||
2390 | if (!empty($exercise_id)) { |
||
2391 | $exercise_id = (int) $exercise_id; |
||
2392 | $condition_quiz = " AND iid = $exercise_id "; |
||
2393 | } |
||
2394 | |||
2395 | // Compose a filter based on optional session id given |
||
2396 | $condition_session = ''; |
||
2397 | $session = null; |
||
2398 | if (isset($sessionId)) { |
||
2399 | $session = api_get_session_entity($course_info['real_id']); |
||
2400 | } |
||
2401 | $sessionCondition = api_get_session_condition($sessionId); |
||
2402 | |||
2403 | $condition_active = ''; |
||
2404 | if (1 == $active_filter) { |
||
2405 | $condition_active = 'AND active <> -1'; |
||
2406 | } elseif (0 == $active_filter) { |
||
2407 | $condition_active = 'AND active <> 0'; |
||
2408 | } |
||
2409 | $condition_into_lp = ''; |
||
2410 | $select_lp_id = ''; |
||
2411 | if (0 == $into_lp) { |
||
2412 | $condition_into_lp = 'AND orig_lp_id = 0 AND orig_lp_item_id = 0'; |
||
2413 | } else { |
||
2414 | $select_lp_id = ', orig_lp_id as lp_id '; |
||
2415 | } |
||
2416 | |||
2417 | $quizRepo = Container::getQuizRepository(); |
||
2418 | $course = api_get_course_entity($course_info['real_id']); |
||
2419 | $qb = $quizRepo->getResourcesByCourse($course, $session); |
||
2420 | $qb |
||
2421 | ->select('count(resource)') |
||
2422 | ->setMaxResults(1); |
||
2423 | $count_quiz = $qb->getQuery()->getSingleScalarResult(); |
||
2424 | |||
2425 | /*$sql = "SELECT count(iid) |
||
2426 | FROM $tbl_course_quiz |
||
2427 | WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz "; |
||
2428 | $count_quiz = 0; |
||
2429 | $countQuizResult = Database::query($sql); |
||
2430 | if (!empty($countQuizResult)) { |
||
2431 | $count_quiz = Database::fetch_row($countQuizResult); |
||
2432 | }*/ |
||
2433 | if (!empty($count_quiz) && !empty($student_id)) { |
||
2434 | if (is_array($student_id)) { |
||
2435 | $student_id = array_map('intval', $student_id); |
||
2436 | $condition_user = " AND exe_user_id IN (".implode(',', $student_id).") "; |
||
2437 | } else { |
||
2438 | $student_id = (int) $student_id; |
||
2439 | $condition_user = " AND exe_user_id = '$student_id' "; |
||
2440 | } |
||
2441 | |||
2442 | if (empty($exercise_id)) { |
||
2443 | $sql = "SELECT iid FROM $tbl_course_quiz |
||
2444 | WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz"; |
||
2445 | $result = Database::query($sql); |
||
2446 | $exercise_list = []; |
||
2447 | $exercise_id = null; |
||
2448 | if (!empty($result) && Database::num_rows($result)) { |
||
2449 | while ($row = Database::fetch_array($result)) { |
||
2450 | $exercise_list[] = $row['iid']; |
||
2451 | } |
||
2452 | } |
||
2453 | if (!empty($exercise_list)) { |
||
2454 | $exercise_id = implode("','", $exercise_list); |
||
2455 | } |
||
2456 | } |
||
2457 | |||
2458 | $sql = "SELECT |
||
2459 | SUM(score/max_score*100) as avg_score, |
||
2460 | COUNT(*) as num_attempts |
||
2461 | $select_lp_id |
||
2462 | FROM $tbl_stats_exercise |
||
2463 | WHERE |
||
2464 | exe_exo_id IN ('".$exercise_id."') |
||
2465 | $condition_user AND |
||
2466 | status = '' AND |
||
2467 | c_id = {$course_info['real_id']} |
||
2468 | $sessionCondition |
||
2469 | $condition_into_lp |
||
2470 | ORDER BY exe_date DESC"; |
||
2471 | |||
2472 | $res = Database::query($sql); |
||
2473 | $row = Database::fetch_array($res); |
||
2474 | $quiz_avg_score = null; |
||
2475 | |||
2476 | if (!empty($row['avg_score'])) { |
||
2477 | $quiz_avg_score = round($row['avg_score'], 2); |
||
2478 | } |
||
2479 | |||
2480 | if (!empty($row['num_attempts'])) { |
||
2481 | $quiz_avg_score = round($quiz_avg_score / $row['num_attempts'], 2); |
||
2482 | } |
||
2483 | if (is_array($student_id)) { |
||
2484 | $quiz_avg_score = round($quiz_avg_score / count($student_id), 2); |
||
2485 | } |
||
2486 | if (0 == $into_lp) { |
||
2487 | return $quiz_avg_score; |
||
2488 | } else { |
||
2489 | if (!empty($row['lp_id'])) { |
||
2490 | $tbl_lp = Database::get_course_table(TABLE_LP_MAIN); |
||
2491 | $sql = "SELECT title FROM $tbl_lp WHERE iid = ".(int) $row['lp_id']; |
||
2492 | $result = Database::query($sql); |
||
2493 | $row_lp = Database::fetch_row($result); |
||
2494 | $lp_name = null; |
||
2495 | if ($row_lp && isset($row_lp[0])) { |
||
2496 | $lp_name = $row_lp[0]; |
||
2497 | } |
||
2498 | |||
2499 | return [$quiz_avg_score, $lp_name]; |
||
2500 | } |
||
2501 | |||
2502 | return [$quiz_avg_score, null]; |
||
2503 | } |
||
2504 | } |
||
2505 | } |
||
2506 | |||
2507 | return null; |
||
2508 | } |
||
2509 | |||
2510 | /** |
||
2511 | * Get count student's exercise COMPLETED attempts. |
||
2512 | * |
||
2513 | * @param int $student_id |
||
2514 | * @param int $courseId |
||
2515 | * @param int $exercise_id |
||
2516 | * @param int $lp_id |
||
2517 | * @param int $lp_item_id |
||
2518 | * @param int $sessionId |
||
2519 | * @param int $find_all_lp 0 = just LP specified |
||
2520 | * 1 = LP specified or whitout LP, |
||
2521 | * 2 = all rows |
||
2522 | * |
||
2523 | * @internal param \Student $int id |
||
2524 | * @internal param \Course $string code |
||
2525 | * @internal param \Exercise $int id |
||
2526 | * @internal param \Learning $int path id (optional), |
||
2527 | * for showing attempts inside a learning path $lp_id and $lp_item_id params are required |
||
2528 | * @internal param \Learning $int path item id (optional), |
||
2529 | * for showing attempts inside a learning path $lp_id and $lp_item_id params are required |
||
2530 | * |
||
2531 | * @return int count of attempts |
||
2532 | */ |
||
2533 | public static function count_student_exercise_attempts( |
||
2534 | $student_id, |
||
2535 | $courseId, |
||
2536 | $exercise_id, |
||
2537 | $lp_id = 0, |
||
2538 | $lp_item_id = 0, |
||
2539 | $sessionId = 0, |
||
2540 | $find_all_lp = 0 |
||
2541 | ) { |
||
2542 | $courseId = intval($courseId); |
||
2543 | $student_id = intval($student_id); |
||
2544 | $exercise_id = intval($exercise_id); |
||
2545 | $sessionId = intval($sessionId); |
||
2546 | |||
2547 | $lp_id = intval($lp_id); |
||
2548 | $lp_item_id = intval($lp_item_id); |
||
2549 | $tbl_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
2550 | $sessionCondition = api_get_session_condition($sessionId); |
||
2551 | $sql = "SELECT COUNT(exe_id) as essais |
||
2552 | FROM $tbl_stats_exercises |
||
2553 | WHERE |
||
2554 | c_id = $courseId AND |
||
2555 | exe_exo_id = $exercise_id AND |
||
2556 | status = '' AND |
||
2557 | exe_user_id= $student_id |
||
2558 | $sessionCondition |
||
2559 | "; |
||
2560 | |||
2561 | if (1 == $find_all_lp) { |
||
2562 | $sql .= "AND (orig_lp_id = $lp_id OR orig_lp_id = 0) |
||
2563 | AND (orig_lp_item_id = $lp_item_id OR orig_lp_item_id = 0)"; |
||
2564 | } elseif (0 == $find_all_lp) { |
||
2565 | $sql .= "AND orig_lp_id = $lp_id |
||
2566 | AND orig_lp_item_id = $lp_item_id"; |
||
2567 | } |
||
2568 | |||
2569 | $rs = Database::query($sql); |
||
2570 | $row = Database::fetch_row($rs); |
||
2571 | $count_attempts = $row[0]; |
||
2572 | |||
2573 | return $count_attempts; |
||
2574 | } |
||
2575 | |||
2576 | /** |
||
2577 | * Get count student's exercise progress. |
||
2578 | * |
||
2579 | * @param CQuiz[] $exerciseList |
||
2580 | * @param int $user_id |
||
2581 | * @param int $courseId |
||
2582 | * @param int $sessionId |
||
2583 | * |
||
2584 | * @return string |
||
2585 | */ |
||
2586 | public static function get_exercise_student_progress( |
||
2587 | $exerciseList, |
||
2588 | $user_id, |
||
2589 | $courseId, |
||
2590 | $sessionId |
||
2591 | ) { |
||
2592 | $courseId = (int) $courseId; |
||
2593 | $user_id = (int) $user_id; |
||
2594 | $sessionId = (int) $sessionId; |
||
2595 | |||
2596 | if (empty($exerciseList)) { |
||
2597 | return '0%'; |
||
2598 | } |
||
2599 | $tbl_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
2600 | $exerciseIdList = []; |
||
2601 | foreach ($exerciseList as $exercise) { |
||
2602 | $exerciseIdList[] = $exercise->getIid(); |
||
2603 | } |
||
2604 | $exercise_list_imploded = implode("' ,'", $exerciseIdList); |
||
2605 | $sessionCondition = api_get_session_condition($sessionId); |
||
2606 | $sql = "SELECT COUNT(DISTINCT exe_exo_id) |
||
2607 | FROM $tbl_stats_exercises |
||
2608 | WHERE |
||
2609 | c_id = $courseId AND |
||
2610 | session_id = $sessionId AND |
||
2611 | exe_user_id = $user_id AND |
||
2612 | status = '' AND |
||
2613 | exe_exo_id IN ('$exercise_list_imploded') |
||
2614 | $sessionCondition |
||
2615 | "; |
||
2616 | |||
2617 | $rs = Database::query($sql); |
||
2618 | $count = 0; |
||
2619 | if ($rs) { |
||
2620 | $row = Database::fetch_row($rs); |
||
2621 | $count = (int) $row[0]; |
||
2622 | } |
||
2623 | $count = (0 != $count) ? 100 * round($count / count($exerciseList), 2).'%' : '0%'; |
||
2624 | |||
2625 | return $count; |
||
2626 | } |
||
2627 | |||
2628 | /** |
||
2629 | * @param CQuiz $exercise_list |
||
2630 | * @param int $user_id |
||
2631 | * @param int $courseId |
||
2632 | * @param int $sessionId |
||
2633 | * |
||
2634 | * @return string |
||
2635 | */ |
||
2636 | public static function get_exercise_student_average_best_attempt( |
||
2637 | $exercise_list, |
||
2638 | $user_id, |
||
2639 | $courseId, |
||
2640 | $sessionId |
||
2641 | ) { |
||
2642 | $result = 0; |
||
2643 | if (!empty($exercise_list) && (is_array($exercise_list) || $exercise_list instanceof \Countable)) { |
||
2644 | foreach ($exercise_list as $exercise_data) { |
||
2645 | $exercise_id = $exercise_data->getIid(); |
||
2646 | $best_attempt = Event::get_best_attempt_exercise_results_per_user( |
||
2647 | $user_id, |
||
2648 | $exercise_id, |
||
2649 | $courseId, |
||
2650 | $sessionId, |
||
2651 | false |
||
2652 | ); |
||
2653 | |||
2654 | if (!empty($best_attempt) && !empty($best_attempt['max_score'])) { |
||
2655 | $result += $best_attempt['score'] / $best_attempt['max_score']; |
||
2656 | } |
||
2657 | } |
||
2658 | |||
2659 | if (count($exercise_list) > 0) { |
||
2660 | $result = $result / count($exercise_list); |
||
2661 | $result = round($result, 2) * 100; |
||
2662 | } |
||
2663 | } |
||
2664 | |||
2665 | return $result.'%'; |
||
2666 | } |
||
2667 | |||
2668 | /** |
||
2669 | * Returns the average student progress in the learning paths of the given |
||
2670 | * course, it will take into account the progress that were not started. |
||
2671 | * |
||
2672 | * @param int|array $studentId |
||
2673 | * @param Course $course The course object |
||
2674 | * @param array $lpIdList Limit average to listed lp ids |
||
2675 | * @param SessionEntity $session Session id (optional), |
||
2676 | * if parameter $sessionId is null(default) it'll return results including |
||
2677 | * sessions, 0 = session is not filtered |
||
2678 | * @param bool $returnArray Will return an array of the type: |
||
2679 | * [sum_of_progresses, number] if it is set to true |
||
2680 | * @param bool $onlySeriousGame Optional. Limit average to lp on seriousgame mode |
||
2681 | * |
||
2682 | * @return float Average progress of the user in this course from 0 to 100 |
||
2683 | */ |
||
2684 | public static function get_avg_student_progress( |
||
2685 | $studentId, |
||
2686 | Course $course = null, |
||
2687 | $lpIdList = [], |
||
2688 | SessionEntity $session = null, |
||
2689 | $returnArray = false, |
||
2690 | $onlySeriousGame = false |
||
2691 | ) { |
||
2692 | // If there is at least one learning path and one student. |
||
2693 | if (empty($studentId)) { |
||
2694 | return false; |
||
2695 | } |
||
2696 | if (empty($course)) { |
||
2697 | return false; |
||
2698 | } |
||
2699 | |||
2700 | $repo = Container::getLpRepository(); |
||
2701 | $qb = $repo->findAllByCourse($course, $session); |
||
2702 | $lps = $qb->getQuery()->getResult(); |
||
2703 | $filteredLP = []; |
||
2704 | |||
2705 | $sessionId = null !== $session ? $session->getId() : 0; |
||
2706 | |||
2707 | /** @var CLp $lp */ |
||
2708 | foreach ($lps as $lp) { |
||
2709 | $filteredLP[] = $lp->getIid(); |
||
2710 | } |
||
2711 | |||
2712 | if (empty($filteredLP)) { |
||
2713 | return false; |
||
2714 | } |
||
2715 | |||
2716 | $lpViewTable = Database::get_course_table(TABLE_LP_VIEW); |
||
2717 | /*$lpConditions = []; |
||
2718 | $lpConditions['c_id = ? '] = $courseInfo['real_id']; |
||
2719 | |||
2720 | if ($sessionId > 0) { |
||
2721 | $lpConditions['AND (session_id = ? OR session_id = 0 OR session_id IS NULL)'] = $sessionId; |
||
2722 | } else { |
||
2723 | $lpConditions['AND session_id = ?'] = $sessionId; |
||
2724 | } |
||
2725 | |||
2726 | if (is_array($lpIdList) && count($lpIdList) > 0) { |
||
2727 | $placeHolders = []; |
||
2728 | for ($i = 0; $i < count($lpIdList); $i++) { |
||
2729 | $placeHolders[] = '?'; |
||
2730 | } |
||
2731 | $lpConditions['AND iid IN('.implode(', ', $placeHolders).') '] = $lpIdList; |
||
2732 | } |
||
2733 | |||
2734 | if ($onlySeriousGame) { |
||
2735 | $lpConditions['AND seriousgame_mode = ? '] = true; |
||
2736 | } |
||
2737 | |||
2738 | $resultLP = Database::select( |
||
2739 | 'iid', |
||
2740 | $lPTable, |
||
2741 | ['where' => $lpConditions] |
||
2742 | ); |
||
2743 | $filteredLP = array_keys($resultLP); |
||
2744 | |||
2745 | if (empty($filteredLP)) { |
||
2746 | return false; |
||
2747 | }*/ |
||
2748 | |||
2749 | $conditions = [ |
||
2750 | //" c_id = {$courseInfo['real_id']} ", |
||
2751 | " lp_view.lp_id IN (".implode(', ', $filteredLP).") ", |
||
2752 | ]; |
||
2753 | |||
2754 | $groupBy = 'GROUP BY lp_id'; |
||
2755 | |||
2756 | if (is_array($studentId)) { |
||
2757 | $studentId = array_map('intval', $studentId); |
||
2758 | $conditions[] = " lp_view.user_id IN (".implode(',', $studentId).") "; |
||
2759 | } else { |
||
2760 | $studentId = (int) $studentId; |
||
2761 | $conditions[] = " lp_view.user_id = '$studentId' "; |
||
2762 | |||
2763 | if (empty($lpIdList)) { |
||
2764 | $lpList = new LearnpathList( |
||
2765 | $studentId, |
||
2766 | ['real_id' => $course->getId()], |
||
2767 | $sessionId, |
||
2768 | null, |
||
2769 | false, |
||
2770 | null, |
||
2771 | true |
||
2772 | ); |
||
2773 | $lpList = $lpList->get_flat_list(); |
||
2774 | if (!empty($lpList)) { |
||
2775 | /** @var $lp */ |
||
2776 | foreach ($lpList as $lpId => $lp) { |
||
2777 | $lpIdList[] = $lp['lp_old_id']; |
||
2778 | } |
||
2779 | } |
||
2780 | } |
||
2781 | } |
||
2782 | |||
2783 | if (!empty($sessionId)) { |
||
2784 | $conditions[] = " session_id = $sessionId "; |
||
2785 | } else { |
||
2786 | $conditions[] = ' (session_id = 0 OR session_id IS NULL) '; |
||
2787 | } |
||
2788 | |||
2789 | $conditionToString = implode('AND', $conditions); |
||
2790 | $sql = "SELECT lp_id, view_count, progress |
||
2791 | FROM $lpViewTable lp_view |
||
2792 | WHERE |
||
2793 | $conditionToString |
||
2794 | $groupBy |
||
2795 | ORDER BY view_count DESC"; |
||
2796 | |||
2797 | $result = Database::query($sql); |
||
2798 | |||
2799 | $progress = []; |
||
2800 | $viewCount = []; |
||
2801 | while ($row = Database::fetch_assoc($result)) { |
||
2802 | if (!isset($viewCount[$row['lp_id']])) { |
||
2803 | $progress[$row['lp_id']] = $row['progress']; |
||
2804 | } |
||
2805 | $viewCount[$row['lp_id']] = $row['view_count']; |
||
2806 | } |
||
2807 | |||
2808 | // Fill with lp ids |
||
2809 | $newProgress = []; |
||
2810 | if (!empty($lpIdList)) { |
||
2811 | foreach ($lpIdList as $lpId) { |
||
2812 | if (isset($progress[$lpId])) { |
||
2813 | $newProgress[] = $progress[$lpId]; |
||
2814 | } |
||
2815 | } |
||
2816 | $total = count($lpIdList); |
||
2817 | } else { |
||
2818 | $newProgress = $progress; |
||
2819 | $total = count($newProgress); |
||
2820 | } |
||
2821 | |||
2822 | $average = 0; |
||
2823 | $sum = 0; |
||
2824 | if (!empty($newProgress)) { |
||
2825 | $sum = array_sum($newProgress); |
||
2826 | $average = $sum / $total; |
||
2827 | } |
||
2828 | |||
2829 | if ($returnArray) { |
||
2830 | return [ |
||
2831 | $sum, |
||
2832 | $total, |
||
2833 | ]; |
||
2834 | } |
||
2835 | |||
2836 | return round($average, 1); |
||
2837 | } |
||
2838 | |||
2839 | /** |
||
2840 | * This function gets: |
||
2841 | * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores. |
||
2842 | * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores. |
||
2843 | * 3. And finally it will return the average between 1. and 2. |
||
2844 | * |
||
2845 | * @param mixed $student_id Array of user ids or an user id |
||
2846 | * @param array $lp_ids List of LP ids |
||
2847 | * @param SessionEntity $session |
||
2848 | * if param $sessionId is null(default) it'll return results |
||
2849 | * including sessions, 0 = session is not filtered |
||
2850 | * @param bool $return_array Returns an array of the |
||
2851 | * type [sum_score, num_score] if set to true |
||
2852 | * @param bool $get_only_latest_attempt_results get only the latest attempts or ALL attempts |
||
2853 | * @param bool $getOnlyBestAttempt |
||
2854 | * |
||
2855 | * @return string value (number %) Which represents a round integer explain in got in 3 |
||
2856 | * |
||
2857 | * @todo improve performance, when loading 1500 users with 20 lps the script dies |
||
2858 | * This function does not take the results of a Test out of a LP |
||
2859 | */ |
||
2860 | public static function get_avg_student_score( |
||
2861 | $student_id, |
||
2862 | Course $course, |
||
2863 | $lp_ids = [], |
||
2864 | SessionEntity $session = null, |
||
2865 | $return_array = false, |
||
2866 | $get_only_latest_attempt_results = false, |
||
2867 | $getOnlyBestAttempt = false |
||
2868 | ) { |
||
2869 | if (empty($student_id)) { |
||
2870 | return null; |
||
2871 | } |
||
2872 | |||
2873 | $debug = false; |
||
2874 | $tbl_stats_exercices = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
2875 | $tbl_stats_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
2876 | |||
2877 | // Get course tables names |
||
2878 | $tbl_quiz_questions = Database::get_course_table(TABLE_QUIZ_QUESTION); |
||
2879 | $lp_table = Database::get_course_table(TABLE_LP_MAIN); |
||
2880 | $lp_item_table = Database::get_course_table(TABLE_LP_ITEM); |
||
2881 | $lp_view_table = Database::get_course_table(TABLE_LP_VIEW); |
||
2882 | $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
2883 | $courseId = $course->getId(); |
||
2884 | |||
2885 | // Compose a filter based on optional learning paths list given |
||
2886 | $condition_lp = ''; |
||
2887 | if (count($lp_ids) > 0) { |
||
2888 | $condition_lp = " iid IN(".implode(',', $lp_ids).") "; |
||
2889 | } |
||
2890 | |||
2891 | // Compose a filter based on optional session id |
||
2892 | $sessionId = null; |
||
2893 | if (null !== $session) { |
||
2894 | $sessionId = $session->getId(); |
||
2895 | } |
||
2896 | $sessionCondition = api_get_session_condition($sessionId); |
||
2897 | |||
2898 | $lp_list = $use_max_score = []; |
||
2899 | if (empty($condition_lp)) { |
||
2900 | $repo = Container::getLpRepository(); |
||
2901 | $qb = $repo->findAllByCourse($course, $session); |
||
2902 | $lps = $qb->getQuery()->getResult(); |
||
2903 | /** @var CLp $lp */ |
||
2904 | foreach ($lps as $lp) { |
||
2905 | $lpId = $lp->getIid(); |
||
2906 | $lp_list[] = $lpId; |
||
2907 | $use_max_score[$lpId] = $lp->getUseMaxScore(); |
||
2908 | } |
||
2909 | } else { |
||
2910 | $sql = "SELECT DISTINCT(iid), use_max_score |
||
2911 | FROM $lp_table |
||
2912 | WHERE $condition_lp "; |
||
2913 | $res_row_lp = Database::query($sql); |
||
2914 | while ($row_lp = Database::fetch_array($res_row_lp)) { |
||
2915 | $lp_list[] = $row_lp['iid']; |
||
2916 | $use_max_score[$row_lp['iid']] = $row_lp['use_max_score']; |
||
2917 | } |
||
2918 | } |
||
2919 | |||
2920 | if (empty($lp_list)) { |
||
2921 | return null; |
||
2922 | } |
||
2923 | |||
2924 | // prepare filter on users |
||
2925 | if (is_array($student_id)) { |
||
2926 | array_walk($student_id, 'intval'); |
||
2927 | $condition_user1 = " AND user_id IN (".implode(',', $student_id).") "; |
||
2928 | } else { |
||
2929 | $condition_user1 = " AND user_id = $student_id "; |
||
2930 | } |
||
2931 | |||
2932 | // Getting latest LP result for a student |
||
2933 | //@todo problem when a course have more than 1500 users |
||
2934 | $sql = "SELECT MAX(view_count) as vc, iid, progress, lp_id, user_id |
||
2935 | FROM $lp_view_table |
||
2936 | WHERE |
||
2937 | lp_id IN (".implode(',', $lp_list).") |
||
2938 | $condition_user1 |
||
2939 | $sessionCondition |
||
2940 | GROUP BY lp_id, user_id"; |
||
2941 | //AND session_id = $sessionId |
||
2942 | |||
2943 | $rs_last_lp_view_id = Database::query($sql); |
||
2944 | $global_result = 0; |
||
2945 | if (Database::num_rows($rs_last_lp_view_id) > 0) { |
||
2946 | // Cycle through each line of the results (grouped by lp_id, user_id) |
||
2947 | while ($row_lp_view = Database::fetch_array($rs_last_lp_view_id)) { |
||
2948 | $count_items = 0; |
||
2949 | $lpPartialTotal = 0; |
||
2950 | $list = []; |
||
2951 | $lp_view_id = $row_lp_view['iid']; |
||
2952 | $lp_id = $row_lp_view['lp_id']; |
||
2953 | $user_id = $row_lp_view['user_id']; |
||
2954 | |||
2955 | if ($debug) { |
||
2956 | echo '<h2>LP id '.$lp_id.'</h2>'; |
||
2957 | echo "get_only_latest_attempt_results: $get_only_latest_attempt_results <br />"; |
||
2958 | echo "getOnlyBestAttempt: $getOnlyBestAttempt <br />"; |
||
2959 | } |
||
2960 | |||
2961 | if ($get_only_latest_attempt_results || $getOnlyBestAttempt) { |
||
2962 | // Getting lp_items done by the user |
||
2963 | $sql = "SELECT DISTINCT lp_item_id |
||
2964 | FROM $lp_item_view_table |
||
2965 | WHERE |
||
2966 | lp_view_id = $lp_view_id |
||
2967 | ORDER BY lp_item_id"; |
||
2968 | $res_lp_item = Database::query($sql); |
||
2969 | |||
2970 | while ($row_lp_item = Database::fetch_assoc($res_lp_item)) { |
||
2971 | $my_lp_item_id = $row_lp_item['lp_item_id']; |
||
2972 | $order = ' view_count DESC'; |
||
2973 | if ($getOnlyBestAttempt) { |
||
2974 | $order = ' lp_iv.score DESC'; |
||
2975 | } |
||
2976 | |||
2977 | // Getting the most recent attempt |
||
2978 | $sql = "SELECT |
||
2979 | lp_iv.iid as lp_item_view_id, |
||
2980 | lp_iv.score as score, |
||
2981 | lp_i.max_score, |
||
2982 | lp_iv.max_score as max_score_item_view, |
||
2983 | lp_i.path, |
||
2984 | lp_i.item_type, |
||
2985 | lp_i.iid |
||
2986 | FROM $lp_item_view_table as lp_iv |
||
2987 | INNER JOIN $lp_item_table as lp_i |
||
2988 | ON ( |
||
2989 | lp_i.iid = lp_iv.lp_item_id |
||
2990 | ) |
||
2991 | WHERE |
||
2992 | lp_item_id = $my_lp_item_id AND |
||
2993 | lp_view_id = $lp_view_id AND |
||
2994 | (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."') |
||
2995 | ORDER BY $order |
||
2996 | LIMIT 1"; |
||
2997 | |||
2998 | $res_lp_item_result = Database::query($sql); |
||
2999 | while ($row_max_score = Database::fetch_assoc($res_lp_item_result)) { |
||
3000 | $list[] = $row_max_score; |
||
3001 | } |
||
3002 | } |
||
3003 | } else { |
||
3004 | // For the currently analysed view, get the score and |
||
3005 | // max_score of each item if it is a sco or a TOOL_QUIZ |
||
3006 | $sql = "SELECT |
||
3007 | lp_iv.iid as lp_item_view_id, |
||
3008 | lp_iv.score as score, |
||
3009 | lp_i.max_score, |
||
3010 | lp_iv.max_score as max_score_item_view, |
||
3011 | lp_i.path, |
||
3012 | lp_i.item_type, |
||
3013 | lp_i.iid |
||
3014 | FROM $lp_item_view_table as lp_iv |
||
3015 | INNER JOIN $lp_item_table as lp_i |
||
3016 | ON lp_i.iid = lp_iv.lp_item_id |
||
3017 | WHERE |
||
3018 | lp_view_id = $lp_view_id AND |
||
3019 | (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."') |
||
3020 | "; |
||
3021 | $res_max_score = Database::query($sql); |
||
3022 | while ($row_max_score = Database::fetch_assoc($res_max_score)) { |
||
3023 | $list[] = $row_max_score; |
||
3024 | } |
||
3025 | } |
||
3026 | |||
3027 | // Go through each scorable element of this view |
||
3028 | $score_of_scorm_calculate = 0; |
||
3029 | foreach ($list as $row_max_score) { |
||
3030 | // Came from the original lp_item |
||
3031 | $max_score = $row_max_score['max_score']; |
||
3032 | // Came from the lp_item_view |
||
3033 | $max_score_item_view = $row_max_score['max_score_item_view']; |
||
3034 | $score = $row_max_score['score']; |
||
3035 | if ($debug) { |
||
3036 | echo '<h3>Item Type: '.$row_max_score['item_type'].'</h3>'; |
||
3037 | } |
||
3038 | |||
3039 | if ('sco' === $row_max_score['item_type']) { |
||
3040 | /* Check if it is sco (easier to get max_score) |
||
3041 | when there's no max score, we assume 100 as the max score, |
||
3042 | as the SCORM 1.2 says that the value should always be between 0 and 100. |
||
3043 | */ |
||
3044 | if (0 == $max_score || is_null($max_score) || '' == $max_score) { |
||
3045 | // Chamilo style |
||
3046 | if ($use_max_score[$lp_id]) { |
||
3047 | $max_score = 100; |
||
3048 | } else { |
||
3049 | // Overwrites max score = 100 to use the one that came in the lp_item_view see BT#1613 |
||
3050 | $max_score = $max_score_item_view; |
||
3051 | } |
||
3052 | } |
||
3053 | // Avoid division by zero errors |
||
3054 | if (!empty($max_score)) { |
||
3055 | $lpPartialTotal += $score / $max_score; |
||
3056 | } |
||
3057 | if ($debug) { |
||
3058 | var_dump("lpPartialTotal: $lpPartialTotal"); |
||
0 ignored issues
–
show
|
|||
3059 | var_dump("score: $score"); |
||
3060 | var_dump("max_score: $max_score"); |
||
3061 | } |
||
3062 | } else { |
||
3063 | // Case of a TOOL_QUIZ element |
||
3064 | $item_id = $row_max_score['iid']; |
||
3065 | $item_path = $row_max_score['path']; |
||
3066 | $lp_item_view_id = (int) $row_max_score['lp_item_view_id']; |
||
3067 | |||
3068 | if (empty($lp_item_view_id)) { |
||
3069 | $lpItemCondition = ' (orig_lp_item_view_id = 0 OR orig_lp_item_view_id IS NULL) '; |
||
3070 | } else { |
||
3071 | $lpItemCondition = " orig_lp_item_view_id = $lp_item_view_id "; |
||
3072 | } |
||
3073 | |||
3074 | // Get last attempt to this exercise through |
||
3075 | // the current lp for the current user |
||
3076 | $order = 'exe_date DESC'; |
||
3077 | if ($getOnlyBestAttempt) { |
||
3078 | $order = 'score DESC'; |
||
3079 | } |
||
3080 | $sql = "SELECT exe_id, score |
||
3081 | FROM $tbl_stats_exercices |
||
3082 | WHERE |
||
3083 | exe_exo_id = '$item_path' AND |
||
3084 | exe_user_id = $user_id AND |
||
3085 | orig_lp_item_id = $item_id AND |
||
3086 | $lpItemCondition AND |
||
3087 | c_id = $courseId AND |
||
3088 | status = '' |
||
3089 | $sessionCondition |
||
3090 | ORDER BY $order |
||
3091 | LIMIT 1"; |
||
3092 | |||
3093 | $result_last_attempt = Database::query($sql); |
||
3094 | $num = Database::num_rows($result_last_attempt); |
||
3095 | if ($num > 0) { |
||
3096 | $attemptResult = Database::fetch_assoc($result_last_attempt); |
||
3097 | $id_last_attempt = $attemptResult['exe_id']; |
||
3098 | // We overwrite the score with the best one not the one saved in the LP (latest) |
||
3099 | if ($getOnlyBestAttempt && false == $get_only_latest_attempt_results) { |
||
3100 | if ($debug) { |
||
3101 | echo "Following score comes from the track_exercise table not in the LP because the score is the best<br />"; |
||
3102 | } |
||
3103 | $score = $attemptResult['score']; |
||
3104 | } |
||
3105 | |||
3106 | if ($debug) { |
||
3107 | echo "Attempt id: $id_last_attempt with score $score<br />"; |
||
3108 | } |
||
3109 | // Within the last attempt number tracking, get the sum of |
||
3110 | // the max_scores of all questions that it was |
||
3111 | // made of (we need to make this call dynamic because of random questions selection) |
||
3112 | $sql = "SELECT SUM(t.ponderation) as maxscore FROM |
||
3113 | ( |
||
3114 | SELECT DISTINCT |
||
3115 | question_id, |
||
3116 | marks, |
||
3117 | ponderation |
||
3118 | FROM $tbl_stats_attempts AS at |
||
3119 | INNER JOIN $tbl_quiz_questions AS q |
||
3120 | ON (q.iid = at.question_id) |
||
3121 | WHERE |
||
3122 | exe_id ='$id_last_attempt' |
||
3123 | ) |
||
3124 | AS t"; |
||
3125 | |||
3126 | $res_max_score_bis = Database::query($sql); |
||
3127 | $row_max_score_bis = Database::fetch_array($res_max_score_bis); |
||
3128 | |||
3129 | if (!empty($row_max_score_bis['maxscore'])) { |
||
3130 | $max_score = $row_max_score_bis['maxscore']; |
||
3131 | } |
||
3132 | if (!empty($max_score) && floatval($max_score) > 0) { |
||
3133 | $lpPartialTotal += $score / $max_score; |
||
3134 | } |
||
3135 | if ($debug) { |
||
3136 | var_dump("score: $score"); |
||
3137 | var_dump("max_score: $max_score"); |
||
3138 | var_dump("lpPartialTotal: $lpPartialTotal"); |
||
3139 | } |
||
3140 | } |
||
3141 | } |
||
3142 | |||
3143 | if (in_array($row_max_score['item_type'], ['quiz', 'sco'])) { |
||
3144 | // Normal way |
||
3145 | if ($use_max_score[$lp_id]) { |
||
3146 | $count_items++; |
||
3147 | } else { |
||
3148 | if ('' != $max_score) { |
||
3149 | $count_items++; |
||
3150 | } |
||
3151 | } |
||
3152 | if ($debug) { |
||
3153 | echo '$count_items: '.$count_items; |
||
3154 | } |
||
3155 | } |
||
3156 | } |
||
3157 | |||
3158 | $score_of_scorm_calculate += $count_items ? (($lpPartialTotal / $count_items) * 100) : 0; |
||
3159 | $global_result += $score_of_scorm_calculate; |
||
3160 | |||
3161 | if ($debug) { |
||
3162 | var_dump("count_items: $count_items"); |
||
3163 | var_dump("score_of_scorm_calculate: $score_of_scorm_calculate"); |
||
3164 | var_dump("global_result: $global_result"); |
||
3165 | } |
||
3166 | } |
||
3167 | } |
||
3168 | |||
3169 | $lp_with_quiz = 0; |
||
3170 | foreach ($lp_list as $lp_id) { |
||
3171 | // Check if LP have a score we assume that all SCO have an score |
||
3172 | $sql = "SELECT count(iid) as count |
||
3173 | FROM $lp_item_table |
||
3174 | WHERE |
||
3175 | (item_type = 'quiz' OR item_type = 'sco') AND |
||
3176 | lp_id = ".$lp_id; |
||
3177 | $result_have_quiz = Database::query($sql); |
||
3178 | if (Database::num_rows($result_have_quiz) > 0) { |
||
3179 | $row = Database::fetch_assoc($result_have_quiz); |
||
3180 | if (is_numeric($row['count']) && 0 != $row['count']) { |
||
3181 | $lp_with_quiz++; |
||
3182 | } |
||
3183 | } |
||
3184 | } |
||
3185 | |||
3186 | if ($debug) { |
||
3187 | echo '<h3>$lp_with_quiz '.$lp_with_quiz.' </h3>'; |
||
3188 | echo '<h3>Final return</h3>'; |
||
3189 | } |
||
3190 | |||
3191 | if (0 != $lp_with_quiz) { |
||
3192 | if (!$return_array) { |
||
3193 | $score_of_scorm_calculate = round(($global_result / $lp_with_quiz), 2); |
||
3194 | if ($debug) { |
||
3195 | var_dump($score_of_scorm_calculate); |
||
3196 | } |
||
3197 | if (empty($lp_ids)) { |
||
3198 | if ($debug) { |
||
3199 | echo '<h2>All lps fix: '.$score_of_scorm_calculate.'</h2>'; |
||
3200 | } |
||
3201 | } |
||
3202 | |||
3203 | return $score_of_scorm_calculate; |
||
3204 | } |
||
3205 | |||
3206 | if ($debug) { |
||
3207 | var_dump($global_result, $lp_with_quiz); |
||
3208 | } |
||
3209 | |||
3210 | return [$global_result, $lp_with_quiz]; |
||
3211 | } |
||
3212 | |||
3213 | return '-'; |
||
3214 | } |
||
3215 | |||
3216 | /** |
||
3217 | * This function gets: |
||
3218 | * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores. |
||
3219 | * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores. |
||
3220 | * 3. And finally it will return the average between 1. and 2. |
||
3221 | * This function does not take the results of a Test out of a LP. |
||
3222 | * |
||
3223 | * @param int|array $student_id Array of user ids or an user id |
||
3224 | * @param string $course_code Course code |
||
3225 | * @param array $lp_ids List of LP ids |
||
3226 | * @param int $sessionId Session id (optional), if param $sessionId is 0(default) |
||
3227 | * it'll return results including sessions, 0 = session is not filtered |
||
3228 | * |
||
3229 | * @return string value (number %) Which represents a round integer explain in got in 3 |
||
3230 | */ |
||
3231 | public static function getAverageStudentScore( |
||
3232 | $student_id, |
||
3233 | $course_code = '', |
||
3234 | $lp_ids = [], |
||
3235 | $sessionId = 0 |
||
3236 | ) { |
||
3237 | if (empty($student_id)) { |
||
3238 | return 0; |
||
3239 | } |
||
3240 | |||
3241 | $conditions = []; |
||
3242 | if (!empty($course_code)) { |
||
3243 | $course = api_get_course_info($course_code); |
||
3244 | $courseId = $course['real_id']; |
||
3245 | //$conditions[] = " lp.c_id = $courseId"; |
||
3246 | } |
||
3247 | |||
3248 | // Get course tables names |
||
3249 | $lp_table = Database::get_course_table(TABLE_LP_MAIN); |
||
3250 | $lp_item_table = Database::get_course_table(TABLE_LP_ITEM); |
||
3251 | $lp_view_table = Database::get_course_table(TABLE_LP_VIEW); |
||
3252 | $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
3253 | |||
3254 | // Compose a filter based on optional learning paths list given |
||
3255 | if (!empty($lp_ids) && count($lp_ids) > 0) { |
||
3256 | $conditions[] = ' lp.iid IN ('.implode(',', $lp_ids).') '; |
||
3257 | } |
||
3258 | |||
3259 | // Compose a filter based on optional session id |
||
3260 | $sessionId = (int) $sessionId; |
||
3261 | if (!empty($sessionId)) { |
||
3262 | $conditions[] = " lp_view.session_id = $sessionId "; |
||
3263 | } |
||
3264 | |||
3265 | if (is_array($student_id)) { |
||
3266 | array_walk($student_id, 'intval'); |
||
3267 | $conditions[] = " lp_view.user_id IN (".implode(',', $student_id).") "; |
||
3268 | } else { |
||
3269 | $student_id = (int) $student_id; |
||
3270 | $conditions[] = " lp_view.user_id = $student_id "; |
||
3271 | } |
||
3272 | |||
3273 | $conditionsToString = implode(' AND ', $conditions); |
||
3274 | $sql = "SELECT |
||
3275 | SUM(lp_iv.score) sum_score, |
||
3276 | SUM(lp_i.max_score) sum_max_score |
||
3277 | FROM $lp_table as lp |
||
3278 | INNER JOIN $lp_item_table as lp_i |
||
3279 | ON lp.iid = lp_i.lp_id |
||
3280 | INNER JOIN $lp_view_table as lp_view |
||
3281 | ON lp_view.lp_id = lp_i.lp_id |
||
3282 | INNER JOIN $lp_item_view_table as lp_iv |
||
3283 | ON |
||
3284 | lp_i.iid = lp_iv.lp_item_id AND |
||
3285 | lp_iv.lp_view_id = lp_view.iid |
||
3286 | WHERE (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."') AND |
||
3287 | $conditionsToString |
||
3288 | "; |
||
3289 | $result = Database::query($sql); |
||
3290 | $row = Database::fetch_assoc($result); |
||
3291 | |||
3292 | if (empty($row['sum_max_score'])) { |
||
3293 | return 0; |
||
3294 | } |
||
3295 | |||
3296 | return ($row['sum_score'] / $row['sum_max_score']) * 100; |
||
3297 | } |
||
3298 | |||
3299 | /** |
||
3300 | * This function gets time spent in learning path for a student inside a course. |
||
3301 | * |
||
3302 | * @param int|array $student_id Student id(s) |
||
3303 | * @param Course $course Course code |
||
3304 | * @param array $lp_ids Limit average to listed lp ids |
||
3305 | * @param int $sessionId Session id (optional), if param $sessionId is null(default) |
||
3306 | * it'll return results including sessions, 0 = session is not filtered |
||
3307 | * |
||
3308 | * @return int Total time in seconds |
||
3309 | */ |
||
3310 | public static function get_time_spent_in_lp( |
||
3311 | $student_id, |
||
3312 | Course $course, |
||
3313 | $lp_ids = [], |
||
3314 | $sessionId = 0 |
||
3315 | ) { |
||
3316 | $student_id = (int) $student_id; |
||
3317 | $sessionId = (int) $sessionId; |
||
3318 | $total_time = 0; |
||
3319 | |||
3320 | if (!empty($course)) { |
||
3321 | $lpTable = Database::get_course_table(TABLE_LP_MAIN); |
||
3322 | $lpItemTable = Database::get_course_table(TABLE_LP_ITEM); |
||
3323 | $lpViewTable = Database::get_course_table(TABLE_LP_VIEW); |
||
3324 | $lpItemViewTable = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
3325 | $trackExercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
3326 | $courseId = $course->getId(); |
||
3327 | |||
3328 | // Compose a filter based on optional learning paths list given |
||
3329 | $condition_lp = ''; |
||
3330 | if (count($lp_ids) > 0) { |
||
3331 | $condition_lp = " AND iid IN(".implode(',', $lp_ids).") "; |
||
3332 | } |
||
3333 | |||
3334 | // Check the real number of LPs corresponding to the filter in the |
||
3335 | // database (and if no list was given, get them all) |
||
3336 | $sql = "SELECT DISTINCT(iid) FROM $lpTable |
||
3337 | WHERE 1=1 $condition_lp"; |
||
3338 | $result = Database::query($sql); |
||
3339 | $session_condition = api_get_session_condition($sessionId); |
||
3340 | |||
3341 | // calculates time |
||
3342 | if (Database::num_rows($result) > 0) { |
||
3343 | while ($row = Database::fetch_array($result)) { |
||
3344 | $lp_id = (int) $row['iid']; |
||
3345 | $lp = Container::getLpRepository()->find($lp_id); |
||
3346 | // Start Exercise in LP total_time |
||
3347 | // Get duration time from track_e_exercises.exe_duration instead of lp_view_item.total_time |
||
3348 | $list = learnpath::get_flat_ordered_items_list($lp, 0, $courseId); |
||
3349 | foreach ($list as $itemId) { |
||
3350 | $sql = "SELECT max(view_count) |
||
3351 | FROM $lpViewTable |
||
3352 | WHERE |
||
3353 | c_id = $courseId AND |
||
3354 | lp_id = $lp_id AND |
||
3355 | user_id = $student_id |
||
3356 | $session_condition"; |
||
3357 | $res = Database::query($sql); |
||
3358 | $view = ''; |
||
3359 | if (Database::num_rows($res) > 0) { |
||
3360 | $myrow = Database::fetch_array($res); |
||
3361 | $view = $myrow[0]; |
||
3362 | } |
||
3363 | $viewCondition = null; |
||
3364 | if (!empty($view)) { |
||
3365 | $viewCondition = " AND v.view_count = $view "; |
||
3366 | } |
||
3367 | $sql = "SELECT |
||
3368 | iv.iid, |
||
3369 | iv.total_time as mytime, |
||
3370 | i.iid as myid, |
||
3371 | iv.view_count as iv_view_count, |
||
3372 | path |
||
3373 | FROM $lpItemTable as i |
||
3374 | INNER JOIN $lpItemViewTable as iv |
||
3375 | ON (i.iid = iv.lp_item_id) |
||
3376 | INNER JOIN $lpViewTable as v |
||
3377 | ON (iv.lp_view_id = v.iid) |
||
3378 | WHERE |
||
3379 | v.c_id = $courseId AND |
||
3380 | i.iid = $itemId AND |
||
3381 | i.lp_id = $lp_id AND |
||
3382 | v.user_id = $student_id AND |
||
3383 | item_type = 'quiz' AND |
||
3384 | path <> '' AND |
||
3385 | v.session_id = $sessionId |
||
3386 | $viewCondition |
||
3387 | ORDER BY iv.view_count DESC "; |
||
3388 | |||
3389 | $resultRow = Database::query($sql); |
||
3390 | if (Database::num_rows($resultRow)) { |
||
3391 | $row = Database::fetch_array($resultRow); |
||
3392 | $totalTimeInLpItemView = $row['mytime']; |
||
3393 | $lpItemViewId = $row['iid']; |
||
3394 | $sessionCondition = api_get_session_condition($sessionId); |
||
3395 | $sql = 'SELECT SUM(exe_duration) exe_duration |
||
3396 | FROM '.$trackExercises.' |
||
3397 | WHERE |
||
3398 | exe_exo_id="'.$row['path'].'" AND |
||
3399 | exe_user_id="'.$student_id.'" AND |
||
3400 | orig_lp_id = "'.$lp_id.'" AND |
||
3401 | orig_lp_item_id = "'.$row['myid'].'" AND |
||
3402 | c_id = '.$courseId.' AND |
||
3403 | status <> "incomplete" |
||
3404 | '.$sessionCondition.' |
||
3405 | ORDER BY exe_date DESC '; |
||
3406 | |||
3407 | $sumScoreResult = Database::query($sql); |
||
3408 | $durationRow = Database::fetch_assoc($sumScoreResult); |
||
3409 | if (!empty($durationRow['exe_duration'])) { |
||
3410 | $exeDuration = $durationRow['exe_duration']; |
||
3411 | if ($exeDuration != $totalTimeInLpItemView && |
||
3412 | !empty($lpItemViewId) && |
||
3413 | !empty($exeDuration) |
||
3414 | ) { |
||
3415 | // Update c_lp_item_view.total_time |
||
3416 | $sqlUpdate = "UPDATE $lpItemViewTable |
||
3417 | SET total_time = '$exeDuration' |
||
3418 | WHERE iid = ".$lpItemViewId; |
||
3419 | Database::query($sqlUpdate); |
||
3420 | } |
||
3421 | } |
||
3422 | } |
||
3423 | } |
||
3424 | |||
3425 | // End total_time fix |
||
3426 | |||
3427 | // Calculate total time |
||
3428 | $sql = "SELECT SUM(total_time) |
||
3429 | FROM $lpItemViewTable AS item_view |
||
3430 | INNER JOIN $lpViewTable AS view |
||
3431 | ON ( |
||
3432 | item_view.lp_view_id = view.iid |
||
3433 | ) |
||
3434 | WHERE |
||
3435 | view.c_id = $courseId AND |
||
3436 | view.lp_id = $lp_id AND |
||
3437 | view.user_id = $student_id AND |
||
3438 | session_id = $sessionId"; |
||
3439 | |||
3440 | $rs = Database::query($sql); |
||
3441 | if (Database::num_rows($rs) > 0) { |
||
3442 | $total_time += Database::result($rs, 0, 0); |
||
3443 | } |
||
3444 | } |
||
3445 | } |
||
3446 | } |
||
3447 | |||
3448 | return $total_time; |
||
3449 | } |
||
3450 | |||
3451 | /** |
||
3452 | * This function gets last connection time to one learning path. |
||
3453 | * |
||
3454 | * @param int|array $student_id Student id(s) |
||
3455 | * @param string $course_code Course code |
||
3456 | * @param int $lp_id Learning path id |
||
3457 | * @param int $sessionId |
||
3458 | * |
||
3459 | * @return int last connection timestamp |
||
3460 | */ |
||
3461 | public static function get_last_connection_time_in_lp( |
||
3462 | $student_id, |
||
3463 | $course_code, |
||
3464 | $lp_id, |
||
3465 | $sessionId = 0 |
||
3466 | ) { |
||
3467 | $course = api_get_course_info($course_code); |
||
3468 | if (empty($course)) { |
||
3469 | return 0; |
||
3470 | } |
||
3471 | |||
3472 | $courseId = $course['real_id']; |
||
3473 | $student_id = (int) $student_id; |
||
3474 | $lp_id = (int) $lp_id; |
||
3475 | $sessionId = (int) $sessionId; |
||
3476 | $lastTime = 0; |
||
3477 | |||
3478 | if (self::minimumTimeAvailable($sessionId, $courseId)) { |
||
3479 | $sql = "SELECT MAX(date_reg) max |
||
3480 | FROM track_e_access_complete |
||
3481 | WHERE |
||
3482 | user_id = $student_id AND |
||
3483 | c_id = $courseId AND |
||
3484 | session_id = $sessionId AND |
||
3485 | tool = 'learnpath' AND |
||
3486 | tool_id = $lp_id AND |
||
3487 | action = 'view' AND |
||
3488 | login_as = 0 |
||
3489 | ORDER BY date_reg ASC |
||
3490 | LIMIT 1"; |
||
3491 | $rs = Database::query($sql); |
||
3492 | |||
3493 | $lastConnection = 0; |
||
3494 | if (Database::num_rows($rs) > 0) { |
||
3495 | $value = Database::fetch_array($rs); |
||
3496 | if (isset($value['max']) && !empty($value['max'])) { |
||
3497 | $lastConnection = api_strtotime($value['max'], 'UTC'); |
||
3498 | } |
||
3499 | } |
||
3500 | |||
3501 | if (!empty($lastConnection)) { |
||
3502 | return $lastConnection; |
||
3503 | } |
||
3504 | } |
||
3505 | if (!empty($course)) { |
||
3506 | $lp_table = Database::get_course_table(TABLE_LP_MAIN); |
||
3507 | $t_lpv = Database::get_course_table(TABLE_LP_VIEW); |
||
3508 | $t_lpiv = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
3509 | |||
3510 | // Check the real number of LPs corresponding to the filter in the |
||
3511 | // database (and if no list was given, get them all) |
||
3512 | $sql = "SELECT iid FROM $lp_table |
||
3513 | WHERE iid = $lp_id "; |
||
3514 | $row = Database::query($sql); |
||
3515 | $count = Database::num_rows($row); |
||
3516 | |||
3517 | // calculates last connection time |
||
3518 | if ($count > 0) { |
||
3519 | $sql = 'SELECT MAX(start_time) |
||
3520 | FROM '.$t_lpiv.' AS item_view |
||
3521 | INNER JOIN '.$t_lpv.' AS view |
||
3522 | ON (item_view.lp_view_id = view.iid) |
||
3523 | WHERE |
||
3524 | status != "not attempted" AND |
||
3525 | view.c_id = '.$courseId.' AND |
||
3526 | view.lp_id = '.$lp_id.' AND |
||
3527 | view.user_id = '.$student_id.' AND |
||
3528 | view.session_id = '.$sessionId; |
||
3529 | $rs = Database::query($sql); |
||
3530 | if (Database::num_rows($rs) > 0) { |
||
3531 | $lastTime = Database::result($rs, 0, 0); |
||
3532 | } |
||
3533 | } |
||
3534 | } |
||
3535 | |||
3536 | return $lastTime; |
||
3537 | } |
||
3538 | |||
3539 | public static function getFirstConnectionTimeInLp( |
||
3540 | $student_id, |
||
3541 | $course_code, |
||
3542 | $lp_id, |
||
3543 | $sessionId = 0 |
||
3544 | ) { |
||
3545 | $course = api_get_course_info($course_code); |
||
3546 | $student_id = (int) $student_id; |
||
3547 | $lp_id = (int) $lp_id; |
||
3548 | $sessionId = (int) $sessionId; |
||
3549 | $time = 0; |
||
3550 | |||
3551 | if (!empty($course)) { |
||
3552 | $courseId = $course['real_id']; |
||
3553 | $lp_table = Database::get_course_table(TABLE_LP_MAIN); |
||
3554 | $t_lpv = Database::get_course_table(TABLE_LP_VIEW); |
||
3555 | $t_lpiv = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
3556 | |||
3557 | // Check the real number of LPs corresponding to the filter in the |
||
3558 | // database (and if no list was given, get them all) |
||
3559 | $sql = "SELECT iid FROM $lp_table |
||
3560 | WHERE iid = $lp_id "; |
||
3561 | $row = Database::query($sql); |
||
3562 | $count = Database::num_rows($row); |
||
3563 | |||
3564 | // calculates first connection time |
||
3565 | if ($count > 0) { |
||
3566 | $sql = 'SELECT MIN(start_time) |
||
3567 | FROM '.$t_lpiv.' AS item_view |
||
3568 | INNER JOIN '.$t_lpv.' AS view |
||
3569 | ON (item_view.lp_view_id = view.iid) |
||
3570 | WHERE |
||
3571 | status != "not attempted" AND |
||
3572 | view.c_id = '.$courseId.' AND |
||
3573 | view.lp_id = '.$lp_id.' AND |
||
3574 | view.user_id = '.$student_id.' AND |
||
3575 | view.session_id = '.$sessionId; |
||
3576 | $rs = Database::query($sql); |
||
3577 | if (Database::num_rows($rs) > 0) { |
||
3578 | $time = Database::result($rs, 0, 0); |
||
3579 | } |
||
3580 | } |
||
3581 | } |
||
3582 | |||
3583 | return $time; |
||
3584 | } |
||
3585 | |||
3586 | /** |
||
3587 | * gets the list of students followed by coach. |
||
3588 | * |
||
3589 | * @param int $coach_id Coach id |
||
3590 | * |
||
3591 | * @return array List of students |
||
3592 | */ |
||
3593 | public static function get_student_followed_by_coach($coach_id) |
||
3594 | { |
||
3595 | $coach_id = (int) $coach_id; |
||
3596 | $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION); |
||
3597 | $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
3598 | $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE); |
||
3599 | $tbl_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER); |
||
3600 | $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION); |
||
3601 | |||
3602 | $accessUrlUtil = Container::getAccessUrlUtil(); |
||
3603 | $access_url_id = -1; |
||
3604 | if ($accessUrlUtil->isMultiple()) { |
||
3605 | $access_url_id = $accessUrlUtil->getCurrent()->getId(); |
||
3606 | } |
||
3607 | $students = []; |
||
3608 | // At first, courses where $coach_id is coach of the course // |
||
3609 | $sql = 'SELECT session_id, c_id |
||
3610 | FROM '.$tbl_session_course_user.' |
||
3611 | WHERE user_id='.$coach_id.' AND status = '.SessionEntity::COURSE_COACH; |
||
3612 | |||
3613 | if (-1 != $access_url_id) { |
||
3614 | $sql = 'SELECT scu.session_id, scu.c_id |
||
3615 | FROM '.$tbl_session_course_user.' scu |
||
3616 | INNER JOIN '.$tbl_session_rel_access_url.' sru |
||
3617 | ON (scu.session_id=sru.session_id) |
||
3618 | WHERE |
||
3619 | scu.user_id='.$coach_id.' AND |
||
3620 | scu.status = '.SessionEntity::COURSE_COACH.' AND |
||
3621 | sru.access_url_id = '.$access_url_id; |
||
3622 | } |
||
3623 | |||
3624 | $result = Database::query($sql); |
||
3625 | |||
3626 | while ($a_courses = Database::fetch_array($result)) { |
||
3627 | $courseId = $a_courses['c_id']; |
||
3628 | $sessionId = $a_courses['session_id']; |
||
3629 | |||
3630 | $sql = "SELECT DISTINCT srcru.user_id |
||
3631 | FROM $tbl_session_course_user AS srcru |
||
3632 | INNER JOIN $tbl_session_user sru |
||
3633 | ON (srcru.user_id = sru.user_id AND srcru.session_id = sru.session_id) |
||
3634 | WHERE |
||
3635 | sru.relation_type = ".SessionEntity::STUDENT." AND |
||
3636 | srcru.c_id = '$courseId' AND |
||
3637 | srcru.session_id = '$sessionId'"; |
||
3638 | |||
3639 | $rs = Database::query($sql); |
||
3640 | while ($row = Database::fetch_array($rs)) { |
||
3641 | $students[$row['user_id']] = $row['user_id']; |
||
3642 | } |
||
3643 | } |
||
3644 | |||
3645 | // Then, courses where $coach_id is coach of the session |
||
3646 | $sql = "SELECT srcru.user_id |
||
3647 | FROM $tbl_session_course_user srcru |
||
3648 | INNER JOIN $tbl_session_course src |
||
3649 | ON (srcru.c_id = src.c_id AND srcru.session_id = src.session_id) |
||
3650 | INNER JOIN $tbl_session s |
||
3651 | ON srcru.session_id = s.id AND src.session_id = s.id |
||
3652 | INNER JOIN $tbl_session_user sru on s.id = sru.session_id |
||
3653 | WHERE |
||
3654 | srcru.status = ".SessionEntity::STUDENT." AND |
||
3655 | sru.relation_type = ".SessionEntity::GENERAL_COACH." AND |
||
3656 | sru.user_id = $coach_id"; |
||
3657 | |||
3658 | if (-1 != $access_url_id) { |
||
3659 | $sql = "SELECT srcru.user_id |
||
3660 | FROM $tbl_session_course_user srcru |
||
3661 | INNER JOIN $tbl_session_course src |
||
3662 | ON (srcru.c_id = src.c_id AND srcru.session_id = src.session_id) |
||
3663 | INNER JOIN $tbl_session s |
||
3664 | ON srcru.session_id = s.id AND src.session_id = s.id |
||
3665 | INNER JOIN $tbl_session_user sru |
||
3666 | ON s.id = sru.session_id |
||
3667 | INNER JOIN $tbl_session_rel_access_url aurs |
||
3668 | ON s.id = aurs.session_id |
||
3669 | WHERE |
||
3670 | srcru.status = ".SessionEntity::STUDENT." AND |
||
3671 | sru.relation_type = ".SessionEntity::GENERAL_COACH." AND |
||
3672 | sru.user_id = $coach_id AND |
||
3673 | aurs.access_url_id = $access_url_id"; |
||
3674 | } |
||
3675 | |||
3676 | $result = Database::query($sql); |
||
3677 | while ($row = Database::fetch_array($result)) { |
||
3678 | $students[$row['user_id']] = $row['user_id']; |
||
3679 | } |
||
3680 | |||
3681 | return $students; |
||
3682 | } |
||
3683 | |||
3684 | /** |
||
3685 | * Check if a coach is allowed to follow a student. |
||
3686 | * |
||
3687 | * @param int Coach id |
||
3688 | * @param int Student id |
||
3689 | * |
||
3690 | * @return bool |
||
3691 | */ |
||
3692 | public static function is_allowed_to_coach_student($coach_id, $student_id) |
||
3693 | { |
||
3694 | $coach_id = intval($coach_id); |
||
3695 | $student_id = intval($student_id); |
||
3696 | |||
3697 | $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
3698 | $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE); |
||
3699 | $tblSessionRelUser = Database::get_main_table(TABLE_MAIN_SESSION_USER); |
||
3700 | $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION); |
||
3701 | |||
3702 | // At first, courses where $coach_id is coach of the course |
||
3703 | $sql = 'SELECT 1 FROM '.$tbl_session_course_user.' |
||
3704 | WHERE user_id='.$coach_id.' AND status = '.SessionEntity::COURSE_COACH; |
||
3705 | $result = Database::query($sql); |
||
3706 | if (Database::num_rows($result) > 0) { |
||
3707 | return true; |
||
3708 | } |
||
3709 | |||
3710 | // Then, courses where $coach_id is coach of the session |
||
3711 | $sql = "SELECT srcru.user_id |
||
3712 | FROM $tbl_session_course_user srcru |
||
3713 | INNER JOIN $tbl_session_course src |
||
3714 | ON (srcru.c_id = src.c_id AND srcru.session_id = src.session_id) |
||
3715 | INNER JOIN $tbl_session s |
||
3716 | ON srcru.session_id = s.id AND src.session_id = s.id |
||
3717 | INNER JOIN $tblSessionRelUser sru |
||
3718 | ON s.id = sru.session_id |
||
3719 | WHERE |
||
3720 | (srcru.status = ".SessionEntity::STUDENT." AND srcru.user_id = $student_id) AND |
||
3721 | (sru.relation_type = ".SessionEntity::GENERAL_COACH." AND sru.user_id = $coach_id)"; |
||
3722 | $result = Database::query($sql); |
||
3723 | if (Database::num_rows($result) > 0) { |
||
3724 | return true; |
||
3725 | } |
||
3726 | |||
3727 | return false; |
||
3728 | } |
||
3729 | |||
3730 | /** |
||
3731 | * Get courses followed by coach. |
||
3732 | * |
||
3733 | * @param int Coach id |
||
3734 | * @param int Session id (optional) |
||
3735 | * |
||
3736 | * @return array Courses list |
||
3737 | */ |
||
3738 | public static function get_courses_followed_by_coach($coach_id, $sessionId = 0) |
||
3739 | { |
||
3740 | $coach_id = intval($coach_id); |
||
3741 | if (!empty($sessionId)) { |
||
3742 | $sessionId = intval($sessionId); |
||
3743 | } |
||
3744 | |||
3745 | $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
3746 | $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE); |
||
3747 | $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION); |
||
3748 | $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE); |
||
3749 | $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); |
||
3750 | $tblSessionRelUser = Database::get_main_table(TABLE_MAIN_SESSION_USER); |
||
3751 | |||
3752 | // At first, courses where $coach_id is coach of the course. |
||
3753 | $sql = 'SELECT DISTINCT c.code |
||
3754 | FROM '.$tbl_session_course_user.' sc |
||
3755 | INNER JOIN '.$tbl_course.' c |
||
3756 | ON (c.id = sc.c_id) |
||
3757 | WHERE sc.user_id = '.$coach_id.' AND sc.status = '.SessionEntity::COURSE_COACH; |
||
3758 | |||
3759 | $accessUrlUtil = Container::getAccessUrlUtil(); |
||
3760 | if ($accessUrlUtil->isMultiple()) { |
||
3761 | $access_url_id = $accessUrlUtil->getCurrent()->getId(); |
||
3762 | if (-1 != $access_url_id) { |
||
3763 | $sql = 'SELECT DISTINCT c.code |
||
3764 | FROM '.$tbl_session_course_user.' scu |
||
3765 | INNER JOIN '.$tbl_course.' c |
||
3766 | ON (c.code = scu.c_id) |
||
3767 | INNER JOIN '.$tbl_course_rel_access_url.' cru |
||
3768 | ON (c.id = cru.c_id) |
||
3769 | WHERE |
||
3770 | scu.user_id='.$coach_id.' AND |
||
3771 | scu.status = '.SessionEntity::COURSE_COACH.' AND |
||
3772 | cru.access_url_id = '.$access_url_id; |
||
3773 | } |
||
3774 | } |
||
3775 | |||
3776 | if (!empty($sessionId)) { |
||
3777 | $sql .= ' AND session_id='.$sessionId; |
||
3778 | } |
||
3779 | |||
3780 | $courseList = []; |
||
3781 | $result = Database::query($sql); |
||
3782 | while ($row = Database::fetch_array($result)) { |
||
3783 | $courseList[$row['code']] = $row['code']; |
||
3784 | } |
||
3785 | |||
3786 | // Then, courses where $coach_id is coach of the session |
||
3787 | $sql = "SELECT DISTINCT course.code |
||
3788 | FROM $tbl_session_course as session_course |
||
3789 | INNER JOIN $tbl_session as session |
||
3790 | ON (session.id = session_course.session_id) |
||
3791 | INNER JOIN $tblSessionRelUser session_user |
||
3792 | ON (session.id = session_user.session_id |
||
3793 | AND session_user.user_id = $coach_id |
||
3794 | AND session_user.relation_type = ".SessionEntity::GENERAL_COACH.") |
||
3795 | INNER JOIN $tbl_course as course |
||
3796 | ON course.id = session_course.c_id"; |
||
3797 | |||
3798 | if ($accessUrlUtil->isMultiple()) { |
||
3799 | $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); |
||
3800 | $access_url_id = $accessUrlUtil->getCurrent()->getId(); |
||
3801 | if (-1 != $access_url_id) { |
||
3802 | $sql = "SELECT DISTINCT c.code |
||
3803 | FROM $tbl_session_course as session_course |
||
3804 | INNER JOIN $tbl_course c |
||
3805 | ON (c.id = session_course.c_id) |
||
3806 | INNER JOIN $tbl_session as session |
||
3807 | ON session.id = session_course.session_id |
||
3808 | INNER JOIN $tblSessionRelUser session_user |
||
3809 | ON (session.id = session_user.session_id |
||
3810 | AND session_user.user_id = $coach_id |
||
3811 | AND session_user.relation_type = ".SessionEntity::GENERAL_COACH.") |
||
3812 | INNER JOIN $tbl_course as course |
||
3813 | ON course.id = session_course.c_id |
||
3814 | INNER JOIN $tbl_course_rel_access_url course_rel_url |
||
3815 | ON (course_rel_url.c_id = c.id)"; |
||
3816 | } |
||
3817 | } |
||
3818 | |||
3819 | if (!empty($sessionId)) { |
||
3820 | $sql .= ' WHERE session_course.session_id='.$sessionId; |
||
3821 | if ($accessUrlUtil->isMultiple()) { |
||
3822 | $sql .= ' AND access_url_id = '.$access_url_id; |
||
3823 | } |
||
3824 | } else { |
||
3825 | if ($accessUrlUtil->isMultiple()) { |
||
3826 | $sql .= ' WHERE access_url_id = '.$access_url_id; |
||
3827 | } |
||
3828 | } |
||
3829 | |||
3830 | $result = Database::query($sql); |
||
3831 | while ($row = Database::fetch_array($result)) { |
||
3832 | $courseList[$row['code']] = $row['code']; |
||
3833 | } |
||
3834 | |||
3835 | return $courseList; |
||
3836 | } |
||
3837 | |||
3838 | /** |
||
3839 | * Get sessions coached by user. |
||
3840 | * |
||
3841 | * @param int $coach_id |
||
3842 | * @param int $start |
||
3843 | * @param int $limit |
||
3844 | * @param bool $getCount |
||
3845 | * @param string $keyword |
||
3846 | * @param string $description |
||
3847 | * @param string $orderByName |
||
3848 | * @param string $orderByDirection |
||
3849 | * @param array $options |
||
3850 | * |
||
3851 | * @return mixed |
||
3852 | */ |
||
3853 | public static function get_sessions_coached_by_user( |
||
3854 | $coach_id, |
||
3855 | $start = 0, |
||
3856 | $limit = 0, |
||
3857 | $getCount = false, |
||
3858 | $keyword = '', |
||
3859 | $description = '', |
||
3860 | $orderByName = '', |
||
3861 | $orderByDirection = '', |
||
3862 | $options = [] |
||
3863 | ) { |
||
3864 | // table definition |
||
3865 | $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION); |
||
3866 | $tblSessionRelUser = Database::get_main_table(TABLE_MAIN_SESSION_USER); |
||
3867 | $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
3868 | $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION); |
||
3869 | |||
3870 | $coach_id = (int) $coach_id; |
||
3871 | |||
3872 | $select = ' SELECT * FROM '; |
||
3873 | if ($getCount) { |
||
3874 | $select = ' SELECT count(DISTINCT id) as count FROM '; |
||
3875 | } |
||
3876 | |||
3877 | $limitCondition = null; |
||
3878 | if (!empty($start) && !empty($limit)) { |
||
3879 | $limitCondition = " LIMIT ".intval($start).", ".intval($limit); |
||
3880 | } |
||
3881 | |||
3882 | $keywordCondition = null; |
||
3883 | if (!empty($keyword)) { |
||
3884 | $keyword = Database::escape_string($keyword); |
||
3885 | $keywordCondition = " AND (title LIKE '%$keyword%' ) "; |
||
3886 | |||
3887 | if (!empty($description)) { |
||
3888 | $description = Database::escape_string($description); |
||
3889 | $keywordCondition = " AND (title LIKE '%$keyword%' OR description LIKE '%$description%' ) "; |
||
3890 | } |
||
3891 | } |
||
3892 | |||
3893 | $extraFieldModel = new ExtraFieldModel('session'); |
||
3894 | $conditions = $extraFieldModel->parseConditions($options); |
||
3895 | $sqlInjectJoins = $conditions['inject_joins']; |
||
3896 | $extraFieldsConditions = $conditions['where']; |
||
3897 | $sqlInjectWhere = $conditions['inject_where']; |
||
3898 | $injectExtraFields = $conditions['inject_extra_fields']; |
||
3899 | |||
3900 | $access_url_id = api_get_current_access_url_id(); |
||
3901 | |||
3902 | $orderBy = ''; |
||
3903 | if (!empty($orderByName)) { |
||
3904 | if (in_array($orderByName, ['title', 'access_start_date'])) { |
||
3905 | $orderByDirection = in_array(strtolower($orderByDirection), ['asc', 'desc']) ? $orderByDirection : 'asc'; |
||
3906 | $orderByName = Database::escape_string($orderByName); |
||
3907 | $orderBy .= " ORDER BY `$orderByName` $orderByDirection"; |
||
3908 | } |
||
3909 | } |
||
3910 | |||
3911 | $sql = " |
||
3912 | $select |
||
3913 | ( |
||
3914 | SELECT DISTINCT |
||
3915 | s.id, |
||
3916 | title, |
||
3917 | $injectExtraFields |
||
3918 | access_start_date, |
||
3919 | access_end_date |
||
3920 | FROM $tbl_session s |
||
3921 | INNER JOIN $tbl_session_rel_access_url session_rel_url |
||
3922 | ON (s.id = session_rel_url.session_id) |
||
3923 | $sqlInjectJoins |
||
3924 | INNER JOIN $tblSessionRelUser sru ON s.id = sru.session_id |
||
3925 | WHERE |
||
3926 | (sru.user_id = $coach_id AND sru.relation_type = ".SessionEntity::GENERAL_COACH.") AND |
||
3927 | access_url_id = $access_url_id |
||
3928 | $keywordCondition |
||
3929 | $extraFieldsConditions |
||
3930 | $sqlInjectWhere |
||
3931 | UNION |
||
3932 | SELECT DISTINCT |
||
3933 | s.id, |
||
3934 | s.title, |
||
3935 | $injectExtraFields |
||
3936 | s.access_start_date, |
||
3937 | s.access_end_date |
||
3938 | FROM $tbl_session as s |
||
3939 | INNER JOIN $tbl_session_course_user as session_course_user |
||
3940 | ON |
||
3941 | s.id = session_course_user.session_id AND |
||
3942 | session_course_user.user_id = $coach_id AND |
||
3943 | session_course_user.status = ".SessionEntity::COURSE_COACH." |
||
3944 | INNER JOIN $tbl_session_rel_access_url session_rel_url |
||
3945 | ON (s.id = session_rel_url.session_id) |
||
3946 | $sqlInjectJoins |
||
3947 | WHERE |
||
3948 | access_url_id = $access_url_id |
||
3949 | $keywordCondition |
||
3950 | $extraFieldsConditions |
||
3951 | $sqlInjectWhere |
||
3952 | ) as sessions $limitCondition $orderBy |
||
3953 | "; |
||
3954 | |||
3955 | $rs = Database::query($sql); |
||
3956 | if ($getCount) { |
||
3957 | $row = Database::fetch_array($rs); |
||
3958 | |||
3959 | return $row['count']; |
||
3960 | } |
||
3961 | |||
3962 | $sessions = []; |
||
3963 | while ($row = Database::fetch_array($rs)) { |
||
3964 | if ('0000-00-00 00:00:00' === $row['access_start_date']) { |
||
3965 | $row['access_start_date'] = null; |
||
3966 | } |
||
3967 | |||
3968 | $sessions[$row['id']] = $row; |
||
3969 | } |
||
3970 | |||
3971 | if (!empty($sessions)) { |
||
3972 | foreach ($sessions as &$session) { |
||
3973 | if (empty($session['access_start_date'])) { |
||
3974 | $session['status'] = get_lang('active'); |
||
3975 | } else { |
||
3976 | $time_start = api_strtotime($session['access_start_date'], 'UTC'); |
||
3977 | $time_end = api_strtotime($session['access_end_date'], 'UTC'); |
||
3978 | if ($time_start < time() && time() < $time_end) { |
||
3979 | $session['status'] = get_lang('active'); |
||
3980 | } else { |
||
3981 | if (time() < $time_start) { |
||
3982 | $session['status'] = get_lang('Not yet begun'); |
||
3983 | } else { |
||
3984 | if (time() > $time_end) { |
||
3985 | $session['status'] = get_lang('Past'); |
||
3986 | } |
||
3987 | } |
||
3988 | } |
||
3989 | } |
||
3990 | } |
||
3991 | } |
||
3992 | |||
3993 | return $sessions; |
||
3994 | } |
||
3995 | |||
3996 | /** |
||
3997 | * Get courses list from a session. |
||
3998 | * |
||
3999 | * @param int Session id |
||
4000 | * |
||
4001 | * @return array Courses list |
||
4002 | */ |
||
4003 | public static function get_courses_list_from_session($sessionId) |
||
4004 | { |
||
4005 | $sessionId = (int) $sessionId; |
||
4006 | |||
4007 | // table definition |
||
4008 | $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE); |
||
4009 | $courseTable = Database::get_main_table(TABLE_MAIN_COURSE); |
||
4010 | |||
4011 | $sql = "SELECT DISTINCT code, c_id |
||
4012 | FROM $tbl_session_course sc |
||
4013 | INNER JOIN $courseTable c |
||
4014 | ON sc.c_id = c.id |
||
4015 | WHERE session_id= $sessionId"; |
||
4016 | |||
4017 | $result = Database::query($sql); |
||
4018 | |||
4019 | $courses = []; |
||
4020 | while ($row = Database::fetch_array($result)) { |
||
4021 | $courses[$row['code']] = $row; |
||
4022 | } |
||
4023 | |||
4024 | return $courses; |
||
4025 | } |
||
4026 | |||
4027 | /** |
||
4028 | * Count the number of documents that an user has uploaded to a course. |
||
4029 | * |
||
4030 | * @param int|array Student id(s) |
||
4031 | * @param string Course code |
||
4032 | * @param int Session id (optional), |
||
4033 | * if param $sessionId is null(default) |
||
4034 | * return count of assignments including sessions, 0 = session is not filtered |
||
4035 | * |
||
4036 | * @return int Number of documents |
||
4037 | */ |
||
4038 | public static function count_student_uploaded_documents( |
||
4039 | $student_id, |
||
4040 | $course_code, |
||
4041 | $sessionId = null |
||
4042 | ) { |
||
4043 | $a_course = api_get_course_info($course_code); |
||
4044 | $repo = Container::getDocumentRepository(); |
||
4045 | |||
4046 | $user = api_get_user_entity($student_id); |
||
4047 | $course = api_get_course_entity($a_course['real_id']); |
||
4048 | $session = api_get_session_entity($sessionId); |
||
4049 | //$group = api_get_group_entity(api_get_group_id()); |
||
4050 | |||
4051 | $qb = $repo->getResourcesByCourseLinkedToUser($user, $course, $session); |
||
4052 | |||
4053 | $qb->select('count(resource)'); |
||
4054 | $count = $qb->getQuery()->getSingleScalarResult(); |
||
4055 | |||
4056 | return $count; |
||
4057 | } |
||
4058 | |||
4059 | /** |
||
4060 | * This function counts the number of post by course. |
||
4061 | * |
||
4062 | * @param string $courseId |
||
4063 | * @param int $sessionId (optional), if is null(default) it'll return results including sessions, |
||
4064 | * 0 = session is not filtered |
||
4065 | * @param int $groupId |
||
4066 | * |
||
4067 | * @return int The number of post by course |
||
4068 | */ |
||
4069 | public static function count_number_of_posts_by_course($courseId, $sessionId = null, $groupId = 0) |
||
4070 | { |
||
4071 | $repo = Container::getForumPostRepository(); |
||
4072 | $course = api_get_course_entity($courseId); |
||
4073 | $session = api_get_session_entity($sessionId); |
||
4074 | $group = api_get_group_entity($groupId); |
||
4075 | $qb = $repo->getResourcesByCourse($course, $session, $group); |
||
4076 | |||
4077 | $qb->select('count(resource)'); |
||
4078 | $count = $qb->getQuery()->getSingleScalarResult(); |
||
4079 | |||
4080 | return $count; |
||
4081 | } |
||
4082 | |||
4083 | /** |
||
4084 | * This function counts the number of threads by course. |
||
4085 | * |
||
4086 | * @param int Course id |
||
4087 | * @param int Session id (optional), |
||
4088 | * if param $sessionId is null(default) it'll return results including |
||
4089 | * sessions, 0 = session is not filtered |
||
4090 | * @param int $groupId |
||
4091 | * |
||
4092 | * @return int The number of threads by course |
||
4093 | */ |
||
4094 | public static function count_number_of_threads_by_course( |
||
4095 | $courseId, |
||
4096 | $sessionId = null, |
||
4097 | $groupId = 0 |
||
4098 | ) { |
||
4099 | $repo = Container::getForumThreadRepository(); |
||
4100 | $course = api_get_course_entity($courseId); |
||
4101 | $session = api_get_session_entity($sessionId); |
||
4102 | $group = api_get_group_entity($groupId); |
||
4103 | $qb = $repo->getResourcesByCourse($course, $session, $group); |
||
4104 | |||
4105 | $qb->select('count(resource)'); |
||
4106 | $count = $qb->getQuery()->getSingleScalarResult(); |
||
4107 | |||
4108 | return $count; |
||
4109 | } |
||
4110 | |||
4111 | /** |
||
4112 | * This function counts the number of forums by course. |
||
4113 | * |
||
4114 | * @param int Course id |
||
4115 | * @param int Session id (optional), |
||
4116 | * if param $sessionId is null(default) it'll return results |
||
4117 | * including sessions, 0 = session is not filtered |
||
4118 | * @param int $groupId |
||
4119 | * |
||
4120 | * @return int The number of forums by course |
||
4121 | */ |
||
4122 | public static function count_number_of_forums_by_course( |
||
4123 | $courseId, |
||
4124 | $sessionId = null, |
||
4125 | $groupId = 0 |
||
4126 | ) { |
||
4127 | $repo = Container::getForumRepository(); |
||
4128 | $course = api_get_course_entity($courseId); |
||
4129 | $session = api_get_session_entity($sessionId); |
||
4130 | $group = api_get_group_entity($groupId); |
||
4131 | |||
4132 | $qb = $repo->getResourcesByCourse($course, $session, $group); |
||
4133 | $qb->select('count(resource)'); |
||
4134 | $count = $qb->getQuery()->getSingleScalarResult(); |
||
4135 | |||
4136 | return $count; |
||
4137 | } |
||
4138 | |||
4139 | /** |
||
4140 | * This function counts the chat last connections by course in x days. |
||
4141 | * |
||
4142 | * @param string Course code |
||
4143 | * @param int Last x days |
||
4144 | * @param int Session id (optional) |
||
4145 | * |
||
4146 | * @return int Chat last connections by course in x days |
||
4147 | */ |
||
4148 | public static function chat_connections_during_last_x_days_by_course( |
||
4149 | $course_code, |
||
4150 | $last_days, |
||
4151 | $session_id = 0 |
||
4152 | ) { |
||
4153 | $course_info = api_get_course_info($course_code); |
||
4154 | if (empty($course_info)) { |
||
4155 | return null; |
||
4156 | } |
||
4157 | $courseId = $course_info['real_id']; |
||
4158 | |||
4159 | // Protect data |
||
4160 | $last_days = (int) $last_days; |
||
4161 | $session_id = (int) $session_id; |
||
4162 | |||
4163 | $tbl_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS); |
||
4164 | $now = api_get_utc_datetime(); |
||
4165 | |||
4166 | $sql = "SELECT count(*) FROM $tbl_stats_access |
||
4167 | WHERE |
||
4168 | DATE_SUB('$now',INTERVAL $last_days DAY) <= access_date AND |
||
4169 | c_id = '$courseId' AND |
||
4170 | access_tool='".TOOL_CHAT."' AND |
||
4171 | session_id = '$session_id' "; |
||
4172 | $result = Database::query($sql); |
||
4173 | if (Database::num_rows($result)) { |
||
4174 | $row = Database::fetch_row($result); |
||
4175 | $count = $row[0]; |
||
4176 | |||
4177 | return $count; |
||
4178 | } |
||
4179 | |||
4180 | return 0; |
||
4181 | } |
||
4182 | |||
4183 | /** |
||
4184 | * This function gets the last student's connection in chat. |
||
4185 | * |
||
4186 | * @param int Student id |
||
4187 | * @param string Course code |
||
4188 | * @param int Session id (optional) |
||
4189 | * |
||
4190 | * @return string datetime formatted without day (e.g: February 23, 2010 10:20:50 ) |
||
4191 | */ |
||
4192 | public static function chat_last_connection( |
||
4193 | $student_id, |
||
4194 | $courseId, |
||
4195 | $session_id = 0 |
||
4196 | ) { |
||
4197 | $student_id = (int) $student_id; |
||
4198 | $courseId = (int) $courseId; |
||
4199 | $session_id = (int) $session_id; |
||
4200 | $date_time = ''; |
||
4201 | |||
4202 | // table definition |
||
4203 | $tbl_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS); |
||
4204 | $sql = "SELECT access_date |
||
4205 | FROM $tbl_stats_access |
||
4206 | WHERE |
||
4207 | access_tool='".TOOL_CHAT."' AND |
||
4208 | access_user_id='$student_id' AND |
||
4209 | c_id = $courseId AND |
||
4210 | session_id = '$session_id' |
||
4211 | ORDER BY access_date DESC limit 1"; |
||
4212 | $rs = Database::query($sql); |
||
4213 | if (Database::num_rows($rs) > 0) { |
||
4214 | $row = Database::fetch_array($rs); |
||
4215 | $date_time = api_convert_and_format_date( |
||
4216 | $row['access_date'], |
||
4217 | null, |
||
4218 | date_default_timezone_get() |
||
4219 | ); |
||
4220 | } |
||
4221 | |||
4222 | return $date_time; |
||
4223 | } |
||
4224 | |||
4225 | /** |
||
4226 | * Get count student's visited links. |
||
4227 | * |
||
4228 | * @param int $student_id Student id |
||
4229 | * @param int $courseId |
||
4230 | * @param int $session_id Session id (optional) |
||
4231 | * |
||
4232 | * @return int count of visited links |
||
4233 | */ |
||
4234 | public static function count_student_visited_links($student_id, $courseId, $session_id = 0) |
||
4235 | { |
||
4236 | $student_id = (int) $student_id; |
||
4237 | $courseId = (int) $courseId; |
||
4238 | $session_id = (int) $session_id; |
||
4239 | |||
4240 | // table definition |
||
4241 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS); |
||
4242 | |||
4243 | $sql = 'SELECT 1 |
||
4244 | FROM '.$table.' |
||
4245 | WHERE |
||
4246 | links_user_id= '.$student_id.' AND |
||
4247 | c_id = "'.$courseId.'" AND |
||
4248 | session_id = '.$session_id.' '; |
||
4249 | |||
4250 | $rs = Database::query($sql); |
||
4251 | |||
4252 | return Database::num_rows($rs); |
||
4253 | } |
||
4254 | |||
4255 | public static function countStudentDownloadedDocuments(int $studentId, int $courseId, int $sessionId = 0): int |
||
4256 | { |
||
4257 | $em = Database::getManager(); |
||
4258 | $qb = $em->createQueryBuilder(); |
||
4259 | |||
4260 | $qb->select('COUNT(td.downId)') |
||
4261 | ->from(TrackEDownloads::class, 'td') |
||
4262 | ->leftJoin('td.resourceLink', 'rl') |
||
4263 | ->where('td.downUserId = :studentId') |
||
4264 | ->andWhere('rl.course = :courseId') |
||
4265 | ->setParameter('studentId', $studentId) |
||
4266 | ->setParameter('courseId', $courseId); |
||
4267 | |||
4268 | if ($sessionId > 0) { |
||
4269 | $qb->andWhere('rl.session = :sessionId') |
||
4270 | ->setParameter('sessionId', $sessionId); |
||
4271 | } |
||
4272 | |||
4273 | $query = $qb->getQuery(); |
||
4274 | |||
4275 | return (int) $query->getSingleScalarResult(); |
||
4276 | } |
||
4277 | |||
4278 | /** |
||
4279 | * Get course list inside a session from a student. |
||
4280 | * |
||
4281 | * @param int $user_id Student id |
||
4282 | * @param int $sessionId Session id (optional) |
||
4283 | * |
||
4284 | * @return array Courses list |
||
4285 | */ |
||
4286 | public static function get_course_list_in_session_from_student($user_id, $sessionId = 0) |
||
4287 | { |
||
4288 | $user_id = (int) $user_id; |
||
4289 | $sessionId = (int) $sessionId; |
||
4290 | $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
4291 | $courseTable = Database::get_main_table(TABLE_MAIN_COURSE); |
||
4292 | |||
4293 | $sql = "SELECT c.code |
||
4294 | FROM $tbl_session_course_user sc |
||
4295 | INNER JOIN $courseTable c |
||
4296 | WHERE |
||
4297 | user_id= $user_id AND |
||
4298 | session_id = $sessionId"; |
||
4299 | $result = Database::query($sql); |
||
4300 | $courses = []; |
||
4301 | while ($row = Database::fetch_array($result)) { |
||
4302 | $courses[$row['code']] = $row['code']; |
||
4303 | } |
||
4304 | |||
4305 | return $courses; |
||
4306 | } |
||
4307 | |||
4308 | /** |
||
4309 | * Get inactive students in course. |
||
4310 | * |
||
4311 | * @param int $courseId |
||
4312 | * @param string|int $since Since login course date (optional, default = 'never') |
||
4313 | * @param int $session_id (optional) |
||
4314 | * |
||
4315 | * @return array Inactive users |
||
4316 | */ |
||
4317 | public static function getInactiveStudentsInCourse( |
||
4318 | $courseId, |
||
4319 | $since = 'never', |
||
4320 | $session_id = 0 |
||
4321 | ) { |
||
4322 | $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
4323 | $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
4324 | $table_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER); |
||
4325 | $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE); |
||
4326 | $now = api_get_utc_datetime(); |
||
4327 | $courseId = (int) $courseId; |
||
4328 | $session_id = (int) $session_id; |
||
4329 | |||
4330 | if (empty($courseId)) { |
||
4331 | return false; |
||
4332 | } |
||
4333 | |||
4334 | if ('never' === $since) { |
||
4335 | if (empty($session_id)) { |
||
4336 | $sql = 'SELECT course_user.user_id |
||
4337 | FROM '.$table_course_rel_user.' course_user |
||
4338 | LEFT JOIN '.$tbl_track_login.' stats_login |
||
4339 | ON course_user.user_id = stats_login.user_id AND |
||
4340 | relation_type<>'.COURSE_RELATION_TYPE_RRHH.' |
||
4341 | INNER JOIN '.$tableCourse.' c |
||
4342 | ON (c.id = course_user.c_id) |
||
4343 | WHERE |
||
4344 | course_user.c_id = '.$courseId.' AND |
||
4345 | stats_login.login_course_date IS NULL |
||
4346 | GROUP BY course_user.user_id'; |
||
4347 | } else { |
||
4348 | $sql = 'SELECT session_course_user.user_id |
||
4349 | FROM '.$tbl_session_course_user.' session_course_user |
||
4350 | LEFT JOIN '.$tbl_track_login.' stats_login |
||
4351 | ON session_course_user.user_id = stats_login.user_id |
||
4352 | INNER JOIN '.$tableCourse.' c |
||
4353 | ON (c.id = session_course_user.c_id) |
||
4354 | WHERE |
||
4355 | session_course_user.c_id = '.$courseId.' AND |
||
4356 | stats_login.login_course_date IS NULL |
||
4357 | GROUP BY session_course_user.user_id'; |
||
4358 | } |
||
4359 | } else { |
||
4360 | $since = (int) $since; |
||
4361 | if (empty($session_id)) { |
||
4362 | $inner = 'INNER JOIN '.$table_course_rel_user.' course_user |
||
4363 | ON course_user.user_id = stats_login.user_id AND course_user.c_id = c.id '; |
||
4364 | } else { |
||
4365 | $inner = 'INNER JOIN '.$tbl_session_course_user.' session_course_user |
||
4366 | ON |
||
4367 | c.id = session_course_user.c_id AND |
||
4368 | session_course_user.session_id = '.$session_id.' AND |
||
4369 | session_course_user.user_id = stats_login.user_id '; |
||
4370 | } |
||
4371 | |||
4372 | $sql = 'SELECT |
||
4373 | stats_login.user_id, |
||
4374 | MAX(login_course_date) max_date |
||
4375 | FROM '.$tbl_track_login.' stats_login |
||
4376 | INNER JOIN '.$tableCourse.' c |
||
4377 | ON (c.id = stats_login.c_id) |
||
4378 | '.$inner.' |
||
4379 | WHERE c.id = '.$courseId.' |
||
4380 | GROUP BY stats_login.user_id |
||
4381 | HAVING DATE_SUB("'.$now.'", INTERVAL '.$since.' DAY) > max_date '; |
||
4382 | } |
||
4383 | |||
4384 | $rs = Database::query($sql); |
||
4385 | |||
4386 | $allow = 'true' === api_get_plugin_setting('pausetraining', 'tool_enable'); |
||
4387 | $allowPauseFormation = 'true' === api_get_plugin_setting('pausetraining', 'allow_users_to_edit_pause_formation'); |
||
4388 | |||
4389 | $extraFieldValue = new ExtraFieldValue('user'); |
||
4390 | $users = []; |
||
4391 | while ($user = Database::fetch_array($rs)) { |
||
4392 | $userId = $user['user_id']; |
||
4393 | |||
4394 | if ($allow && $allowPauseFormation) { |
||
4395 | $pause = $extraFieldValue->get_values_by_handler_and_field_variable($userId, 'pause_formation'); |
||
4396 | if (!empty($pause) && isset($pause['value']) && 1 == $pause['value']) { |
||
4397 | // Skip user because he paused his formation. |
||
4398 | continue; |
||
4399 | } |
||
4400 | } |
||
4401 | |||
4402 | $users[] = $userId; |
||
4403 | } |
||
4404 | |||
4405 | return $users; |
||
4406 | } |
||
4407 | |||
4408 | /** |
||
4409 | * get count clicks about tools most used by course. |
||
4410 | * |
||
4411 | * @param int $courseId |
||
4412 | * @param int Session id (optional), |
||
4413 | * if param $session_id is null(default) it'll return results |
||
4414 | * including sessions, 0 = session is not filtered |
||
4415 | * |
||
4416 | * @return array tools data |
||
4417 | */ |
||
4418 | public static function get_tools_most_used_by_course($courseId, $session_id = null) |
||
4419 | { |
||
4420 | $courseId = (int) $courseId; |
||
4421 | $data = []; |
||
4422 | $TABLETRACK_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS); |
||
4423 | $condition_session = ''; |
||
4424 | if (isset($session_id)) { |
||
4425 | $session_id = (int) $session_id; |
||
4426 | $condition_session = ' AND session_id = '.$session_id; |
||
4427 | } |
||
4428 | $sql = "SELECT |
||
4429 | access_tool, |
||
4430 | COUNT(DISTINCT access_user_id), |
||
4431 | count(access_tool) as count_access_tool |
||
4432 | FROM $TABLETRACK_ACCESS |
||
4433 | WHERE |
||
4434 | access_tool IS NOT NULL AND |
||
4435 | access_tool != '' AND |
||
4436 | c_id = '$courseId' |
||
4437 | $condition_session |
||
4438 | GROUP BY access_tool |
||
4439 | ORDER BY count_access_tool DESC |
||
4440 | LIMIT 0, 3"; |
||
4441 | $rs = Database::query($sql); |
||
4442 | if (Database::num_rows($rs) > 0) { |
||
4443 | while ($row = Database::fetch_array($rs)) { |
||
4444 | $data[] = $row; |
||
4445 | } |
||
4446 | } |
||
4447 | |||
4448 | return $data; |
||
4449 | } |
||
4450 | |||
4451 | /** |
||
4452 | * get documents most downloaded by course. |
||
4453 | * |
||
4454 | * @param string Course code |
||
4455 | * @param int Session id (optional), |
||
4456 | * if param $session_id is null(default) it'll return results including |
||
4457 | * sessions, 0 = session is not filtered |
||
4458 | * @param int Limit (optional, default = 0, 0 = without limit) |
||
4459 | * |
||
4460 | * @return array documents downloaded |
||
4461 | */ |
||
4462 | public static function get_documents_most_downloaded_by_course( |
||
4463 | $course_code, |
||
4464 | $session_id = 0, |
||
4465 | $limit = 0 |
||
4466 | ) { |
||
4467 | $courseId = api_get_course_int_id($course_code); |
||
4468 | $data = []; |
||
4469 | |||
4470 | $TABLETRACK_DOWNLOADS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS); |
||
4471 | $tableResourceLink = Database::get_main_table('resource_link'); |
||
4472 | $tableResourceNode = Database::get_main_table('resource_node'); |
||
4473 | $condition_session = ''; |
||
4474 | $session_id = intval($session_id); |
||
4475 | if (!empty($session_id)) { |
||
4476 | $condition_session = ' AND l.session_id = '.$session_id; |
||
4477 | } |
||
4478 | $sql = "SELECT t.resource_link_id as lid, |
||
4479 | n.path as npath, |
||
4480 | n.title as ntitle, |
||
4481 | n.uuid as uuid, |
||
4482 | n.id as nid, |
||
4483 | COUNT(t.down_id) as count_down |
||
4484 | FROM $TABLETRACK_DOWNLOADS t |
||
4485 | INNER JOIN $tableResourceLink l |
||
4486 | ON t.resource_link_id = l.id |
||
4487 | INNER JOIN $tableResourceNode n |
||
4488 | ON l.resource_node_id = n.id |
||
4489 | WHERE l.c_id = $courseId |
||
4490 | $condition_session |
||
4491 | GROUP BY nid |
||
4492 | ORDER BY count_down DESC |
||
4493 | LIMIT 0, $limit"; |
||
4494 | $rs = Database::query($sql); |
||
4495 | |||
4496 | if (Database::num_rows($rs) > 0) { |
||
4497 | while ($row = Database::fetch_array($rs)) { |
||
4498 | $data[] = $row; |
||
4499 | } |
||
4500 | } |
||
4501 | |||
4502 | return $data; |
||
4503 | } |
||
4504 | |||
4505 | /** |
||
4506 | * get links most visited by course. |
||
4507 | * |
||
4508 | * @param string Course code |
||
4509 | * @param int Session id (optional), |
||
4510 | * if param $session_id is null(default) it'll |
||
4511 | * return results including sessions, 0 = session is not filtered |
||
4512 | * |
||
4513 | * @return array links most visited |
||
4514 | */ |
||
4515 | public static function get_links_most_visited_by_course($course_code, $session_id = null) |
||
4516 | { |
||
4517 | $course_code = Database::escape_string($course_code); |
||
4518 | $course_info = api_get_course_info($course_code); |
||
4519 | $courseId = $course_info['real_id']; |
||
4520 | $data = []; |
||
4521 | |||
4522 | $TABLETRACK_LINKS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS); |
||
4523 | $TABLECOURSE_LINKS = Database::get_course_table(TABLE_LINK); |
||
4524 | |||
4525 | $condition_session = ''; |
||
4526 | if (isset($session_id)) { |
||
4527 | $session_id = intval($session_id); |
||
4528 | $condition_session = ' AND sl.session_id = '.$session_id; |
||
4529 | } |
||
4530 | |||
4531 | $sql = "SELECT cl.title, cl.url,count(DISTINCT sl.links_user_id), count(cl.title) as count_visits |
||
4532 | FROM $TABLETRACK_LINKS AS sl, $TABLECOURSE_LINKS AS cl |
||
4533 | WHERE |
||
4534 | sl.links_link_id = cl.iid AND |
||
4535 | sl.c_id = $courseId |
||
4536 | $condition_session |
||
4537 | GROUP BY cl.title, cl.url |
||
4538 | ORDER BY count_visits DESC |
||
4539 | LIMIT 0, 3"; |
||
4540 | $rs = Database::query($sql); |
||
4541 | if (Database::num_rows($rs) > 0) { |
||
4542 | while ($row = Database::fetch_array($rs)) { |
||
4543 | $data[] = $row; |
||
4544 | } |
||
4545 | } |
||
4546 | |||
4547 | return $data; |
||
4548 | } |
||
4549 | |||
4550 | /** |
||
4551 | * Shows the user progress (when clicking in the Progress tab). |
||
4552 | * |
||
4553 | * @param int $user_id |
||
4554 | * @param int $session_id |
||
4555 | * @param string $extra_params |
||
4556 | * @param bool $show_courses |
||
4557 | * @param bool $showAllSessions |
||
4558 | * @param bool $returnArray |
||
4559 | * |
||
4560 | * @return string|array |
||
4561 | * @throws \Doctrine\DBAL\Exception |
||
4562 | * @throws Exception |
||
4563 | */ |
||
4564 | public static function show_user_progress( |
||
4565 | $user_id, |
||
4566 | $session_id = 0, |
||
4567 | $extra_params = '', |
||
4568 | $show_courses = true, |
||
4569 | $showAllSessions = true, |
||
4570 | $returnArray = false |
||
4571 | ) { |
||
4572 | $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE); |
||
4573 | $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION); |
||
4574 | $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER); |
||
4575 | $tbl_access_rel_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); |
||
4576 | $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER); |
||
4577 | $tbl_access_rel_session = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION); |
||
4578 | |||
4579 | $trackingColumns = [ |
||
4580 | 'course_session' => [ |
||
4581 | 'course_title' => true, |
||
4582 | 'published_exercises' => true, |
||
4583 | 'new_exercises' => true, |
||
4584 | 'my_average' => true, |
||
4585 | 'average_exercise_result' => true, |
||
4586 | 'time_spent' => true, |
||
4587 | 'lp_progress' => true, |
||
4588 | 'score' => true, |
||
4589 | 'best_score' => true, |
||
4590 | 'last_connection' => true, |
||
4591 | 'details' => true, |
||
4592 | ], |
||
4593 | ]; |
||
4594 | |||
4595 | $trackingColumnsConfig = api_get_setting('session.tracking_columns', true); |
||
4596 | if (!empty($trackingColumnsConfig)) { |
||
4597 | $trackingColumns = $trackingColumnsConfig; |
||
4598 | } |
||
4599 | |||
4600 | $user_id = (int) $user_id; |
||
4601 | $session_id = (int) $session_id; |
||
4602 | $urlId = -1; |
||
4603 | |||
4604 | $accessUrlUtil = Container::getAccessUrlUtil(); |
||
4605 | if ($accessUrlUtil->isMultiple()) { |
||
4606 | $urlId = $accessUrlUtil->getCurrent()->getId(); |
||
4607 | $sql = "SELECT c.id, c.code, title |
||
4608 | FROM $tbl_course_user cu |
||
4609 | INNER JOIN $tbl_course c |
||
4610 | ON (cu.c_id = c.id) |
||
4611 | INNER JOIN $tbl_access_rel_course a |
||
4612 | ON (a.c_id = c.id) |
||
4613 | WHERE |
||
4614 | cu.user_id = $user_id AND |
||
4615 | relation_type<> ".COURSE_RELATION_TYPE_RRHH." AND |
||
4616 | access_url_id = $urlId |
||
4617 | ORDER BY title"; |
||
4618 | } else { |
||
4619 | $sql = "SELECT c.id, c.code, title |
||
4620 | FROM $tbl_course_user cu |
||
4621 | INNER JOIN $tbl_course c |
||
4622 | ON (cu.c_id = c.id) |
||
4623 | WHERE |
||
4624 | cu.user_id = $user_id AND |
||
4625 | relation_type <> ".COURSE_RELATION_TYPE_RRHH." |
||
4626 | ORDER BY title"; |
||
4627 | } |
||
4628 | |||
4629 | $rs = Database::query($sql); |
||
4630 | $courses = $course_in_session = $temp_course_in_session = []; |
||
4631 | $courseIdList = []; |
||
4632 | while ($row = Database::fetch_assoc($rs)) { |
||
4633 | $courses[$row['id']] = $row['title']; |
||
4634 | $courseIdList[] = $row['id']; |
||
4635 | } |
||
4636 | |||
4637 | $orderBy = ' ORDER BY title '; |
||
4638 | $extraInnerJoin = null; |
||
4639 | |||
4640 | if (SessionManager::orderCourseIsEnabled() && !empty($session_id)) { |
||
4641 | $orderBy = ' ORDER BY s.id, src.position '; |
||
4642 | $tableSessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE); |
||
4643 | $extraInnerJoin = " INNER JOIN $tableSessionRelCourse src |
||
4644 | ON (cu.c_id = src.c_id AND src.session_id = $session_id) "; |
||
4645 | } |
||
4646 | |||
4647 | $sessionCondition = ''; |
||
4648 | if (!empty($session_id)) { |
||
4649 | $sessionCondition = " AND s.id = $session_id"; |
||
4650 | } |
||
4651 | |||
4652 | // Get the list of sessions where the user is subscribed as student |
||
4653 | if ($accessUrlUtil->isMultiple()) { |
||
4654 | $sql = "SELECT DISTINCT c.code, s.id as session_id, s.title |
||
4655 | FROM $tbl_session_course_user cu |
||
4656 | INNER JOIN $tbl_access_rel_session a |
||
4657 | ON (a.session_id = cu.session_id) |
||
4658 | INNER JOIN $tbl_session s |
||
4659 | ON (s.id = a.session_id) |
||
4660 | INNER JOIN $tbl_course c |
||
4661 | ON (c.id = cu.c_id) |
||
4662 | $extraInnerJoin |
||
4663 | WHERE |
||
4664 | cu.user_id = $user_id AND |
||
4665 | access_url_id = $urlId |
||
4666 | $sessionCondition |
||
4667 | $orderBy "; |
||
4668 | } else { |
||
4669 | $sql = "SELECT DISTINCT c.code, s.id as session_id, s.title |
||
4670 | FROM $tbl_session_course_user cu |
||
4671 | INNER JOIN $tbl_session s |
||
4672 | ON (s.id = cu.session_id) |
||
4673 | INNER JOIN $tbl_course c |
||
4674 | ON (c.id = cu.c_id) |
||
4675 | $extraInnerJoin |
||
4676 | WHERE |
||
4677 | cu.user_id = $user_id |
||
4678 | $sessionCondition |
||
4679 | $orderBy "; |
||
4680 | } |
||
4681 | |||
4682 | $rs = Database::query($sql); |
||
4683 | $simple_session_array = []; |
||
4684 | while ($row = Database::fetch_assoc($rs)) { |
||
4685 | $course_info = api_get_course_info($row['code']); |
||
4686 | $temp_course_in_session[$row['session_id']]['course_list'][$course_info['real_id']] = $course_info; |
||
4687 | $temp_course_in_session[$row['session_id']]['title'] = $row['title']; |
||
4688 | $simple_session_array[$row['session_id']] = $row['title']; |
||
4689 | } |
||
4690 | |||
4691 | foreach ($simple_session_array as $my_session_id => $session_title) { |
||
4692 | $course_list = $temp_course_in_session[$my_session_id]['course_list']; |
||
4693 | $my_course_data = []; |
||
4694 | foreach ($course_list as $courseId => $course_data) { |
||
4695 | $my_course_data[$courseId] = $course_data['title']; |
||
4696 | } |
||
4697 | |||
4698 | if (empty($session_id)) { |
||
4699 | $my_course_data = utf8_sort($my_course_data); |
||
4700 | } |
||
4701 | |||
4702 | $final_course_data = []; |
||
4703 | foreach ($my_course_data as $course_id => $value) { |
||
4704 | if (isset($course_list[$course_id])) { |
||
4705 | $final_course_data[$course_id] = $course_list[$course_id]; |
||
4706 | } |
||
4707 | } |
||
4708 | $course_in_session[$my_session_id]['course_list'] = $final_course_data; |
||
4709 | $course_in_session[$my_session_id]['title'] = $session_title; |
||
4710 | } |
||
4711 | |||
4712 | if ($returnArray) { |
||
4713 | $course_in_session[0] = $courseIdList; |
||
4714 | |||
4715 | return $course_in_session; |
||
4716 | } |
||
4717 | |||
4718 | $html = ''; |
||
4719 | // Course list |
||
4720 | if ($show_courses) { |
||
4721 | if (!empty($courses)) { |
||
4722 | $html .= Display::page_subheader( |
||
4723 | Display::getMdiIcon( |
||
4724 | 'book-open-page-variant', |
||
4725 | 'ch-tool-icon', |
||
4726 | null, |
||
4727 | ICON_SIZE_SMALL, |
||
4728 | get_lang('My courses') |
||
4729 | ).' '.get_lang('My courses') |
||
4730 | ); |
||
4731 | |||
4732 | $columns = [ |
||
4733 | 'course_title' => get_lang('Course'), |
||
4734 | 'time_spent' => get_lang('Time spent in the course'), |
||
4735 | 'progress' => get_lang('Progress'), |
||
4736 | 'best_score_in_lp' => get_lang('Best score in learning path'), |
||
4737 | 'best_score_not_in_lp' => get_lang('Best score not in learning path'), |
||
4738 | 'latest_login' => get_lang('Latest login'), |
||
4739 | 'details' => get_lang('Details'), |
||
4740 | ]; |
||
4741 | $availableColumns = []; |
||
4742 | if (isset($trackingColumns['my_progress_courses'])) { |
||
4743 | $availableColumns = $trackingColumns['my_progress_courses']; |
||
4744 | } |
||
4745 | $html .= '<div class="table-responsive">'; |
||
4746 | $html .= '<table class="table table-striped table-hover">'; |
||
4747 | $html .= '<thead><tr>'; |
||
4748 | foreach ($columns as $columnKey => $name) { |
||
4749 | if (!empty($availableColumns)) { |
||
4750 | if (isset($availableColumns[$columnKey]) && false == $availableColumns[$columnKey]) { |
||
4751 | continue; |
||
4752 | } |
||
4753 | } |
||
4754 | $html .= Display::tag('th', $name); |
||
4755 | } |
||
4756 | $html .= '</tr></thead><tbody>'; |
||
4757 | |||
4758 | foreach ($courses as $courseId => $course_title) { |
||
4759 | $course = api_get_course_entity($courseId); |
||
4760 | $courseCode = $course->getCode(); |
||
4761 | |||
4762 | $total_time_login = self::get_time_spent_on_the_course( |
||
4763 | $user_id, |
||
4764 | $courseId |
||
4765 | ); |
||
4766 | $time = api_time_to_hms($total_time_login); |
||
4767 | $progress = self::get_avg_student_progress( |
||
4768 | $user_id, |
||
4769 | $course |
||
4770 | ); |
||
4771 | $bestScore = self::get_avg_student_score( |
||
4772 | $user_id, |
||
4773 | $course, |
||
4774 | [], |
||
4775 | null, |
||
4776 | false, |
||
4777 | false, |
||
4778 | true |
||
4779 | ); |
||
4780 | |||
4781 | /*$exerciseList = ExerciseLib::get_all_exercises( |
||
4782 | $courseInfo, |
||
4783 | 0, |
||
4784 | false, |
||
4785 | null, |
||
4786 | false, |
||
4787 | 1 |
||
4788 | );*/ |
||
4789 | |||
4790 | $qb = Container::getQuizRepository()->findAllByCourse($course, null, null, 1, false); |
||
4791 | /** @var CQuiz[] $exercises */ |
||
4792 | $exercises = $qb->getQuery()->getResult(); |
||
4793 | |||
4794 | $bestScoreAverageNotInLP = 0; |
||
4795 | if (!empty($exercises)) { |
||
4796 | foreach ($exercises as $exerciseData) { |
||
4797 | $results = Event::get_best_exercise_results_by_user( |
||
4798 | $exerciseData->getIid(), |
||
4799 | $courseId, |
||
4800 | 0, |
||
4801 | $user_id |
||
4802 | ); |
||
4803 | $best = 0; |
||
4804 | if (!empty($results)) { |
||
4805 | foreach ($results as $result) { |
||
4806 | if (!empty($result['max_score'])) { |
||
4807 | $score = $result['score'] / $result['max_score']; |
||
4808 | if ($score > $best) { |
||
4809 | $best = $score; |
||
4810 | } |
||
4811 | } |
||
4812 | } |
||
4813 | } |
||
4814 | $bestScoreAverageNotInLP += $best; |
||
4815 | } |
||
4816 | $bestScoreAverageNotInLP = round($bestScoreAverageNotInLP / count($exercises) * 100, 2); |
||
4817 | } |
||
4818 | |||
4819 | $last_connection = self::get_last_connection_date_on_the_course( |
||
4820 | $user_id, |
||
4821 | ['real_id' => $courseId] |
||
4822 | ); |
||
4823 | |||
4824 | if (is_null($progress) || empty($progress)) { |
||
4825 | $progress = '0%'; |
||
4826 | } else { |
||
4827 | $progress = $progress.'%'; |
||
4828 | } |
||
4829 | |||
4830 | if (isset($_GET['course']) && |
||
4831 | $courseCode == $_GET['course'] && |
||
4832 | empty($_GET['session_id']) |
||
4833 | ) { |
||
4834 | $html .= '<tr class="row_odd" style="background-color:#FBF09D">'; |
||
4835 | } else { |
||
4836 | $html .= '<tr class="row_even">'; |
||
4837 | } |
||
4838 | $url = api_get_course_url($courseId, $session_id); |
||
4839 | $course_url = Display::url($course_title, $url, ['target' => SESSION_LINK_TARGET]); |
||
4840 | if (empty($bestScore)) { |
||
4841 | $bestScoreResult = '-'; |
||
4842 | } else { |
||
4843 | $bestScoreResult = $bestScore.'%'; |
||
4844 | } |
||
4845 | if (empty($bestScoreAverageNotInLP)) { |
||
4846 | $bestScoreNotInLP = '-'; |
||
4847 | } else { |
||
4848 | $bestScoreNotInLP = $bestScoreAverageNotInLP.'%'; |
||
4849 | } |
||
4850 | |||
4851 | $detailsLink = ''; |
||
4852 | if (isset($_GET['course']) && |
||
4853 | $courseCode == $_GET['course'] && |
||
4854 | empty($_GET['session_id']) |
||
4855 | ) { |
||
4856 | $detailsLink .= '<a href="#course_session_header">'; |
||
4857 | $detailsLink .= Display::getMdiIcon( |
||
4858 | 'fast-forward-outline', |
||
4859 | 'ch-tool-icon', |
||
4860 | null, |
||
4861 | ICON_SIZE_SMALL, |
||
4862 | get_lang('Details') |
||
4863 | ); |
||
4864 | $detailsLink .= '</a>'; |
||
4865 | } else { |
||
4866 | $detailsLink .= '<a href="'.api_get_self().'?course='.$courseCode.$extra_params.'#course_session_header">'; |
||
4867 | $detailsLink .= Display::getMdiIcon( |
||
4868 | 'fast-forward-outline', |
||
4869 | 'ch-tool-icon', |
||
4870 | null, |
||
4871 | ICON_SIZE_SMALL, |
||
4872 | get_lang('Details') |
||
4873 | ); |
||
4874 | $detailsLink .= '</a>'; |
||
4875 | } |
||
4876 | |||
4877 | $result = [ |
||
4878 | 'course_title' => $course_url, |
||
4879 | 'time_spent' => $time, |
||
4880 | 'progress' => $progress, |
||
4881 | 'best_score_in_lp' => $bestScoreResult, |
||
4882 | 'best_score_not_in_lp' => $bestScoreNotInLP, |
||
4883 | 'latest_login' => $last_connection, |
||
4884 | 'details' => $detailsLink, |
||
4885 | ]; |
||
4886 | |||
4887 | foreach ($result as $columnKey => $data) { |
||
4888 | if (!empty($availableColumns)) { |
||
4889 | if (isset($availableColumns[$columnKey]) && false == $availableColumns[$columnKey]) { |
||
4890 | continue; |
||
4891 | } |
||
4892 | } |
||
4893 | $html .= '<td>'.$data.'</td>'; |
||
4894 | } |
||
4895 | |||
4896 | $html .= '</tr>'; |
||
4897 | } |
||
4898 | $html .= '</tbody></table>'; |
||
4899 | $html .= '</div>'; |
||
4900 | } |
||
4901 | } |
||
4902 | |||
4903 | // Session list |
||
4904 | if (!empty($course_in_session)) { |
||
4905 | $main_session_graph = ''; |
||
4906 | // Load graphics only when calling to an specific session |
||
4907 | $all_exercise_graph_name_list = []; |
||
4908 | $my_results = []; |
||
4909 | $all_exercise_graph_list = []; |
||
4910 | $all_exercise_start_time = []; |
||
4911 | foreach ($course_in_session as $my_session_id => $session_data) { |
||
4912 | $course_list = $session_data['course_list']; |
||
4913 | $user_count = count(SessionManager::get_users_by_session($my_session_id)); |
||
4914 | $exercise_graph_name_list = []; |
||
4915 | $exercise_graph_list = []; |
||
4916 | |||
4917 | foreach ($course_list as $course_data) { |
||
4918 | $course = api_get_course_entity($course_data['real_id']); |
||
4919 | $courseId = $course->getId(); |
||
4920 | /*$exercise_list = ExerciseLib::get_all_exercises( |
||
4921 | $course_data, |
||
4922 | $my_session_id, |
||
4923 | false, |
||
4924 | null, |
||
4925 | false, |
||
4926 | 1 |
||
4927 | );*/ |
||
4928 | |||
4929 | $qb = Container::getQuizRepository()->findAllByCourse($course, null, null, 1, false); |
||
4930 | /** @var CQuiz[] $exercises */ |
||
4931 | $exercises = $qb->getQuery()->getResult(); |
||
4932 | $countExercises = count($exercises); |
||
4933 | foreach ($exercises as $exercise_data) { |
||
4934 | //$exercise_obj = new Exercise($course_data['real_id']); |
||
4935 | //$exercise_obj->read($exercise_data['id']); |
||
4936 | // Exercise is not necessary to be visible to show results check the result_disable configuration instead |
||
4937 | //$visible_return = $exercise_obj->is_visible(); |
||
4938 | $disabled = $exercise_data->getResultsDisabled(); |
||
4939 | $exerciseId = $exercise_data->getIid(); |
||
4940 | if (0 == $disabled || 2 == $disabled) { |
||
4941 | $best_average = (int) |
||
4942 | ExerciseLib::get_best_average_score_by_exercise( |
||
4943 | $exerciseId, |
||
4944 | $courseId, |
||
4945 | $my_session_id, |
||
4946 | $user_count |
||
4947 | ) |
||
4948 | ; |
||
4949 | |||
4950 | $exercise_graph_list[] = $best_average; |
||
4951 | $all_exercise_graph_list[] = $best_average; |
||
4952 | |||
4953 | $user_result_data = ExerciseLib::get_best_attempt_by_user( |
||
4954 | api_get_user_id(), |
||
4955 | $exerciseId, |
||
4956 | $courseId, |
||
4957 | $my_session_id |
||
4958 | ); |
||
4959 | |||
4960 | $score = 0; |
||
4961 | if (!empty($user_result_data['max_score']) && 0 != intval($user_result_data['max_score'])) { |
||
4962 | $score = intval($user_result_data['score'] / $user_result_data['max_score'] * 100); |
||
4963 | } |
||
4964 | $start = $exercise_data->getStartTime() ? $exercise_data->getStartTime()->getTimestamp() : null; |
||
4965 | $time = null !== $start ? $start : 0; |
||
4966 | $all_exercise_start_time[] = $time; |
||
4967 | $my_results[] = $score; |
||
4968 | $exerciseTitle = $exercise_data->getTitle(); |
||
4969 | if ($countExercises <= 10) { |
||
4970 | $title = cut($course_data['title'], 30)." \n ".cut($exerciseTitle, 30); |
||
4971 | $exercise_graph_name_list[] = $title; |
||
4972 | $all_exercise_graph_name_list[] = $title; |
||
4973 | } else { |
||
4974 | // if there are more than 10 results, space becomes difficult to find, |
||
4975 | // so only show the title of the exercise, not the tool |
||
4976 | $title = cut($exerciseTitle, 30); |
||
4977 | $exercise_graph_name_list[] = $title; |
||
4978 | $all_exercise_graph_name_list[] = $title; |
||
4979 | } |
||
4980 | } |
||
4981 | } |
||
4982 | } |
||
4983 | } |
||
4984 | |||
4985 | // Complete graph |
||
4986 | if (!empty($my_results) && !empty($all_exercise_graph_list)) { |
||
4987 | asort($all_exercise_start_time); |
||
4988 | |||
4989 | //Fix exams order |
||
4990 | $final_all_exercise_graph_name_list = []; |
||
4991 | $my_results_final = []; |
||
4992 | $final_all_exercise_graph_list = []; |
||
4993 | |||
4994 | foreach ($all_exercise_start_time as $key => $time) { |
||
4995 | $label_time = ''; |
||
4996 | if (!empty($time)) { |
||
4997 | $label_time = date('d-m-y', $time); |
||
4998 | } |
||
4999 | $final_all_exercise_graph_name_list[] = $all_exercise_graph_name_list[$key].' '.$label_time; |
||
5000 | $my_results_final[] = $my_results[$key]; |
||
5001 | $final_all_exercise_graph_list[] = $all_exercise_graph_list[$key]; |
||
5002 | } |
||
5003 | $main_session_graph = self::generate_session_exercise_graph( |
||
5004 | $final_all_exercise_graph_name_list, |
||
5005 | $my_results_final, |
||
5006 | $final_all_exercise_graph_list |
||
5007 | ); |
||
5008 | } |
||
5009 | |||
5010 | $sessionIcon = Display::getMdiIcon( |
||
5011 | 'google-classroom', |
||
5012 | 'ch-tool-icon', |
||
5013 | null, |
||
5014 | ICON_SIZE_SMALL, |
||
5015 | get_lang('Course sessions') |
||
5016 | ); |
||
5017 | |||
5018 | $anchor = Display::url('', '', ['name' => 'course_session_header']); |
||
5019 | $html .= $anchor.Display::page_subheader( |
||
5020 | $sessionIcon.' '.get_lang('Course sessions') |
||
5021 | ); |
||
5022 | |||
5023 | $html .= '<div class="table-responsive">'; |
||
5024 | $html .= '<table class="table table-striped table-hover">'; |
||
5025 | $html .= '<thead>'; |
||
5026 | $html .= '<tr> |
||
5027 | '.Display::tag('th', get_lang('Session'), ['width' => '300px']).' |
||
5028 | '.Display::tag('th', get_lang('Tests available'), ['width' => '300px']).' |
||
5029 | '.Display::tag('th', get_lang('New exercises')).' |
||
5030 | '.Display::tag('th', get_lang('Average exercise result')).' |
||
5031 | '.Display::tag('th', get_lang('Details')).' |
||
5032 | </tr>'; |
||
5033 | $html .= '</thead>'; |
||
5034 | $html .= '<tbody>'; |
||
5035 | |||
5036 | $session = api_get_session_entity($my_session_id); |
||
5037 | |||
5038 | foreach ($course_in_session as $my_session_id => $session_data) { |
||
5039 | $course_list = $session_data['course_list']; |
||
5040 | $session_name = $session_data['title']; |
||
5041 | if (false == $showAllSessions) { |
||
5042 | if (isset($session_id) && !empty($session_id)) { |
||
5043 | if ($session_id != $my_session_id) { |
||
5044 | continue; |
||
5045 | } |
||
5046 | } |
||
5047 | } |
||
5048 | |||
5049 | $all_exercises = 0; |
||
5050 | $all_unanswered_exercises_by_user = 0; |
||
5051 | $all_average = 0; |
||
5052 | $stats_array = []; |
||
5053 | |||
5054 | foreach ($course_list as $course_data) { |
||
5055 | $courseId = $course_data['real_id']; |
||
5056 | $course = api_get_course_entity($courseId); |
||
5057 | |||
5058 | // All exercises in the course @todo change for a real count |
||
5059 | //$exercises = ExerciseLib::get_all_exercises($course_data, $my_session_id); |
||
5060 | |||
5061 | $qb = Container::getQuizRepository()->findAllByCourse($course, $session, null, 2); |
||
5062 | |||
5063 | /** @var CQuiz[] $exercises */ |
||
5064 | $exercises = $qb->getQuery()->getResult(); |
||
5065 | $count_exercises = count($exercises); |
||
5066 | |||
5067 | // Count of user results |
||
5068 | $done_exercises = null; |
||
5069 | $answered_exercises = 0; |
||
5070 | if (!empty($exercises)) { |
||
5071 | foreach ($exercises as $exercise_item) { |
||
5072 | $attempts = Event::count_exercise_attempts_by_user( |
||
5073 | api_get_user_id(), |
||
5074 | $exercise_item->getIid(), |
||
5075 | $courseId, |
||
5076 | $my_session_id |
||
5077 | ); |
||
5078 | if ($attempts > 1) { |
||
5079 | $answered_exercises++; |
||
5080 | } |
||
5081 | } |
||
5082 | } |
||
5083 | |||
5084 | // Average |
||
5085 | $average = ExerciseLib::get_average_score_by_course( |
||
5086 | $courseId, |
||
5087 | $my_session_id |
||
5088 | ); |
||
5089 | $all_exercises += $count_exercises; |
||
5090 | $all_unanswered_exercises_by_user += $count_exercises - $answered_exercises; |
||
5091 | $all_average += $average; |
||
5092 | } |
||
5093 | |||
5094 | if (!empty($course_list)) { |
||
5095 | $all_average = $all_average / count($course_list); |
||
5096 | } |
||
5097 | |||
5098 | if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) { |
||
5099 | $html .= '<tr style="background-color:#FBF09D">'; |
||
5100 | } else { |
||
5101 | $html .= '<tr>'; |
||
5102 | } |
||
5103 | $url = api_get_path(WEB_CODE_PATH)."session/index.php?session_id={$my_session_id}"; |
||
5104 | |||
5105 | $html .= Display::tag('td', Display::url($session_title, $url, ['target' => SESSION_LINK_TARGET])); |
||
5106 | $html .= Display::tag('td', $all_exercises); |
||
5107 | $html .= Display::tag('td', $all_unanswered_exercises_by_user); |
||
5108 | $html .= Display::tag('td', ExerciseLib::convert_to_percentage($all_average)); |
||
5109 | |||
5110 | if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) { |
||
5111 | $icon = Display::url( |
||
5112 | Display::getMdiIcon( |
||
5113 | 'fast-forward-outline', |
||
5114 | 'ch-tool-icon', |
||
5115 | null, |
||
5116 | ICON_SIZE_SMALL, |
||
5117 | get_lang('Details') |
||
5118 | ), |
||
5119 | api_get_self().'?session_id='.$my_session_id.'#course_session_list' |
||
5120 | ); |
||
5121 | } else { |
||
5122 | $icon = Display::url( |
||
5123 | Display::getMdiIcon( |
||
5124 | 'fast-forward-outline', |
||
5125 | 'ch-tool-icon', |
||
5126 | null, |
||
5127 | ICON_SIZE_SMALL, |
||
5128 | get_lang('Details') |
||
5129 | ), |
||
5130 | api_get_self().'?session_id='.$my_session_id.'#course_session_list' |
||
5131 | ); |
||
5132 | } |
||
5133 | $html .= Display::tag('td', $icon); |
||
5134 | $html .= '</tr>'; |
||
5135 | } |
||
5136 | $html .= '</tbody>'; |
||
5137 | $html .= '</table></div><br />'; |
||
5138 | $html .= Display::div( |
||
5139 | $main_session_graph, |
||
5140 | [ |
||
5141 | 'id' => 'session_graph', |
||
5142 | 'class' => 'chart-session', |
||
5143 | 'style' => 'position:relative; text-align: center;', |
||
5144 | ] |
||
5145 | ); |
||
5146 | |||
5147 | // Checking selected session. |
||
5148 | if (isset($_GET['session_id'])) { |
||
5149 | $session_id_from_get = (int) $_GET['session_id']; |
||
5150 | $session_data = $course_in_session[$session_id_from_get]; |
||
5151 | $course_list = $session_data['course_list']; |
||
5152 | |||
5153 | $html .= '<a name= "course_session_list"></a>'; |
||
5154 | $html .= Display::tag('h3', $session_data['title'].' - '.get_lang('Course list')); |
||
5155 | |||
5156 | $html .= '<div class="table-responsive">'; |
||
5157 | $html .= '<table class="table table-hover table-striped">'; |
||
5158 | |||
5159 | $columnHeaders = [ |
||
5160 | 'course_title' => [ |
||
5161 | get_lang('Course'), |
||
5162 | ['width' => '300px'], |
||
5163 | ], |
||
5164 | 'published_exercises' => [ |
||
5165 | get_lang('Tests available'), |
||
5166 | ], |
||
5167 | 'new_exercises' => [ |
||
5168 | get_lang('New exercises'), |
||
5169 | ], |
||
5170 | 'my_average' => [ |
||
5171 | get_lang('My average'), |
||
5172 | ], |
||
5173 | 'average_exercise_result' => [ |
||
5174 | get_lang('Average exercise result'), |
||
5175 | ], |
||
5176 | 'time_spent' => [ |
||
5177 | get_lang('Time spent in the course'), |
||
5178 | ], |
||
5179 | 'lp_progress' => [ |
||
5180 | get_lang('Learning path progress'), |
||
5181 | ], |
||
5182 | 'score' => [ |
||
5183 | get_lang('Score'). |
||
5184 | Display::getMdiIcon( |
||
5185 | ActionIcon::INFORMATION, |
||
5186 | 'ch-tool-icon', |
||
5187 | null, |
||
5188 | ICON_SIZE_SMALL, |
||
5189 | get_lang('Average of tests in Learning Paths') |
||
5190 | ), |
||
5191 | ], |
||
5192 | 'best_score' => [ |
||
5193 | get_lang('Best score'), |
||
5194 | ], |
||
5195 | 'last_connection' => [ |
||
5196 | get_lang('Latest login'), |
||
5197 | ], |
||
5198 | 'details' => [ |
||
5199 | get_lang('Details'), |
||
5200 | ], |
||
5201 | ]; |
||
5202 | |||
5203 | $html .= '<thead><tr>'; |
||
5204 | foreach ($columnHeaders as $key => $columnSetting) { |
||
5205 | if (isset($trackingColumns['course_session']) && |
||
5206 | in_array($key, $trackingColumns['course_session']) && |
||
5207 | $trackingColumns['course_session'][$key] |
||
5208 | ) { |
||
5209 | $settings = isset($columnSetting[1]) ? $columnSetting[1] : []; |
||
5210 | $html .= Display::tag( |
||
5211 | 'th', |
||
5212 | $columnSetting[0], |
||
5213 | $settings |
||
5214 | ); |
||
5215 | } |
||
5216 | } |
||
5217 | |||
5218 | $html .= '</tr> |
||
5219 | </thead> |
||
5220 | <tbody>'; |
||
5221 | |||
5222 | foreach ($course_list as $course_data) { |
||
5223 | $course_code = $course_data['code']; |
||
5224 | $course_title = $course_data['title']; |
||
5225 | $courseId = $course_data['real_id']; |
||
5226 | $course = api_get_course_entity($courseId); |
||
5227 | $session = api_get_session_entity($session_id_from_get); |
||
5228 | |||
5229 | $qb = Container::getQuizRepository()->findAllByCourse($course, $session, null, 2); |
||
5230 | |||
5231 | /** @var CQuiz[] $exercises */ |
||
5232 | $exercises = $qb->getQuery()->getResult(); |
||
5233 | $count_exercises = 0; |
||
5234 | if (!empty($exercises)) { |
||
5235 | $count_exercises = count($exercises); |
||
5236 | } |
||
5237 | |||
5238 | $answered_exercises = 0; |
||
5239 | foreach ($exercises as $exercise_item) { |
||
5240 | $attempts = Event::count_exercise_attempts_by_user( |
||
5241 | api_get_user_id(), |
||
5242 | $exercise_item->getIid(), |
||
5243 | $courseId, |
||
5244 | $session_id_from_get |
||
5245 | ); |
||
5246 | if ($attempts > 1) { |
||
5247 | $answered_exercises++; |
||
5248 | } |
||
5249 | } |
||
5250 | |||
5251 | $unanswered_exercises = $count_exercises - $answered_exercises; |
||
5252 | |||
5253 | // Average |
||
5254 | $average = ExerciseLib::get_average_score_by_course( |
||
5255 | $courseId, |
||
5256 | $session_id_from_get |
||
5257 | ); |
||
5258 | $my_average = ExerciseLib::get_average_score_by_course_by_user( |
||
5259 | api_get_user_id(), |
||
5260 | $courseId, |
||
5261 | $session_id_from_get |
||
5262 | ); |
||
5263 | |||
5264 | $bestScore = self::get_avg_student_score( |
||
5265 | $user_id, |
||
5266 | $course, |
||
5267 | [], |
||
5268 | $session, |
||
5269 | false, |
||
5270 | false, |
||
5271 | true |
||
5272 | ); |
||
5273 | |||
5274 | $stats_array[$course_code] = [ |
||
5275 | 'exercises' => $count_exercises, |
||
5276 | 'unanswered_exercises_by_user' => $unanswered_exercises, |
||
5277 | 'done_exercises' => $done_exercises, |
||
5278 | 'average' => $average, |
||
5279 | 'my_average' => $my_average, |
||
5280 | 'best_score' => $bestScore, |
||
5281 | ]; |
||
5282 | |||
5283 | $last_connection = self::get_last_connection_date_on_the_course( |
||
5284 | $user_id, |
||
5285 | $course_data, |
||
5286 | $session_id_from_get |
||
5287 | ); |
||
5288 | |||
5289 | $progress = self::get_avg_student_progress( |
||
5290 | $user_id, |
||
5291 | $course, |
||
5292 | [], |
||
5293 | $session |
||
5294 | ); |
||
5295 | |||
5296 | $total_time_login = self::get_time_spent_on_the_course( |
||
5297 | $user_id, |
||
5298 | $courseId, |
||
5299 | $session_id_from_get |
||
5300 | ); |
||
5301 | $time = api_time_to_hms($total_time_login); |
||
5302 | |||
5303 | $percentage_score = self::get_avg_student_score( |
||
5304 | $user_id, |
||
5305 | $course, |
||
5306 | [], |
||
5307 | $session |
||
5308 | ); |
||
5309 | $courseCodeFromGet = isset($_GET['course']) ? $_GET['course'] : null; |
||
5310 | |||
5311 | if ($course_code == $courseCodeFromGet && $_GET['session_id'] == $session_id_from_get) { |
||
5312 | $html .= '<tr class="row_odd" style="background-color:#FBF09D" >'; |
||
5313 | } else { |
||
5314 | $html .= '<tr class="row_even">'; |
||
5315 | } |
||
5316 | |||
5317 | $url = api_get_course_url($courseId, $session_id_from_get); |
||
5318 | $course_url = Display::url( |
||
5319 | $course_title, |
||
5320 | $url, |
||
5321 | ['target' => SESSION_LINK_TARGET] |
||
5322 | ); |
||
5323 | |||
5324 | if (is_numeric($progress)) { |
||
5325 | $progress = $progress.'%'; |
||
5326 | } else { |
||
5327 | $progress = '0%'; |
||
5328 | } |
||
5329 | if (is_numeric($percentage_score)) { |
||
5330 | $percentage_score = $percentage_score.'%'; |
||
5331 | } else { |
||
5332 | $percentage_score = '0%'; |
||
5333 | } |
||
5334 | |||
5335 | if (is_numeric($stats_array[$course_code]['best_score'])) { |
||
5336 | $bestScore = $stats_array[$course_code]['best_score'].'%'; |
||
5337 | } else { |
||
5338 | $bestScore = '-'; |
||
5339 | } |
||
5340 | |||
5341 | if (empty($last_connection) || is_bool($last_connection)) { |
||
5342 | $last_connection = ''; |
||
5343 | } |
||
5344 | |||
5345 | if ($course_code == $courseCodeFromGet && |
||
5346 | $_GET['session_id'] == $session_id_from_get |
||
5347 | ) { |
||
5348 | $details = Display::url( |
||
5349 | Display::getMdiIcon('fast-forward-outline', 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Details')), |
||
5350 | '#course_session_data' |
||
5351 | ); |
||
5352 | } else { |
||
5353 | $url = api_get_self(). |
||
5354 | '?course='.$course_code.'&session_id='.$session_id_from_get.$extra_params.'#course_session_data'; |
||
5355 | $details = Display::url( |
||
5356 | Display::getMdiIcon('fast-forward-outline', 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Details') |
||
5357 | ), |
||
5358 | $url |
||
5359 | ); |
||
5360 | } |
||
5361 | |||
5362 | $data = [ |
||
5363 | 'course_title' => $course_url, |
||
5364 | 'published_exercises' => $stats_array[$course_code]['exercises'], // exercise available |
||
5365 | 'new_exercises' => $stats_array[$course_code]['unanswered_exercises_by_user'], |
||
5366 | 'my_average' => ExerciseLib::convert_to_percentage($stats_array[$course_code]['my_average']), |
||
5367 | 'average_exercise_result' => 0 == $stats_array[$course_code]['average'] ? '-' : '('.ExerciseLib::convert_to_percentage($stats_array[$course_code]['average']).')', |
||
5368 | 'time_spent' => $time, |
||
5369 | 'lp_progress' => $progress, |
||
5370 | 'score' => $percentage_score, |
||
5371 | 'best_score' => $bestScore, |
||
5372 | 'last_connection' => $last_connection, |
||
5373 | 'details' => $details, |
||
5374 | ]; |
||
5375 | |||
5376 | foreach ($data as $key => $value) { |
||
5377 | if (in_array($key, $trackingColumns['course_session']) |
||
5378 | && $trackingColumns['course_session'][$key] |
||
5379 | ) { |
||
5380 | $html .= Display::tag('td', $value); |
||
5381 | } |
||
5382 | } |
||
5383 | $html .= '</tr>'; |
||
5384 | } |
||
5385 | $html .= '</tbody></table></div>'; |
||
5386 | } |
||
5387 | } |
||
5388 | |||
5389 | $pluginCalendar = 'true' === api_get_plugin_setting('learning_calendar', 'enabled'); |
||
5390 | if ($pluginCalendar) { |
||
5391 | $course_in_session[0] = $courseIdList; |
||
5392 | $plugin = LearningCalendarPlugin::create(); |
||
5393 | $html .= $plugin->getUserStatsPanel($user_id, $course_in_session); |
||
5394 | } |
||
5395 | |||
5396 | return $html; |
||
5397 | } |
||
5398 | |||
5399 | /** |
||
5400 | * Shows the user detail progress (when clicking in the details link). |
||
5401 | * |
||
5402 | * @param int $userId |
||
5403 | * @param int $courseId |
||
5404 | * @param int $sessionId |
||
5405 | * @param bool $showDiagram |
||
5406 | * |
||
5407 | * @return string html code |
||
5408 | */ |
||
5409 | public static function show_course_detail($userId, $courseId, $sessionId = 0, $showDiagram = false) |
||
5410 | { |
||
5411 | $html = ''; |
||
5412 | $courseId = (int) $courseId; |
||
5413 | |||
5414 | if (empty($courseId)) { |
||
5415 | return ''; |
||
5416 | } |
||
5417 | $userId = (int) $userId; |
||
5418 | $sessionId = (int) $sessionId; |
||
5419 | $course = api_get_course_entity($courseId); |
||
5420 | if (null === $course) { |
||
5421 | return ''; |
||
5422 | } |
||
5423 | $courseCode = $course->getCode(); |
||
5424 | |||
5425 | $html .= '<a name="course_session_data"></a>'; |
||
5426 | $html .= Display::page_subheader($course->getTitle()); |
||
5427 | |||
5428 | if ($showDiagram && !empty($sessionId)) { |
||
5429 | $visibility = api_get_session_visibility($sessionId); |
||
5430 | if (SESSION_AVAILABLE === $visibility) { |
||
5431 | $html .= Display::page_subheader2($course->getTitle()); |
||
5432 | } |
||
5433 | } |
||
5434 | |||
5435 | $html .= '<div class="table-responsive">'; |
||
5436 | $html .= '<table class="table table-striped table-hover">'; |
||
5437 | |||
5438 | // Course details |
||
5439 | $html .= ' |
||
5440 | <thead> |
||
5441 | <tr> |
||
5442 | <th>'.get_lang('Tests').'</th> |
||
5443 | <th>'.get_lang('Attempts').'</th> |
||
5444 | <th>'.get_lang('Best attempt').'</th> |
||
5445 | <th>'.get_lang('Ranking').'</th> |
||
5446 | <th>'.get_lang('Best result in course').'</th> |
||
5447 | <th>'.get_lang('Statistics').' ' |
||
5448 | .Display::getMdiIcon( |
||
5449 | ActionIcon::INFORMATION, |
||
5450 | 'ch-tool-icon', |
||
5451 | null, |
||
5452 | ICON_SIZE_SMALL, |
||
5453 | get_lang('In case of multiple attempts') |
||
5454 | ). |
||
5455 | '</th> |
||
5456 | </tr> |
||
5457 | </thead> |
||
5458 | <tbody>'; |
||
5459 | $session = null; |
||
5460 | if (empty($sessionId)) { |
||
5461 | $user_list = CourseManager::get_user_list_from_course_code( |
||
5462 | $courseCode, |
||
5463 | $sessionId, |
||
5464 | null, |
||
5465 | null, |
||
5466 | STUDENT |
||
5467 | ); |
||
5468 | } else { |
||
5469 | $session = api_get_session_entity($sessionId); |
||
5470 | $user_list = CourseManager::get_user_list_from_course_code( |
||
5471 | $courseCode, |
||
5472 | $sessionId, |
||
5473 | null, |
||
5474 | null, |
||
5475 | 0 |
||
5476 | ); |
||
5477 | } |
||
5478 | |||
5479 | // Show exercise results of invisible exercises? see BT#4091 |
||
5480 | /*$exercise_list = ExerciseLib::get_all_exercises( |
||
5481 | $course_info, |
||
5482 | $session_id, |
||
5483 | false, |
||
5484 | null, |
||
5485 | false, |
||
5486 | 2 |
||
5487 | );*/ |
||
5488 | $qb = Container::getQuizRepository()->findAllByCourse($course, $session, null, 2, false); |
||
5489 | /** @var CQuiz[] $exercises */ |
||
5490 | $exercises = $qb->getQuery()->getResult(); |
||
5491 | |||
5492 | $to_graph_exercise_result = []; |
||
5493 | if (!empty($exercises)) { |
||
5494 | $weighting = $exe_id = 0; |
||
5495 | foreach ($exercises as $exercise) { |
||
5496 | $exerciseId = $exercise->getIid(); |
||
5497 | $exercise_obj = new Exercise($courseId); |
||
5498 | $exercise_obj->read($exerciseId); |
||
5499 | $visible_return = $exercise_obj->is_visible(); |
||
5500 | $score = $weighting = $attempts = 0; |
||
5501 | |||
5502 | // Getting count of attempts by user |
||
5503 | $attempts = Event::count_exercise_attempts_by_user( |
||
5504 | api_get_user_id(), |
||
5505 | $exercise->getIid(), |
||
5506 | $courseId, |
||
5507 | $sessionId |
||
5508 | ); |
||
5509 | |||
5510 | $html .= '<tr class="row_even">'; |
||
5511 | $url = api_get_path(WEB_CODE_PATH). |
||
5512 | "exercise/overview.php?cid={$courseId}&sid=$sessionId&exerciseId={$exerciseId}"; |
||
5513 | |||
5514 | if (true == $visible_return['value']) { |
||
5515 | $exerciseTitle = Display::url( |
||
5516 | $exercise->getTitle(), |
||
5517 | $url, |
||
5518 | ['target' => SESSION_LINK_TARGET] |
||
5519 | ); |
||
5520 | } elseif (-1 == $exercise->getActive()) { |
||
5521 | $exerciseTitle = sprintf(get_lang('%s (deleted)'), $exercise->getTitle()); |
||
5522 | } |
||
5523 | |||
5524 | $html .= Display::tag('td', $exerciseTitle); |
||
5525 | $resultsDisabled = $exercise->getResultsDisabled(); |
||
5526 | |||
5527 | // Exercise configuration show results or show only score |
||
5528 | if (0 == $resultsDisabled || 2 == $resultsDisabled) { |
||
5529 | //For graphics |
||
5530 | $best_exercise_stats = Event::get_best_exercise_results_by_user( |
||
5531 | $exerciseId, |
||
5532 | $courseId, |
||
5533 | $sessionId |
||
5534 | ); |
||
5535 | |||
5536 | $to_graph_exercise_result[$exerciseId] = [ |
||
5537 | 'title' => $exerciseTitle, |
||
5538 | 'data' => $best_exercise_stats, |
||
5539 | ]; |
||
5540 | |||
5541 | $latest_attempt_url = ''; |
||
5542 | $best_score = $position = $percentage_score_result = '-'; |
||
5543 | $graph = $normal_graph = null; |
||
5544 | |||
5545 | // Getting best results |
||
5546 | $best_score_data = ExerciseLib::get_best_attempt_in_course( |
||
5547 | $exerciseId, |
||
5548 | $courseId, |
||
5549 | $sessionId |
||
5550 | ); |
||
5551 | |||
5552 | $best_score = ''; |
||
5553 | if (!empty($best_score_data)) { |
||
5554 | $best_score = ExerciseLib::show_score( |
||
5555 | $best_score_data['score'], |
||
5556 | $best_score_data['max_score'] |
||
5557 | ); |
||
5558 | } |
||
5559 | |||
5560 | if ($attempts > 0) { |
||
5561 | $exercise_stat = ExerciseLib::get_best_attempt_by_user( |
||
5562 | api_get_user_id(), |
||
5563 | $exerciseId, |
||
5564 | $courseId, |
||
5565 | $sessionId |
||
5566 | ); |
||
5567 | if (!empty($exercise_stat)) { |
||
5568 | // Always getting the BEST attempt |
||
5569 | $score = $exercise_stat['score']; |
||
5570 | $weighting = $exercise_stat['max_score']; |
||
5571 | $exe_id = $exercise_stat['exe_id']; |
||
5572 | |||
5573 | $latest_attempt_url .= api_get_path(WEB_CODE_PATH). |
||
5574 | 'exercise/result.php?id='.$exe_id.'&cid='.$courseId.'&show_headers=1&sid='.$sessionId; |
||
5575 | $percentage_score_result = Display::url( |
||
5576 | ExerciseLib::show_score($score, $weighting), |
||
5577 | $latest_attempt_url |
||
5578 | ); |
||
5579 | $my_score = 0; |
||
5580 | if (!empty($weighting) && 0 != intval($weighting)) { |
||
5581 | $my_score = $score / $weighting; |
||
5582 | } |
||
5583 | //@todo this function slows the page |
||
5584 | if (is_int($user_list)) { |
||
5585 | $user_list = [$user_list]; |
||
5586 | } |
||
5587 | $position = ExerciseLib::get_exercise_result_ranking( |
||
5588 | $my_score, |
||
5589 | $exe_id, |
||
5590 | $exerciseId, |
||
5591 | $courseCode, |
||
5592 | $sessionId, |
||
5593 | $user_list |
||
5594 | ); |
||
5595 | |||
5596 | $graph = self::generate_exercise_result_thumbnail_graph( |
||
5597 | $to_graph_exercise_result[$exerciseId] |
||
5598 | ); |
||
5599 | $normal_graph = self::generate_exercise_result_graph( |
||
5600 | $to_graph_exercise_result[$exerciseId] |
||
5601 | ); |
||
5602 | } |
||
5603 | } |
||
5604 | $html .= Display::div( |
||
5605 | $normal_graph, |
||
5606 | [ |
||
5607 | 'id' => 'main_graph_'.$exerciseId, |
||
5608 | 'class' => 'dialog', |
||
5609 | 'style' => 'display:none', |
||
5610 | ] |
||
5611 | ); |
||
5612 | |||
5613 | if (empty($graph)) { |
||
5614 | $graph = '-'; |
||
5615 | } else { |
||
5616 | $graph = Display::url( |
||
5617 | '<img src="'.$graph.'" >', |
||
5618 | $normal_graph, |
||
5619 | [ |
||
5620 | 'id' => $exerciseId, |
||
5621 | 'class' => 'expand-image', |
||
5622 | ] |
||
5623 | ); |
||
5624 | } |
||
5625 | |||
5626 | $html .= Display::tag('td', $attempts); |
||
5627 | $html .= Display::tag('td', $percentage_score_result); |
||
5628 | $html .= Display::tag('td', $position); |
||
5629 | $html .= Display::tag('td', $best_score); |
||
5630 | $html .= Display::tag('td', $graph); |
||
5631 | } else { |
||
5632 | // Exercise configuration NO results |
||
5633 | $html .= Display::tag('td', $attempts); |
||
5634 | $html .= Display::tag('td', '-'); |
||
5635 | $html .= Display::tag('td', '-'); |
||
5636 | $html .= Display::tag('td', '-'); |
||
5637 | $html .= Display::tag('td', '-'); |
||
5638 | } |
||
5639 | $html .= '</tr>'; |
||
5640 | } |
||
5641 | } else { |
||
5642 | $html .= '<tr><td colspan="5">'.get_lang('There is no test for the moment').'</td></tr>'; |
||
5643 | } |
||
5644 | $html .= '</tbody></table></div>'; |
||
5645 | |||
5646 | $columnHeaders = [ |
||
5647 | 'lp' => get_lang('Learning paths'), |
||
5648 | 'time' => get_lang('Time spent'), |
||
5649 | 'progress' => get_lang('Progress'), |
||
5650 | 'score' => get_lang('Score'), |
||
5651 | 'best_score' => get_lang('Best score'), |
||
5652 | 'last_connection' => get_lang('Latest login'), |
||
5653 | ]; |
||
5654 | |||
5655 | $headers = ''; |
||
5656 | $trackingColumns = api_get_setting('session.tracking_columns', true); |
||
5657 | if (isset($trackingColumns['my_progress_lp'])) { |
||
5658 | foreach ($columnHeaders as $key => $value) { |
||
5659 | if (!isset($trackingColumns['my_progress_lp'][$key]) || |
||
5660 | false == $trackingColumns['my_progress_lp'][$key] |
||
5661 | ) { |
||
5662 | unset($columnHeaders[$key]); |
||
5663 | } |
||
5664 | } |
||
5665 | } |
||
5666 | |||
5667 | $columnHeadersKeys = array_keys($columnHeaders); |
||
5668 | foreach ($columnHeaders as $columnName) { |
||
5669 | $headers .= Display::tag( |
||
5670 | 'th', |
||
5671 | $columnName |
||
5672 | ); |
||
5673 | } |
||
5674 | |||
5675 | // LP table results |
||
5676 | $html .= '<div class="table-responsive">'; |
||
5677 | $html .= '<table class="table table-striped table-hover">'; |
||
5678 | $html .= '<thead><tr>'; |
||
5679 | $html .= $headers; |
||
5680 | $html .= '</tr></thead><tbody>'; |
||
5681 | |||
5682 | $list = new LearnpathList( |
||
5683 | api_get_user_id(), |
||
5684 | ['real_id' => $courseId], |
||
5685 | $sessionId, |
||
5686 | 'resource.publishedOn ASC', |
||
5687 | true, |
||
5688 | null, |
||
5689 | true |
||
5690 | ); |
||
5691 | |||
5692 | $lp_list = $list->get_flat_list(); |
||
5693 | |||
5694 | if (!empty($lp_list)) { |
||
5695 | foreach ($lp_list as $lp_id => $learnpath) { |
||
5696 | if (!$learnpath['lp_visibility']) { |
||
5697 | continue; |
||
5698 | } |
||
5699 | |||
5700 | $progress = self::get_avg_student_progress( |
||
5701 | $userId, |
||
5702 | $course, |
||
5703 | [$lp_id], |
||
5704 | $session |
||
5705 | ); |
||
5706 | $last_connection_in_lp = self::get_last_connection_time_in_lp( |
||
5707 | $userId, |
||
5708 | $course->getCode(), |
||
5709 | $lp_id, |
||
5710 | $sessionId |
||
5711 | ); |
||
5712 | |||
5713 | $time_spent_in_lp = self::get_time_spent_in_lp( |
||
5714 | $userId, |
||
5715 | $course, |
||
5716 | [$lp_id], |
||
5717 | $sessionId |
||
5718 | ); |
||
5719 | $percentage_score = self::get_avg_student_score( |
||
5720 | $userId, |
||
5721 | $course, |
||
5722 | [$lp_id], |
||
5723 | $session |
||
5724 | ); |
||
5725 | |||
5726 | $bestScore = self::get_avg_student_score( |
||
5727 | $userId, |
||
5728 | $course, |
||
5729 | [$lp_id], |
||
5730 | $session, |
||
5731 | false, |
||
5732 | false, |
||
5733 | true |
||
5734 | ); |
||
5735 | |||
5736 | if (is_numeric($progress)) { |
||
5737 | $progress = $progress.'%'; |
||
5738 | } |
||
5739 | if (is_numeric($percentage_score)) { |
||
5740 | $percentage_score = $percentage_score.'%'; |
||
5741 | } else { |
||
5742 | $percentage_score = '0%'; |
||
5743 | } |
||
5744 | |||
5745 | if (is_numeric($bestScore)) { |
||
5746 | $bestScore = $bestScore.'%'; |
||
5747 | } else { |
||
5748 | $bestScore = '-'; |
||
5749 | } |
||
5750 | |||
5751 | $time_spent_in_lp = api_time_to_hms($time_spent_in_lp); |
||
5752 | $last_connection = '-'; |
||
5753 | if (!empty($last_connection_in_lp)) { |
||
5754 | $last_connection = api_convert_and_format_date( |
||
5755 | $last_connection_in_lp, |
||
5756 | DATE_TIME_FORMAT_LONG |
||
5757 | ); |
||
5758 | } |
||
5759 | |||
5760 | $url = api_get_path(WEB_CODE_PATH). |
||
5761 | "lp/lp_controller.php?cid={$courseId}&sid=$sessionId&lp_id=$lp_id&action=view"; |
||
5762 | $html .= '<tr class="row_even">'; |
||
5763 | |||
5764 | if (in_array('lp', $columnHeadersKeys)) { |
||
5765 | if (0 == $learnpath['lp_visibility']) { |
||
5766 | $html .= Display::tag('td', $learnpath['lp_name']); |
||
5767 | } else { |
||
5768 | $html .= Display::tag( |
||
5769 | 'td', |
||
5770 | Display::url( |
||
5771 | $learnpath['lp_name'], |
||
5772 | $url, |
||
5773 | ['target' => SESSION_LINK_TARGET] |
||
5774 | ) |
||
5775 | ); |
||
5776 | } |
||
5777 | } |
||
5778 | |||
5779 | if (in_array('time', $columnHeadersKeys)) { |
||
5780 | $html .= Display::tag( |
||
5781 | 'td', |
||
5782 | $time_spent_in_lp |
||
5783 | ); |
||
5784 | } |
||
5785 | |||
5786 | if (in_array('progress', $columnHeadersKeys)) { |
||
5787 | $html .= Display::tag( |
||
5788 | 'td', |
||
5789 | $progress |
||
5790 | ); |
||
5791 | } |
||
5792 | |||
5793 | if (in_array('score', $columnHeadersKeys)) { |
||
5794 | $html .= Display::tag('td', $percentage_score); |
||
5795 | } |
||
5796 | if (in_array('best_score', $columnHeadersKeys)) { |
||
5797 | $html .= Display::tag('td', $bestScore); |
||
5798 | } |
||
5799 | |||
5800 | if (in_array('last_connection', $columnHeadersKeys)) { |
||
5801 | $html .= Display::tag('td', $last_connection, ['width' => '180px']); |
||
5802 | } |
||
5803 | $html .= '</tr>'; |
||
5804 | } |
||
5805 | } else { |
||
5806 | $html .= '<tr> |
||
5807 | <td colspan="4" align="center"> |
||
5808 | '.get_lang('No learning path').' |
||
5809 | </td> |
||
5810 | </tr>'; |
||
5811 | } |
||
5812 | $html .= '</tbody></table></div>'; |
||
5813 | |||
5814 | $html .= self::displayUserSkills($userId, $courseId, $sessionId); |
||
5815 | |||
5816 | return $html; |
||
5817 | } |
||
5818 | |||
5819 | /** |
||
5820 | * Generates an histogram. |
||
5821 | * |
||
5822 | * @param array $names list of exercise names |
||
5823 | * @param array $my_results my results 0 to 100 |
||
5824 | * @param array $average average scores 0-100 |
||
5825 | * |
||
5826 | * @return string |
||
5827 | */ |
||
5828 | public static function generate_session_exercise_graph($names, $my_results, $average) |
||
5829 | { |
||
5830 | //$html = api_get_js('chartjs/Chart.js'); |
||
5831 | $canvas = Display::tag('canvas', '', ['id' => 'session_graph_chart']); |
||
5832 | $html = Display::tag('div', $canvas, ['style' => 'width:100%']); |
||
5833 | $jsStr = " var data = { |
||
5834 | labels:".json_encode($names).", |
||
5835 | datasets: [ |
||
5836 | { |
||
5837 | label: '".get_lang('My results')."', |
||
5838 | backgroundColor: 'rgb(255, 99, 132)', |
||
5839 | stack: 'Stack1', |
||
5840 | data: ".json_encode($my_results).", |
||
5841 | }, |
||
5842 | { |
||
5843 | label: '".get_lang('Average score')."', |
||
5844 | backgroundColor: 'rgb(75, 192, 192)', |
||
5845 | stack: 'Stack2', |
||
5846 | data: ".json_encode($average).", |
||
5847 | }, |
||
5848 | ], |
||
5849 | }; |
||
5850 | var ctx = document.getElementById('session_graph_chart').getContext('2d'); |
||
5851 | var myBarChart = new Chart(ctx, { |
||
5852 | type: 'bar', |
||
5853 | data: data, |
||
5854 | options: { |
||
5855 | title: { |
||
5856 | display: true, |
||
5857 | text: '".get_lang('TestsInTimeProgressChart')."' |
||
5858 | }, |
||
5859 | tooltips: { |
||
5860 | mode: 'index', |
||
5861 | intersect: false |
||
5862 | }, |
||
5863 | responsive: true, |
||
5864 | scales: { |
||
5865 | yAxes: [{ |
||
5866 | ticks: { |
||
5867 | // Include a dollar sign in the ticks |
||
5868 | callback: function(value, index, values) { |
||
5869 | return value + '%'; |
||
5870 | } |
||
5871 | } |
||
5872 | }] |
||
5873 | } |
||
5874 | } |
||
5875 | });"; |
||
5876 | $html .= Display::tag('script', $jsStr); |
||
5877 | |||
5878 | return $html; |
||
5879 | } |
||
5880 | |||
5881 | /** |
||
5882 | * Returns a thumbnail of the function generate_exercise_result_graph. |
||
5883 | * |
||
5884 | * @param array $attempts |
||
5885 | */ |
||
5886 | public static function generate_exercise_result_thumbnail_graph($attempts) |
||
5887 | { |
||
5888 | //$exercise_title = $attempts['title']; |
||
5889 | $attempts = $attempts['data']; |
||
5890 | $my_exercise_result_array = $exercise_result = []; |
||
5891 | if (empty($attempts)) { |
||
5892 | return null; |
||
5893 | } |
||
5894 | |||
5895 | foreach ($attempts as $attempt) { |
||
5896 | if (api_get_user_id() == $attempt['exe_user_id']) { |
||
5897 | if (0 != $attempt['max_score']) { |
||
5898 | $my_exercise_result_array[] = $attempt['score'] / $attempt['max_score']; |
||
5899 | } |
||
5900 | } else { |
||
5901 | if (0 != $attempt['max_score']) { |
||
5902 | $exercise_result[] = $attempt['score'] / $attempt['max_score']; |
||
5903 | } |
||
5904 | } |
||
5905 | } |
||
5906 | |||
5907 | // Getting best result |
||
5908 | rsort($my_exercise_result_array); |
||
5909 | $my_exercise_result = 0; |
||
5910 | if (isset($my_exercise_result_array[0])) { |
||
5911 | $my_exercise_result = $my_exercise_result_array[0] * 100; |
||
5912 | } |
||
5913 | |||
5914 | $max = 100; |
||
5915 | $pieces = 5; |
||
5916 | $part = round($max / $pieces); |
||
5917 | $x_axis = []; |
||
5918 | $final_array = []; |
||
5919 | $my_final_array = []; |
||
5920 | |||
5921 | for ($i = 1; $i <= $pieces; $i++) { |
||
5922 | $sum = 1; |
||
5923 | if (1 == $i) { |
||
5924 | $sum = 0; |
||
5925 | } |
||
5926 | $min = ($i - 1) * $part + $sum; |
||
5927 | $max = ($i) * $part; |
||
5928 | $x_axis[] = $min." - ".$max; |
||
5929 | $count = 0; |
||
5930 | foreach ($exercise_result as $result) { |
||
5931 | $percentage = $result * 100; |
||
5932 | if ($percentage >= $min && $percentage <= $max) { |
||
5933 | //echo ' is > '; |
||
5934 | $count++; |
||
5935 | } |
||
5936 | } |
||
5937 | //echo '<br />'; |
||
5938 | $final_array[] = $count; |
||
5939 | |||
5940 | if ($my_exercise_result >= $min && $my_exercise_result <= $max) { |
||
5941 | $my_final_array[] = 1; |
||
5942 | } else { |
||
5943 | $my_final_array[] = 0; |
||
5944 | } |
||
5945 | } |
||
5946 | |||
5947 | // Fix to remove the data of the user with my data |
||
5948 | 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
}
![]() |
|||
5949 | if (!empty($my_final_array[$i])) { |
||
5950 | $my_final_array[$i] = $final_array[$i] + 1; //Add my result |
||
5951 | $final_array[$i] = 0; |
||
5952 | } |
||
5953 | } |
||
5954 | |||
5955 | // Dataset definition |
||
5956 | $dataSet = new pData(); |
||
5957 | $dataSet->addPoints($final_array, 'Serie1'); |
||
5958 | $dataSet->addPoints($my_final_array, 'Serie2'); |
||
5959 | $dataSet->normalize(100, "%"); |
||
5960 | $dataSet->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true); |
||
5961 | |||
5962 | // Cache definition |
||
5963 | $cachePath = api_get_path(SYS_ARCHIVE_PATH); |
||
5964 | $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]); |
||
5965 | $chartHash = $myCache->getHash($dataSet); |
||
5966 | if ($myCache->isInCache($chartHash)) { |
||
5967 | $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash; |
||
5968 | $myCache->saveFromCache($chartHash, $imgPath); |
||
5969 | $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash; |
||
5970 | } else { |
||
5971 | /* Create the pChart object */ |
||
5972 | $widthSize = 80; |
||
5973 | $heightSize = 35; |
||
5974 | $fontSize = 2; |
||
5975 | |||
5976 | $myPicture = new pImage($widthSize, $heightSize, $dataSet); |
||
5977 | |||
5978 | /* Turn of Antialiasing */ |
||
5979 | $myPicture->Antialias = false; |
||
5980 | |||
5981 | /* Add a border to the picture */ |
||
5982 | $myPicture->drawRectangle( |
||
5983 | 0, |
||
5984 | 0, |
||
5985 | $widthSize - 1, |
||
5986 | $heightSize - 1, |
||
5987 | ['R' => 0, 'G' => 0, 'B' => 0] |
||
5988 | ); |
||
5989 | |||
5990 | /* Set the default font */ |
||
5991 | $myPicture->setFontProperties( |
||
5992 | [ |
||
5993 | 'FontName' => api_get_path( |
||
5994 | SYS_FONTS_PATH |
||
5995 | ).'opensans/OpenSans-Regular.ttf', |
||
5996 | 'FontSize' => $fontSize, |
||
5997 | ] |
||
5998 | ); |
||
5999 | |||
6000 | /* Do not write the chart title */ |
||
6001 | /* Define the chart area */ |
||
6002 | $myPicture->setGraphArea(5, 5, $widthSize - 5, $heightSize - 5); |
||
6003 | |||
6004 | /* Draw the scale */ |
||
6005 | $scaleSettings = [ |
||
6006 | 'GridR' => 200, |
||
6007 | 'GridG' => 200, |
||
6008 | 'GridB' => 200, |
||
6009 | 'DrawSubTicks' => true, |
||
6010 | 'CycleBackground' => true, |
||
6011 | 'Mode' => SCALE_MODE_MANUAL, |
||
6012 | 'ManualScale' => [ |
||
6013 | '0' => [ |
||
6014 | 'Min' => 0, |
||
6015 | 'Max' => 100, |
||
6016 | ], |
||
6017 | ], |
||
6018 | ]; |
||
6019 | $myPicture->drawScale($scaleSettings); |
||
6020 | |||
6021 | /* Turn on shadow computing */ |
||
6022 | $myPicture->setShadow( |
||
6023 | true, |
||
6024 | [ |
||
6025 | 'X' => 1, |
||
6026 | 'Y' => 1, |
||
6027 | 'R' => 0, |
||
6028 | 'G' => 0, |
||
6029 | 'B' => 0, |
||
6030 | 'Alpha' => 10, |
||
6031 | ] |
||
6032 | ); |
||
6033 | |||
6034 | /* Draw the chart */ |
||
6035 | $myPicture->setShadow( |
||
6036 | true, |
||
6037 | [ |
||
6038 | 'X' => 1, |
||
6039 | 'Y' => 1, |
||
6040 | 'R' => 0, |
||
6041 | 'G' => 0, |
||
6042 | 'B' => 0, |
||
6043 | 'Alpha' => 10, |
||
6044 | ] |
||
6045 | ); |
||
6046 | $settings = [ |
||
6047 | 'DisplayValues' => true, |
||
6048 | 'DisplaySize' => $fontSize, |
||
6049 | 'DisplayR' => 0, |
||
6050 | 'DisplayG' => 0, |
||
6051 | 'DisplayB' => 0, |
||
6052 | 'DisplayOrientation' => ORIENTATION_HORIZONTAL, |
||
6053 | 'Gradient' => false, |
||
6054 | 'Surrounding' => 5, |
||
6055 | 'InnerSurrounding' => 5, |
||
6056 | ]; |
||
6057 | $myPicture->drawStackedBarChart($settings); |
||
6058 | |||
6059 | /* Save and write in cache */ |
||
6060 | $myCache->writeToCache($chartHash, $myPicture); |
||
6061 | $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash; |
||
6062 | $myCache->saveFromCache($chartHash, $imgPath); |
||
6063 | $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash; |
||
6064 | } |
||
6065 | |||
6066 | return $imgPath; |
||
6067 | } |
||
6068 | |||
6069 | /** |
||
6070 | * Generates a big graph with the number of best results. |
||
6071 | * |
||
6072 | * @param array |
||
6073 | */ |
||
6074 | public static function generate_exercise_result_graph($attempts) |
||
6075 | { |
||
6076 | $exercise_title = strip_tags($attempts['title']); |
||
6077 | $attempts = $attempts['data']; |
||
6078 | $my_exercise_result_array = $exercise_result = []; |
||
6079 | if (empty($attempts)) { |
||
6080 | return null; |
||
6081 | } |
||
6082 | foreach ($attempts as $attempt) { |
||
6083 | if (api_get_user_id() == $attempt['exe_user_id']) { |
||
6084 | if (0 != $attempt['max_score']) { |
||
6085 | $my_exercise_result_array[] = $attempt['score'] / $attempt['max_score']; |
||
6086 | } |
||
6087 | } else { |
||
6088 | if (0 != $attempt['max_score']) { |
||
6089 | $exercise_result[] = $attempt['score'] / $attempt['max_score']; |
||
6090 | } |
||
6091 | } |
||
6092 | } |
||
6093 | |||
6094 | //Getting best result |
||
6095 | rsort($my_exercise_result_array); |
||
6096 | $my_exercise_result = 0; |
||
6097 | if (isset($my_exercise_result_array[0])) { |
||
6098 | $my_exercise_result = $my_exercise_result_array[0] * 100; |
||
6099 | } |
||
6100 | |||
6101 | $max = 100; |
||
6102 | $pieces = 5; |
||
6103 | $part = round($max / $pieces); |
||
6104 | $x_axis = []; |
||
6105 | $final_array = []; |
||
6106 | $my_final_array = []; |
||
6107 | |||
6108 | for ($i = 1; $i <= $pieces; $i++) { |
||
6109 | $sum = 1; |
||
6110 | if (1 == $i) { |
||
6111 | $sum = 0; |
||
6112 | } |
||
6113 | $min = ($i - 1) * $part + $sum; |
||
6114 | $max = ($i) * $part; |
||
6115 | $x_axis[] = $min." - ".$max; |
||
6116 | $count = 0; |
||
6117 | foreach ($exercise_result as $result) { |
||
6118 | $percentage = $result * 100; |
||
6119 | if ($percentage >= $min && $percentage <= $max) { |
||
6120 | $count++; |
||
6121 | } |
||
6122 | } |
||
6123 | $final_array[] = $count; |
||
6124 | |||
6125 | if ($my_exercise_result >= $min && $my_exercise_result <= $max) { |
||
6126 | $my_final_array[] = 1; |
||
6127 | } else { |
||
6128 | $my_final_array[] = 0; |
||
6129 | } |
||
6130 | } |
||
6131 | |||
6132 | //Fix to remove the data of the user with my data |
||
6133 | |||
6134 | 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
}
![]() |
|||
6135 | if (!empty($my_final_array[$i])) { |
||
6136 | $my_final_array[$i] = $final_array[$i] + 1; //Add my result |
||
6137 | $final_array[$i] = 0; |
||
6138 | } |
||
6139 | } |
||
6140 | |||
6141 | // Dataset definition |
||
6142 | $dataSet = new pData(); |
||
6143 | $dataSet->addPoints($final_array, 'Serie1'); |
||
6144 | $dataSet->addPoints($my_final_array, 'Serie2'); |
||
6145 | $dataSet->addPoints($x_axis, 'Serie3'); |
||
6146 | |||
6147 | $dataSet->setSerieDescription('Serie1', get_lang('Score')); |
||
6148 | $dataSet->setSerieDescription('Serie2', get_lang('My results')); |
||
6149 | $dataSet->setAbscissa('Serie3'); |
||
6150 | |||
6151 | $dataSet->setXAxisName(get_lang('Score')); |
||
6152 | $dataSet->normalize(100, "%"); |
||
6153 | |||
6154 | $dataSet->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true); |
||
6155 | |||
6156 | // Cache definition |
||
6157 | $cachePath = api_get_path(SYS_ARCHIVE_PATH); |
||
6158 | $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]); |
||
6159 | $chartHash = $myCache->getHash($dataSet); |
||
6160 | |||
6161 | if ($myCache->isInCache($chartHash)) { |
||
6162 | $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash; |
||
6163 | $myCache->saveFromCache($chartHash, $imgPath); |
||
6164 | $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash; |
||
6165 | } else { |
||
6166 | /* Create the pChart object */ |
||
6167 | $widthSize = 480; |
||
6168 | $heightSize = 250; |
||
6169 | $fontSize = 8; |
||
6170 | $myPicture = new pImage($widthSize, $heightSize, $dataSet); |
||
6171 | |||
6172 | /* Turn of Antialiasing */ |
||
6173 | $myPicture->Antialias = false; |
||
6174 | |||
6175 | /* Add a border to the picture */ |
||
6176 | $myPicture->drawRectangle(0, 0, $widthSize - 1, $heightSize - 1, ['R' => 0, 'G' => 0, 'B' => 0]); |
||
6177 | |||
6178 | /* Set the default font */ |
||
6179 | $myPicture->setFontProperties( |
||
6180 | [ |
||
6181 | 'FontName' => api_get_path( |
||
6182 | SYS_FONTS_PATH |
||
6183 | ).'opensans/OpenSans-Regular.ttf', |
||
6184 | 'FontSize' => 10, |
||
6185 | ] |
||
6186 | ); |
||
6187 | |||
6188 | /* Write the chart title */ |
||
6189 | $myPicture->drawText( |
||
6190 | 250, |
||
6191 | 20, |
||
6192 | $exercise_title, |
||
6193 | [ |
||
6194 | 'FontSize' => 12, |
||
6195 | 'Align' => TEXT_ALIGN_BOTTOMMIDDLE, |
||
6196 | ] |
||
6197 | ); |
||
6198 | |||
6199 | /* Define the chart area */ |
||
6200 | $myPicture->setGraphArea(50, 50, $widthSize - 20, $heightSize - 30); |
||
6201 | |||
6202 | /* Draw the scale */ |
||
6203 | $scaleSettings = [ |
||
6204 | 'GridR' => 200, |
||
6205 | 'GridG' => 200, |
||
6206 | 'GridB' => 200, |
||
6207 | 'DrawSubTicks' => true, |
||
6208 | 'CycleBackground' => true, |
||
6209 | 'Mode' => SCALE_MODE_MANUAL, |
||
6210 | 'ManualScale' => [ |
||
6211 | '0' => [ |
||
6212 | 'Min' => 0, |
||
6213 | 'Max' => 100, |
||
6214 | ], |
||
6215 | ], |
||
6216 | ]; |
||
6217 | $myPicture->drawScale($scaleSettings); |
||
6218 | |||
6219 | /* Turn on shadow computing */ |
||
6220 | $myPicture->setShadow(true, ['X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10]); |
||
6221 | |||
6222 | /* Draw the chart */ |
||
6223 | $myPicture->setShadow(true, ['X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10]); |
||
6224 | $settings = [ |
||
6225 | 'DisplayValues' => true, |
||
6226 | 'DisplaySize' => $fontSize, |
||
6227 | 'DisplayR' => 0, |
||
6228 | 'DisplayG' => 0, |
||
6229 | 'DisplayB' => 0, |
||
6230 | 'DisplayOrientation' => ORIENTATION_HORIZONTAL, |
||
6231 | 'Gradient' => false, |
||
6232 | 'Surrounding' => 30, |
||
6233 | 'InnerSurrounding' => 25, |
||
6234 | ]; |
||
6235 | $myPicture->drawStackedBarChart($settings); |
||
6236 | |||
6237 | $legendSettings = [ |
||
6238 | 'Mode' => LEGEND_HORIZONTAL, |
||
6239 | 'Style' => LEGEND_NOBORDER, |
||
6240 | ]; |
||
6241 | $myPicture->drawLegend($widthSize / 2, 30, $legendSettings); |
||
6242 | |||
6243 | /* Write and save into cache */ |
||
6244 | $myCache->writeToCache($chartHash, $myPicture); |
||
6245 | $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash; |
||
6246 | $myCache->saveFromCache($chartHash, $imgPath); |
||
6247 | $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash; |
||
6248 | } |
||
6249 | |||
6250 | return $imgPath; |
||
6251 | } |
||
6252 | |||
6253 | /** |
||
6254 | * @param FormValidator $form |
||
6255 | * |
||
6256 | * @return mixed |
||
6257 | */ |
||
6258 | public static function setUserSearchForm($form) |
||
6259 | { |
||
6260 | $form->addElement('text', 'keyword', get_lang('Keyword')); |
||
6261 | $form->addSelect( |
||
6262 | 'active', |
||
6263 | get_lang('Status'), |
||
6264 | [1 => get_lang('active'), 0 => get_lang('inactive')] |
||
6265 | ); |
||
6266 | |||
6267 | $form->addSelect( |
||
6268 | 'sleeping_days', |
||
6269 | get_lang('Inactive days'), |
||
6270 | [ |
||
6271 | '', |
||
6272 | 1 => 1, |
||
6273 | 5 => 5, |
||
6274 | 15 => 15, |
||
6275 | 30 => 30, |
||
6276 | 60 => 60, |
||
6277 | 90 => 90, |
||
6278 | 120 => 120, |
||
6279 | ] |
||
6280 | ); |
||
6281 | |||
6282 | $form->addButtonSearch(get_lang('Search')); |
||
6283 | |||
6284 | return $form; |
||
6285 | } |
||
6286 | |||
6287 | /** |
||
6288 | * Get the progress of a exercise. |
||
6289 | * |
||
6290 | * @param int $sessionId The session ID (session.id) |
||
6291 | * @param int $courseId The course ID (course.id) |
||
6292 | * @param int $exerciseId The quiz ID (c_quiz.id) |
||
6293 | * @param string $date_from |
||
6294 | * @param string $date_to |
||
6295 | * @param array $options An array of options you can pass to the query (limit, where and order) |
||
6296 | * |
||
6297 | * @return array An array with the data of exercise(s) progress |
||
6298 | */ |
||
6299 | public static function get_exercise_progress( |
||
6300 | $sessionId = 0, |
||
6301 | $courseId = 0, |
||
6302 | $exerciseId = 0, |
||
6303 | $date_from = null, |
||
6304 | $date_to = null, |
||
6305 | $options = [] |
||
6306 | ) { |
||
6307 | $sessionId = intval($sessionId); |
||
6308 | $courseId = intval($courseId); |
||
6309 | $exerciseId = intval($exerciseId); |
||
6310 | $date_from = Database::escape_string($date_from); |
||
6311 | $date_to = Database::escape_string($date_to); |
||
6312 | /* |
||
6313 | * This method gets the data by blocks, as previous attempts at one single |
||
6314 | * query made it take ages. The logic of query division is described below |
||
6315 | */ |
||
6316 | // Get tables names |
||
6317 | $tuser = Database::get_main_table(TABLE_MAIN_USER); |
||
6318 | $tquiz = Database::get_course_table(TABLE_QUIZ_TEST); |
||
6319 | $tquiz_answer = Database::get_course_table(TABLE_QUIZ_ANSWER); |
||
6320 | $tquiz_question = Database::get_course_table(TABLE_QUIZ_QUESTION); |
||
6321 | $tquiz_rel_question = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION); |
||
6322 | $ttrack_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
6323 | $ttrack_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
6324 | |||
6325 | $sessions = []; |
||
6326 | $courses = []; |
||
6327 | // if session ID is defined but course ID is empty, get all the courses |
||
6328 | // from that session |
||
6329 | if (!empty($sessionId) && empty($courseId)) { |
||
6330 | // $courses is an array of course int id as index and course details hash as value |
||
6331 | $courses = SessionManager::get_course_list_by_session_id($sessionId); |
||
6332 | $sessions[$sessionId] = api_get_session_info($sessionId); |
||
6333 | } elseif (empty($sessionId) && !empty($courseId)) { |
||
6334 | // if, to the contrary, course is defined but not sessions, get the sessions that include this course |
||
6335 | // $sessions is an array like: [0] => ('id' => 3, 'title' => 'Session 35'), [1] => () etc; |
||
6336 | $course = api_get_course_info_by_id($courseId); |
||
6337 | $sessionsTemp = SessionManager::get_session_by_course($courseId); |
||
6338 | $courses[$courseId] = $course; |
||
6339 | foreach ($sessionsTemp as $sessionItem) { |
||
6340 | $sessions[$sessionItem['id']] = $sessionItem; |
||
6341 | } |
||
6342 | } elseif (!empty($courseId) && !empty($sessionId)) { |
||
6343 | //none is empty |
||
6344 | $course = api_get_course_info_by_id($courseId); |
||
6345 | $courses[$courseId] = [$course['code']]; |
||
6346 | $courses[$courseId]['code'] = $course['code']; |
||
6347 | $sessions[$sessionId] = api_get_session_info($sessionId); |
||
6348 | } else { |
||
6349 | //both are empty, not enough data, return an empty array |
||
6350 | return []; |
||
6351 | } |
||
6352 | // Now we have two arrays of courses and sessions with enough data to proceed |
||
6353 | // If no course could be found, we shouldn't return anything. |
||
6354 | // Course sessions can be empty (then we only return the pure-course-context results) |
||
6355 | if (count($courses) < 1) { |
||
6356 | return []; |
||
6357 | } |
||
6358 | |||
6359 | $data = []; |
||
6360 | // The following loop is less expensive than what it seems: |
||
6361 | // - if a course was defined, then we only loop through sessions |
||
6362 | // - if a session was defined, then we only loop through courses |
||
6363 | // - if a session and a course were defined, then we only loop once |
||
6364 | foreach ($courses as $courseIdx => $courseData) { |
||
6365 | $where = ''; |
||
6366 | $whereParams = []; |
||
6367 | $whereSessionParams = ''; |
||
6368 | if (count($sessions > 0)) { |
||
6369 | foreach ($sessions as $sessionIdx => $sessionData) { |
||
6370 | if (!empty($sessionIdx)) { |
||
6371 | $whereSessionParams .= $sessionIdx.','; |
||
6372 | } |
||
6373 | } |
||
6374 | $whereSessionParams = substr($whereSessionParams, 0, -1); |
||
6375 | } |
||
6376 | |||
6377 | if (!empty($exerciseId)) { |
||
6378 | $exerciseId = intval($exerciseId); |
||
6379 | $where .= ' AND q.iid = %d '; |
||
6380 | $whereParams[] = $exerciseId; |
||
6381 | } |
||
6382 | |||
6383 | /* |
||
6384 | * This feature has been disabled for now, to avoid having to |
||
6385 | * join two very large tables |
||
6386 | //2 = show all questions (wrong and correct answered) |
||
6387 | if ($answer != 2) { |
||
6388 | $answer = intval($answer); |
||
6389 | //$where .= ' AND qa.correct = %d'; |
||
6390 | //$whereParams[] = $answer; |
||
6391 | } |
||
6392 | */ |
||
6393 | |||
6394 | $limit = ''; |
||
6395 | if (!empty($options['limit'])) { |
||
6396 | $limit = " LIMIT ".$options['limit']; |
||
6397 | } |
||
6398 | |||
6399 | if (!empty($options['where'])) { |
||
6400 | $where .= ' AND '.Database::escape_string($options['where']); |
||
6401 | } |
||
6402 | |||
6403 | $order = ''; |
||
6404 | if (!empty($options['order'])) { |
||
6405 | $order = " ORDER BY ".$options['order']; |
||
6406 | } |
||
6407 | |||
6408 | if (!empty($date_to) && !empty($date_from)) { |
||
6409 | $where .= sprintf(" AND (te.start_date BETWEEN '%s 00:00:00' AND '%s 23:59:59')", $date_from, $date_to); |
||
6410 | } |
||
6411 | |||
6412 | $sql = "SELECT |
||
6413 | te.session_id, |
||
6414 | ta.id as attempt_id, |
||
6415 | te.exe_user_id as user_id, |
||
6416 | te.exe_id as exercise_attempt_id, |
||
6417 | ta.question_id, |
||
6418 | ta.answer as answer_id, |
||
6419 | ta.tms as time, |
||
6420 | te.exe_exo_id as quiz_id, |
||
6421 | CONCAT ('c', q.c_id, '_e', q.iid) as exercise_id, |
||
6422 | q.title as quiz_title, |
||
6423 | qq.description as description |
||
6424 | FROM $ttrack_exercises te |
||
6425 | INNER JOIN $ttrack_attempt ta |
||
6426 | ON ta.exe_id = te.exe_id |
||
6427 | INNER JOIN $tquiz q |
||
6428 | ON q.iid = te.exe_exo_id |
||
6429 | INNER JOIN $tquiz_rel_question rq |
||
6430 | ON rq.quiz_id = q.iid AND rq.c_id = q.c_id |
||
6431 | INNER JOIN $tquiz_question qq |
||
6432 | ON |
||
6433 | qq.iid = rq.question_id AND |
||
6434 | qq.c_id = rq.c_id AND |
||
6435 | qq.position = rq.question_order AND |
||
6436 | ta.question_id = rq.question_id |
||
6437 | WHERE |
||
6438 | te.c_id = $courseIdx ".(empty($whereSessionParams) ? '' : "AND te.session_id IN ($whereSessionParams)")." |
||
6439 | AND q.c_id = $courseIdx |
||
6440 | $where $order $limit"; |
||
6441 | $sql_query = vsprintf($sql, $whereParams); |
||
6442 | |||
6443 | // Now browse through the results and get the data |
||
6444 | $rs = Database::query($sql_query); |
||
6445 | $userIds = []; |
||
6446 | $questionIds = []; |
||
6447 | $answerIds = []; |
||
6448 | while ($row = Database::fetch_array($rs)) { |
||
6449 | //only show if exercise is visible |
||
6450 | if (api_get_item_visibility($courseData, 'quiz', $row['exercise_id'])) { |
||
6451 | $userIds[$row['user_id']] = $row['user_id']; |
||
6452 | $questionIds[$row['question_id']] = $row['question_id']; |
||
6453 | $answerIds[$row['question_id']][$row['answer_id']] = $row['answer_id']; |
||
6454 | $row['session'] = $sessions[$row['session_id']]; |
||
6455 | $data[] = $row; |
||
6456 | } |
||
6457 | } |
||
6458 | // Now fill questions data. Query all questions and answers for this test to avoid |
||
6459 | $sqlQuestions = "SELECT tq.c_id, tq.iid as question_id, tq.question, tqa.iid, |
||
6460 | tqa.answer, tqa.correct, tq.position, tqa.iid as answer_id |
||
6461 | FROM $tquiz_question tq, $tquiz_answer tqa |
||
6462 | WHERE |
||
6463 | tqa.question_id = tq.iid AND |
||
6464 | tqa.c_id = tq.c_id AND |
||
6465 | tq.c_id = $courseIdx AND |
||
6466 | tq.iid IN (".implode(',', $questionIds).")"; |
||
6467 | |||
6468 | $resQuestions = Database::query($sqlQuestions); |
||
6469 | $answer = []; |
||
6470 | $question = []; |
||
6471 | while ($rowQuestion = Database::fetch_assoc($resQuestions)) { |
||
6472 | $questionId = $rowQuestion['question_id']; |
||
6473 | $answerId = $rowQuestion['answer_id']; |
||
6474 | $answer[$questionId][$answerId] = [ |
||
6475 | 'position' => $rowQuestion['position'], |
||
6476 | 'question' => $rowQuestion['question'], |
||
6477 | 'answer' => $rowQuestion['answer'], |
||
6478 | 'correct' => $rowQuestion['correct'], |
||
6479 | ]; |
||
6480 | $question[$questionId]['question'] = $rowQuestion['question']; |
||
6481 | } |
||
6482 | |||
6483 | // Now fill users data |
||
6484 | $sqlUsers = "SELECT id as user_id, username, lastname, firstname |
||
6485 | FROM $tuser |
||
6486 | WHERE active <> ".USER_SOFT_DELETED." AND id IN (".implode(',', $userIds).")"; |
||
6487 | $resUsers = Database::query($sqlUsers); |
||
6488 | while ($rowUser = Database::fetch_assoc($resUsers)) { |
||
6489 | $users[$rowUser['user_id']] = $rowUser; |
||
6490 | } |
||
6491 | |||
6492 | foreach ($data as $id => $row) { |
||
6493 | $rowQuestId = $row['question_id']; |
||
6494 | $rowAnsId = $row['answer_id']; |
||
6495 | $data[$id]['session'] = $sessions[$row['session_id']]['title']; |
||
6496 | $data[$id]['firstname'] = $users[$row['user_id']]['firstname']; |
||
6497 | $data[$id]['lastname'] = $users[$row['user_id']]['lastname']; |
||
6498 | $data[$id]['username'] = $users[$row['user_id']]['username']; |
||
6499 | $data[$id]['answer'] = $answer[$rowQuestId][$rowAnsId]['answer']; |
||
6500 | $data[$id]['correct'] = (0 == $answer[$rowQuestId][$rowAnsId]['correct'] ? get_lang('No') : get_lang('Yes')); |
||
6501 | $data[$id]['question'] = $question[$rowQuestId]['question']; |
||
6502 | $data[$id]['question_id'] = $rowQuestId; |
||
6503 | $data[$id]['description'] = $row['description']; |
||
6504 | } |
||
6505 | |||
6506 | /* |
||
6507 | The minimum expected array structure at the end is: |
||
6508 | attempt_id, |
||
6509 | session title, |
||
6510 | exercise_id, |
||
6511 | quiz_title, |
||
6512 | username, |
||
6513 | lastname, |
||
6514 | firstname, |
||
6515 | time, |
||
6516 | question_id, |
||
6517 | question, |
||
6518 | answer, |
||
6519 | */ |
||
6520 | } |
||
6521 | |||
6522 | return $data; |
||
6523 | } |
||
6524 | |||
6525 | /** |
||
6526 | * @param string $tool |
||
6527 | * @param SessionEntity |null $session |
||
6528 | * |
||
6529 | * @return CStudentPublication|null |
||
6530 | */ |
||
6531 | public static function getLastStudentPublication( |
||
6532 | User $user, |
||
6533 | $tool, |
||
6534 | Course $course, |
||
6535 | SessionEntity $session = null |
||
6536 | ) { |
||
6537 | // @todo |
||
6538 | return null; |
||
6539 | |||
6540 | return Database::getManager() |
||
0 ignored issues
–
show
return Database::getMana...)->getOneOrNullResult() is not reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
6541 | ->createQuery(" |
||
6542 | SELECT csp |
||
6543 | FROM ChamiloCourseBundle:CStudentPublication csp |
||
6544 | INNER JOIN ChamiloCourseBundle:CItemProperty cip |
||
6545 | WITH ( |
||
6546 | csp.iid = cip.ref AND |
||
6547 | csp.session = cip.session AND |
||
6548 | csp.cId = cip.course AND |
||
6549 | csp.userId = cip.lasteditUserId |
||
6550 | ) |
||
6551 | WHERE |
||
6552 | cip.session = :session AND cip.course = :course AND cip.lasteditUserId = :user AND cip.tool = :tool |
||
6553 | ORDER BY csp.iid DESC |
||
6554 | ") |
||
6555 | ->setMaxResults(1) |
||
6556 | ->setParameters([ |
||
6557 | 'tool' => $tool, |
||
6558 | 'session' => $session, |
||
6559 | 'course' => $course, |
||
6560 | 'user' => $user, |
||
6561 | ]) |
||
6562 | ->getOneOrNullResult(); |
||
6563 | } |
||
6564 | |||
6565 | /** |
||
6566 | * Get the HTML code for show a block with the achieved user skill on course/session. |
||
6567 | * |
||
6568 | * @param int $userId |
||
6569 | * @param ?int $courseId |
||
6570 | * @param ?int $sessionId |
||
6571 | * @param ?bool $forceView forces the view of the skills, not checking for deeper access |
||
6572 | * |
||
6573 | * @return string |
||
6574 | */ |
||
6575 | public static function displayUserSkills(int $userId, ?int $courseId = 0, ?int $sessionId = 0, ?bool $forceView = false): string |
||
6576 | { |
||
6577 | if (false === SkillModel::isAllowed($userId, false) && !$forceView) { |
||
6578 | return ''; |
||
6579 | } |
||
6580 | $skillManager = new SkillModel(); |
||
6581 | |||
6582 | return $skillManager->getUserSkillsTable($userId, $courseId, $sessionId)['table']; |
||
6583 | } |
||
6584 | |||
6585 | /** |
||
6586 | * Return time spent by the given user in the given course/session, from the track_e_access_complete table, and |
||
6587 | * breakdown time items in different array elements |
||
6588 | * @param int $userId |
||
6589 | * @param int $courseId |
||
6590 | * @param int $sessionId |
||
6591 | * |
||
6592 | * @return array |
||
6593 | * @throws \Doctrine\DBAL\Exception |
||
6594 | */ |
||
6595 | public static function getCalculateTime(int $userId, int $courseId, int $sessionId): array |
||
6596 | { |
||
6597 | if (empty($userId) || empty($courseId)) { |
||
6598 | return []; |
||
6599 | } |
||
6600 | |||
6601 | $sql = "SELECT MIN(date_reg) min, MAX(date_reg) max |
||
6602 | FROM track_e_access_complete |
||
6603 | WHERE |
||
6604 | user_id = $userId AND |
||
6605 | c_id = $courseId AND |
||
6606 | session_id = $sessionId AND |
||
6607 | login_as = 0 |
||
6608 | ORDER BY date_reg ASC |
||
6609 | LIMIT 1"; |
||
6610 | $rs = Database::query($sql); |
||
6611 | |||
6612 | $firstConnection = ''; |
||
6613 | $lastConnection = ''; |
||
6614 | if (Database::num_rows($rs) > 0) { |
||
6615 | $value = Database::fetch_array($rs); |
||
6616 | $firstConnection = $value['min']; |
||
6617 | $lastConnection = $value['max']; |
||
6618 | } |
||
6619 | |||
6620 | $sql = "SELECT * FROM track_e_access_complete |
||
6621 | WHERE |
||
6622 | user_id = $userId AND |
||
6623 | c_id = $courseId AND |
||
6624 | session_id = $sessionId AND |
||
6625 | login_as = 0 AND current_id <> 0"; |
||
6626 | |||
6627 | $res = Database::query($sql); |
||
6628 | $reg = []; |
||
6629 | while ($row = Database::fetch_assoc($res)) { |
||
6630 | $reg[$row['id']] = $row; |
||
6631 | $reg[$row['id']]['date_reg'] = strtotime($row['date_reg']); |
||
6632 | } |
||
6633 | |||
6634 | $sessions = []; |
||
6635 | foreach ($reg as $key => $value) { |
||
6636 | $sessions[$value['current_id']][$value['tool']][] = $value; |
||
6637 | } |
||
6638 | |||
6639 | $quizTime = 0; |
||
6640 | $result = []; |
||
6641 | $totalTime = 0; |
||
6642 | $lpTime = []; |
||
6643 | $lpDetailTime = []; |
||
6644 | foreach ($sessions as $listPerTool) { |
||
6645 | $min = 0; |
||
6646 | $max = 0; |
||
6647 | $sessionDiff = 0; |
||
6648 | foreach ($listPerTool as $tool => $results) { |
||
6649 | $beforeItem = []; |
||
6650 | foreach ($results as $item) { |
||
6651 | if (empty($beforeItem)) { |
||
6652 | $beforeItem = $item; |
||
6653 | if (empty($min)) { |
||
6654 | $min = $item['date_reg']; |
||
6655 | } |
||
6656 | |||
6657 | if (empty($max)) { |
||
6658 | $max = $item['date_reg']; |
||
6659 | } |
||
6660 | continue; |
||
6661 | } |
||
6662 | |||
6663 | $partialTime = $item['date_reg'] - $beforeItem['date_reg']; |
||
6664 | if ($item['date_reg'] > $max) { |
||
6665 | $max = $item['date_reg']; |
||
6666 | } |
||
6667 | |||
6668 | if (empty($min)) { |
||
6669 | $min = $item['date_reg']; |
||
6670 | } |
||
6671 | |||
6672 | if ($item['date_reg'] < $min) { |
||
6673 | $min = $item['date_reg']; |
||
6674 | } |
||
6675 | |||
6676 | switch ($tool) { |
||
6677 | case TOOL_AGENDA: |
||
6678 | case TOOL_FORUM: |
||
6679 | case TOOL_ANNOUNCEMENT: |
||
6680 | case TOOL_COURSE_DESCRIPTION: |
||
6681 | case TOOL_SURVEY: |
||
6682 | case TOOL_NOTEBOOK: |
||
6683 | case TOOL_GRADEBOOK: |
||
6684 | case TOOL_DROPBOX: |
||
6685 | case 'Reports': |
||
6686 | case 'Videoconference': |
||
6687 | case TOOL_LINK: |
||
6688 | case TOOL_CHAT: |
||
6689 | case 'course-main': |
||
6690 | if (!isset($result[$tool])) { |
||
6691 | $result[$tool] = 0; |
||
6692 | } |
||
6693 | $result[$tool] += $partialTime; |
||
6694 | break; |
||
6695 | case TOOL_LEARNPATH: |
||
6696 | if ($item['tool_id'] != $beforeItem['tool_id']) { |
||
6697 | break; |
||
6698 | } |
||
6699 | if (!isset($lpTime[$item['tool_id']])) { |
||
6700 | $lpTime[$item['tool_id']] = 0; |
||
6701 | } |
||
6702 | |||
6703 | // Saving the attempt id "action_details" |
||
6704 | if (!empty($item['tool_id'])) { |
||
6705 | if (!empty($item['tool_id_detail'])) { |
||
6706 | if (!isset($lpDetailTime[$item['tool_id']][$item['tool_id_detail']][$item['action_details']])) { |
||
6707 | $lpDetailTime[$item['tool_id']][$item['tool_id_detail']][$item['action_details']] = 0; |
||
6708 | } |
||
6709 | $lpDetailTime[$item['tool_id']][$item['tool_id_detail']][$item['action_details']] += $partialTime; |
||
6710 | } |
||
6711 | $lpTime[$item['tool_id']] += $partialTime; |
||
6712 | } |
||
6713 | break; |
||
6714 | case TOOL_QUIZ: |
||
6715 | if (!isset($lpTime[$item['action_details']])) { |
||
6716 | $lpTime[$item['action_details']] = 0; |
||
6717 | } |
||
6718 | if ('learnpath_id' === $beforeItem['action']) { |
||
6719 | $lpTime[$item['action_details']] += $partialTime; |
||
6720 | } else { |
||
6721 | $quizTime += $partialTime; |
||
6722 | } |
||
6723 | break; |
||
6724 | } |
||
6725 | $beforeItem = $item; |
||
6726 | } |
||
6727 | } |
||
6728 | |||
6729 | $sessionDiff += $max - $min; |
||
6730 | if ($sessionDiff > 0) { |
||
6731 | $totalTime += $sessionDiff; |
||
6732 | } |
||
6733 | } |
||
6734 | |||
6735 | $totalLp = 0; |
||
6736 | foreach ($lpTime as $value) { |
||
6737 | $totalLp += $value; |
||
6738 | } |
||
6739 | |||
6740 | $result['learnpath_detailed'] = $lpDetailTime; |
||
6741 | $result[TOOL_LEARNPATH] = $lpTime; |
||
6742 | $result[TOOL_QUIZ] = $quizTime; |
||
6743 | $result['total_learnpath'] = $totalLp; |
||
6744 | $result['total_time'] = $totalTime; |
||
6745 | $result['number_connections'] = count($sessions); |
||
6746 | $result['first'] = $firstConnection; |
||
6747 | $result['last'] = $lastConnection; |
||
6748 | |||
6749 | return $result; |
||
6750 | } |
||
6751 | |||
6752 | /** |
||
6753 | * Gets the IP of a given user, using the last login before the given date. |
||
6754 | * |
||
6755 | * @param int User ID |
||
6756 | * @param string Datetime |
||
6757 | * @param ?bool Whether to return the IP as a link or just as an IP |
||
6758 | * @param ?string If defined and return_as_link if true, will be used as the text to be shown as the link |
||
6759 | * |
||
6760 | * @return string IP address (or false on error) |
||
6761 | * @assert (0,0) === false |
||
6762 | * @throws \Doctrine\DBAL\Exception |
||
6763 | */ |
||
6764 | public static function get_ip_from_user_event( |
||
6765 | int $user_id, |
||
6766 | string $event_date, |
||
6767 | ?bool $return_as_link = false, |
||
6768 | ?string $body_replace = null |
||
6769 | ): mixed { |
||
6770 | if (empty($user_id) || empty($event_date)) { |
||
6771 | return false; |
||
6772 | } |
||
6773 | $user_id = intval($user_id); |
||
6774 | $event_date = Database::escape_string($event_date); |
||
6775 | $table_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN); |
||
6776 | $sql_ip = "SELECT login_date, user_ip |
||
6777 | FROM $table_login |
||
6778 | WHERE login_user_id = $user_id AND login_date < '$event_date' |
||
6779 | ORDER BY login_date DESC LIMIT 1"; |
||
6780 | $ip = ''; |
||
6781 | $res_ip = Database::query($sql_ip); |
||
6782 | if (false !== $res_ip && Database::num_rows($res_ip) > 0) { |
||
6783 | $row_ip = Database::fetch_row($res_ip); |
||
6784 | if ($return_as_link) { |
||
6785 | $ip = Display::url( |
||
6786 | (empty($body_replace) ? $row_ip[1] : $body_replace), |
||
6787 | 'http://www.whatsmyip.org/ip-geo-location/?ip='.$row_ip[1], |
||
6788 | ['title' => get_lang('Trace IP'), 'target' => '_blank'] |
||
6789 | ); |
||
6790 | } else { |
||
6791 | $ip = $row_ip[1]; |
||
6792 | } |
||
6793 | } |
||
6794 | |||
6795 | return $ip; |
||
6796 | } |
||
6797 | |||
6798 | /** |
||
6799 | * @param int $userId |
||
6800 | * @param array $courseInfo |
||
6801 | * @param ?int $sessionId |
||
6802 | * |
||
6803 | * @return array |
||
6804 | */ |
||
6805 | public static function getToolInformation( |
||
6806 | int $userId, |
||
6807 | array $courseInfo, |
||
6808 | ?int $sessionId = 0 |
||
6809 | ): array { |
||
6810 | $csvContent = []; |
||
6811 | $courseToolInformation = ''; |
||
6812 | $headerTool = [ |
||
6813 | [get_lang('Title')], |
||
6814 | [get_lang('Created at')], |
||
6815 | [get_lang('Updated at')], |
||
6816 | ]; |
||
6817 | |||
6818 | $headerListForCSV = []; |
||
6819 | foreach ($headerTool as $item) { |
||
6820 | $headerListForCSV[] = $item[0]; |
||
6821 | } |
||
6822 | |||
6823 | $courseForumInformationArray = getForumCreatedByUser( |
||
6824 | $userId, |
||
6825 | $courseInfo, |
||
6826 | $sessionId |
||
6827 | ); |
||
6828 | |||
6829 | if (!empty($courseForumInformationArray)) { |
||
6830 | $csvContent[] = []; |
||
6831 | $csvContent[] = [get_lang('Forums')]; |
||
6832 | $csvContent[] = $headerListForCSV; |
||
6833 | foreach ($courseForumInformationArray as $row) { |
||
6834 | $csvContent[] = $row; |
||
6835 | } |
||
6836 | |||
6837 | $courseToolInformation .= Display::page_subheader2( |
||
6838 | get_lang('Forums') |
||
6839 | ); |
||
6840 | $courseToolInformation .= Display::return_sortable_table( |
||
6841 | $headerTool, |
||
6842 | $courseForumInformationArray |
||
6843 | ); |
||
6844 | } |
||
6845 | |||
6846 | $courseWorkInformationArray = getWorkCreatedByUser( |
||
6847 | $userId, |
||
6848 | $courseInfo['real_id'], |
||
6849 | $sessionId |
||
6850 | ); |
||
6851 | |||
6852 | if (!empty($courseWorkInformationArray)) { |
||
6853 | $csvContent[] = null; |
||
6854 | $csvContent[] = [get_lang('Assignments')]; |
||
6855 | $csvContent[] = $headerListForCSV; |
||
6856 | |||
6857 | foreach ($courseWorkInformationArray as $row) { |
||
6858 | $csvContent[] = $row; |
||
6859 | } |
||
6860 | $csvContent[] = null; |
||
6861 | |||
6862 | $courseToolInformation .= Display::page_subheader2( |
||
6863 | get_lang('Assignments') |
||
6864 | ); |
||
6865 | $courseToolInformation .= Display::return_sortable_table( |
||
6866 | $headerTool, |
||
6867 | $courseWorkInformationArray |
||
6868 | ); |
||
6869 | } |
||
6870 | |||
6871 | $courseToolInformationTotal = null; |
||
6872 | if (!empty($courseToolInformation)) { |
||
6873 | $sessionTitle = null; |
||
6874 | if (!empty($sessionId)) { |
||
6875 | $sessionTitle = ' ('.api_get_session_name($sessionId).')'; |
||
6876 | } |
||
6877 | |||
6878 | $courseToolInformationTotal .= Display::page_subheader( |
||
6879 | $courseInfo['title'].$sessionTitle |
||
6880 | ); |
||
6881 | $courseToolInformationTotal .= $courseToolInformation; |
||
6882 | } |
||
6883 | |||
6884 | return [ |
||
6885 | 'array' => $csvContent, |
||
6886 | 'html' => $courseToolInformationTotal, |
||
6887 | ]; |
||
6888 | } |
||
6889 | |||
6890 | /** |
||
6891 | * @param int $sessionId |
||
6892 | * |
||
6893 | * @return bool |
||
6894 | */ |
||
6895 | public static function isAllowToTrack($sessionId) |
||
6896 | { |
||
6897 | return |
||
6898 | api_is_platform_admin(true, true) || |
||
6899 | (!empty($sessionId) && api_get_session_entity($sessionId)->hasUserAsGeneralCoach(api_get_user_entity())) || |
||
6900 | api_is_allowed_to_create_course() || |
||
6901 | api_is_course_tutor() || |
||
6902 | api_is_course_admin(); |
||
6903 | } |
||
6904 | |||
6905 | public static function getCourseLpProgress($userId, $sessionId) |
||
6906 | { |
||
6907 | $controller = new IndexManager(get_lang('MyCourses')); |
||
6908 | $data = $controller->returnCoursesAndSessions($userId); |
||
6909 | $courseList = $data['courses']; |
||
6910 | $result = []; |
||
6911 | if ($courseList) { |
||
6912 | //$counter = 1; |
||
6913 | foreach ($courseList as $course) { |
||
6914 | $courseId = $course['course_id']; |
||
6915 | $courseInfo = api_get_course_info_by_id($courseId); |
||
6916 | if (empty($courseInfo)) { |
||
6917 | continue; |
||
6918 | } |
||
6919 | $courseCode = $courseInfo['code']; |
||
6920 | $lpTimeList = self::getCalculateTime($userId, $courseId, $sessionId); |
||
6921 | |||
6922 | // total progress |
||
6923 | $list = new LearnpathList( |
||
6924 | $userId, |
||
6925 | $courseInfo, |
||
6926 | 0, |
||
6927 | 'resource.publishedOn ASC', |
||
6928 | true, |
||
6929 | null, |
||
6930 | true |
||
6931 | ); |
||
6932 | |||
6933 | $list = $list->get_flat_list(); |
||
6934 | $totalProgress = 0; |
||
6935 | $totalTime = 0; |
||
6936 | if (!empty($list)) { |
||
6937 | foreach ($list as $lp_id => $learnpath) { |
||
6938 | if (!$learnpath['lp_visibility']) { |
||
6939 | continue; |
||
6940 | } |
||
6941 | $lpProgress = self::get_avg_student_progress($userId, $courseCode, [$lp_id], $sessionId); |
||
6942 | $time = isset($lpTimeList[TOOL_LEARNPATH][$lp_id]) ? $lpTimeList[TOOL_LEARNPATH][$lp_id] : 0; |
||
6943 | if (100 == $lpProgress) { |
||
6944 | if (!empty($time)) { |
||
6945 | $timeInMinutes = $time / 60; |
||
6946 | $min = (int) learnpath::getAccumulateWorkTimePrerequisite($lp_id, $courseId); |
||
6947 | if ($timeInMinutes >= $min) { |
||
6948 | $totalProgress++; |
||
6949 | } |
||
6950 | } |
||
6951 | } |
||
6952 | $totalTime += $time; |
||
6953 | } |
||
6954 | |||
6955 | if (!empty($totalProgress)) { |
||
6956 | $totalProgress = (float) api_number_format($totalProgress / count($list) * 100, 2); |
||
6957 | } |
||
6958 | } |
||
6959 | |||
6960 | $progress = self::get_avg_student_progress($userId, $courseCode, [], $sessionId); |
||
6961 | |||
6962 | $result[] = [ |
||
6963 | 'module' => $courseInfo['name'], |
||
6964 | 'progress' => $progress, |
||
6965 | 'qualification' => $totalProgress, |
||
6966 | 'activeTime' => $totalTime, |
||
6967 | ]; |
||
6968 | } |
||
6969 | } |
||
6970 | |||
6971 | return $result; |
||
6972 | } |
||
6973 | |||
6974 | /** |
||
6975 | * @param int $userId |
||
6976 | * @param int $courseId |
||
6977 | * @param int $sessionId |
||
6978 | * |
||
6979 | * @return int |
||
6980 | */ |
||
6981 | public static function getNumberOfCourseAccessDates($userId, $courseId, $sessionId) |
||
6982 | { |
||
6983 | $tblTrackCourseAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
6984 | $sessionCondition = api_get_session_condition($sessionId); |
||
6985 | $courseId = (int) $courseId; |
||
6986 | $userId = (int) $userId; |
||
6987 | |||
6988 | $sql = "SELECT COUNT(DISTINCT (DATE(login_course_date))) AS c |
||
6989 | FROM $tblTrackCourseAccess |
||
6990 | WHERE c_id = $courseId $sessionCondition AND user_id = $userId"; |
||
6991 | |||
6992 | $result = Database::fetch_assoc(Database::query($sql)); |
||
6993 | |||
6994 | return (int) $result['c']; |
||
6995 | } |
||
6996 | |||
6997 | public static function processUserDataMove( |
||
6998 | $user_id, |
||
6999 | $course_info, |
||
7000 | $origin_session_id, |
||
7001 | $new_session_id, |
||
7002 | $update_database, |
||
7003 | $debug = false |
||
7004 | ) { |
||
7005 | // Begin with the import process |
||
7006 | $origin_course_code = $course_info['code']; |
||
7007 | $course_id = $course_info['real_id']; |
||
7008 | $user_id = (int) $user_id; |
||
7009 | $origin_session_id = (int) $origin_session_id; |
||
7010 | $new_session_id = (int) $new_session_id; |
||
7011 | $session = api_get_session_entity($new_session_id); |
||
7012 | $em = Database::getManager(); |
||
7013 | |||
7014 | $TABLETRACK_EXERCICES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
7015 | $TBL_TRACK_ATTEMPT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
7016 | $TBL_TRACK_E_COURSE_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
7017 | $TBL_TRACK_E_LAST_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS); |
||
7018 | $TBL_LP_VIEW = Database::get_course_table(TABLE_LP_VIEW); |
||
7019 | $TBL_NOTEBOOK = Database::get_course_table(TABLE_NOTEBOOK); |
||
7020 | $TBL_STUDENT_PUBLICATION = Database::get_course_table(TABLE_STUDENT_PUBLICATION); |
||
7021 | $TBL_STUDENT_PUBLICATION_ASSIGNMENT = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT); |
||
7022 | $TBL_ITEM_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY); |
||
7023 | |||
7024 | $TBL_DROPBOX_FILE = Database::get_course_table(TABLE_DROPBOX_FILE); |
||
7025 | $TBL_DROPBOX_POST = Database::get_course_table(TABLE_DROPBOX_POST); |
||
7026 | $TBL_AGENDA = Database::get_course_table(TABLE_AGENDA); |
||
7027 | |||
7028 | //1. track_e_exercises |
||
7029 | //ORIGINAL COURSE |
||
7030 | $sessionCondition = api_get_session_condition($origin_session_id); |
||
7031 | $sql = "SELECT * FROM $TABLETRACK_EXERCICES |
||
7032 | WHERE c_id = $course_id AND exe_user_id = $user_id $sessionCondition"; |
||
7033 | $res = Database::query($sql); |
||
7034 | $list = []; |
||
7035 | while ($row = Database::fetch_assoc($res)) { |
||
7036 | $list[$row['exe_id']] = $row; |
||
7037 | } |
||
7038 | |||
7039 | $result_message = []; |
||
7040 | $result_message_compare = []; |
||
7041 | if (!empty($list)) { |
||
7042 | foreach ($list as $exe_id => $data) { |
||
7043 | if ($update_database) { |
||
7044 | $sql = "UPDATE $TABLETRACK_EXERCICES SET session_id = '$new_session_id' WHERE exe_id = $exe_id"; |
||
7045 | Database::query($sql); |
||
7046 | |||
7047 | //$sql = "UPDATE $TBL_TRACK_ATTEMPT SET session_id = '$new_session_id' WHERE exe_id = $exe_id"; |
||
7048 | //Database::query($sql); |
||
7049 | |||
7050 | $repoTrackQualify = $em->getRepository(TrackEAttemptQualify::class); |
||
7051 | /** @var TrackEAttemptQualify $trackQualify */ |
||
7052 | $trackQualify = $repoTrackQualify->findBy([ |
||
7053 | 'exeId' => $exe_id |
||
7054 | ]); |
||
7055 | if ($trackQualify) { |
||
7056 | $trackQualify->setSessionId($new_session_id); |
||
7057 | $em->persist($trackQualify); |
||
7058 | $em->flush(); |
||
7059 | } |
||
7060 | |||
7061 | if (!isset($result_message[$TABLETRACK_EXERCICES])) { |
||
7062 | $result_message[$TABLETRACK_EXERCICES] = 0; |
||
7063 | } |
||
7064 | $result_message[$TABLETRACK_EXERCICES]++; |
||
7065 | } else { |
||
7066 | if (!empty($data['orig_lp_id']) && !empty($data['orig_lp_item_id'])) { |
||
7067 | $result_message['TRACK_E_EXERCISES'][$exe_id] = $data; |
||
7068 | } else { |
||
7069 | $result_message['TRACK_E_EXERCISES_IN_LP'][$exe_id] = $data; |
||
7070 | } |
||
7071 | } |
||
7072 | } |
||
7073 | } |
||
7074 | |||
7075 | // DESTINY COURSE |
||
7076 | if (!$update_database) { |
||
7077 | $sql = "SELECT * FROM $TABLETRACK_EXERCICES |
||
7078 | WHERE |
||
7079 | c_id = $course_id AND |
||
7080 | session_id = $new_session_id AND |
||
7081 | exe_user_id = $user_id "; |
||
7082 | $res = Database::query($sql); |
||
7083 | $list = []; |
||
7084 | while ($row = Database::fetch_assoc($res)) { |
||
7085 | $list[$row['exe_id']] = $row; |
||
7086 | } |
||
7087 | |||
7088 | if (!empty($list)) { |
||
7089 | foreach ($list as $exe_id => $data) { |
||
7090 | if ($update_database) { |
||
7091 | $sql = "UPDATE $TABLETRACK_EXERCICES |
||
7092 | SET session_id = '$new_session_id' |
||
7093 | WHERE exe_id = $exe_id"; |
||
7094 | Database::query($sql); |
||
7095 | $result_message[$TABLETRACK_EXERCICES]++; |
||
7096 | } else { |
||
7097 | if (!empty($data['orig_lp_id']) && !empty($data['orig_lp_item_id'])) { |
||
7098 | $result_message_compare['TRACK_E_EXERCISES'][$exe_id] = $data; |
||
7099 | } else { |
||
7100 | $result_message_compare['TRACK_E_EXERCISES_IN_LP'][$exe_id] = $data; |
||
7101 | } |
||
7102 | } |
||
7103 | } |
||
7104 | } |
||
7105 | } |
||
7106 | |||
7107 | // 2.track_e_attempt, track_e_attempt_recording, track_e_downloads |
||
7108 | // Nothing to do because there are not relationship with a session |
||
7109 | // 3. track_e_course_access |
||
7110 | $sql = "SELECT * FROM $TBL_TRACK_E_COURSE_ACCESS |
||
7111 | WHERE c_id = $course_id AND session_id = $origin_session_id AND user_id = $user_id "; |
||
7112 | $res = Database::query($sql); |
||
7113 | $list = []; |
||
7114 | while ($row = Database::fetch_assoc($res)) { |
||
7115 | $list[$row['course_access_id']] = $row; |
||
7116 | } |
||
7117 | |||
7118 | if (!empty($list)) { |
||
7119 | foreach ($list as $id => $data) { |
||
7120 | if ($update_database) { |
||
7121 | $sql = "UPDATE $TBL_TRACK_E_COURSE_ACCESS |
||
7122 | SET session_id = $new_session_id |
||
7123 | WHERE course_access_id = $id"; |
||
7124 | if ($debug) { |
||
7125 | echo $sql; |
||
7126 | } |
||
7127 | Database::query($sql); |
||
7128 | if (!isset($result_message[$TBL_TRACK_E_COURSE_ACCESS])) { |
||
7129 | $result_message[$TBL_TRACK_E_COURSE_ACCESS] = 0; |
||
7130 | } |
||
7131 | $result_message[$TBL_TRACK_E_COURSE_ACCESS]++; |
||
7132 | } |
||
7133 | } |
||
7134 | } |
||
7135 | |||
7136 | // 4. track_e_lastaccess |
||
7137 | $sql = "SELECT access_id FROM $TBL_TRACK_E_LAST_ACCESS |
||
7138 | WHERE |
||
7139 | c_id = $course_id AND |
||
7140 | session_id = $origin_session_id AND |
||
7141 | access_user_id = $user_id "; |
||
7142 | $res = Database::query($sql); |
||
7143 | $list = []; |
||
7144 | while ($row = Database::fetch_assoc($res)) { |
||
7145 | $list[] = $row['access_id']; |
||
7146 | } |
||
7147 | |||
7148 | if (!empty($list)) { |
||
7149 | foreach ($list as $id) { |
||
7150 | if ($update_database) { |
||
7151 | $sql = "UPDATE $TBL_TRACK_E_LAST_ACCESS |
||
7152 | SET session_id = $new_session_id |
||
7153 | WHERE access_id = $id"; |
||
7154 | if ($debug) { |
||
7155 | echo $sql; |
||
7156 | } |
||
7157 | Database::query($sql); |
||
7158 | if (!isset($result_message[$TBL_TRACK_E_LAST_ACCESS])) { |
||
7159 | $result_message[$TBL_TRACK_E_LAST_ACCESS] = 0; |
||
7160 | } |
||
7161 | $result_message[$TBL_TRACK_E_LAST_ACCESS]++; |
||
7162 | } |
||
7163 | } |
||
7164 | } |
||
7165 | |||
7166 | // 5. lp_item_view |
||
7167 | // CHECK ORIGIN |
||
7168 | $sql = "SELECT * FROM $TBL_LP_VIEW |
||
7169 | WHERE user_id = $user_id AND session_id = $origin_session_id AND c_id = $course_id "; |
||
7170 | $res = Database::query($sql); |
||
7171 | |||
7172 | // Getting the list of LPs in the new session |
||
7173 | $lp_list = new LearnpathList($user_id, $course_info, $new_session_id); |
||
7174 | $flat_list = $lp_list->get_flat_list(); |
||
7175 | $list = []; |
||
7176 | while ($row = Database::fetch_assoc($res)) { |
||
7177 | // Checking if the LP exist in the new session |
||
7178 | //if (in_array($row['lp_id'], array_keys($flat_list))) { |
||
7179 | $list[$row['id']] = $row; |
||
7180 | //} |
||
7181 | } |
||
7182 | |||
7183 | if (!empty($list)) { |
||
7184 | foreach ($list as $id => $data) { |
||
7185 | if ($update_database) { |
||
7186 | $sql = "UPDATE $TBL_LP_VIEW |
||
7187 | SET session_id = $new_session_id |
||
7188 | WHERE c_id = $course_id AND iid = $id "; |
||
7189 | if ($debug) { |
||
7190 | var_dump($sql); |
||
0 ignored issues
–
show
|
|||
7191 | } |
||
7192 | $res = Database::query($sql); |
||
7193 | if ($debug) { |
||
7194 | var_dump($res); |
||
7195 | } |
||
7196 | if (!isset($result_message[$TBL_LP_VIEW])) { |
||
7197 | $result_message[$TBL_LP_VIEW] = 0; |
||
7198 | } |
||
7199 | $result_message[$TBL_LP_VIEW]++; |
||
7200 | } else { |
||
7201 | // Getting all information of that lp_item_id |
||
7202 | $score = self::get_avg_student_score( |
||
7203 | $user_id, |
||
7204 | $origin_course_code, |
||
7205 | [$data['lp_id']], |
||
7206 | $origin_session_id |
||
7207 | ); |
||
7208 | $progress = self::get_avg_student_progress( |
||
7209 | $user_id, |
||
7210 | $origin_course_code, |
||
7211 | [$data['lp_id']], |
||
7212 | $origin_session_id |
||
7213 | ); |
||
7214 | $result_message['LP_VIEW'][$data['lp_id']] = [ |
||
7215 | 'score' => $score, |
||
7216 | 'progress' => $progress, |
||
7217 | ]; |
||
7218 | } |
||
7219 | } |
||
7220 | } |
||
7221 | |||
7222 | // Check destination. |
||
7223 | if (!$update_database) { |
||
7224 | $sql = "SELECT * FROM $TBL_LP_VIEW |
||
7225 | WHERE user_id = $user_id AND session_id = $new_session_id AND c_id = $course_id"; |
||
7226 | $res = Database::query($sql); |
||
7227 | |||
7228 | // Getting the list of LPs in the new session |
||
7229 | $lp_list = new LearnpathList($user_id, $course_info, $new_session_id); |
||
7230 | $flat_list = $lp_list->get_flat_list(); |
||
7231 | |||
7232 | $list = []; |
||
7233 | while ($row = Database::fetch_assoc($res)) { |
||
7234 | //Checking if the LP exist in the new session |
||
7235 | //if (in_array($row['lp_id'], array_keys($flat_list))) { |
||
7236 | $list[$row['id']] = $row; |
||
7237 | //} |
||
7238 | } |
||
7239 | |||
7240 | if (!empty($list)) { |
||
7241 | foreach ($list as $id => $data) { |
||
7242 | // Getting all information of that lp_item_id |
||
7243 | $score = self::get_avg_student_score( |
||
7244 | $user_id, |
||
7245 | $origin_course_code, |
||
7246 | [$data['lp_id']], |
||
7247 | $new_session_id |
||
7248 | ); |
||
7249 | $progress = self::get_avg_student_progress( |
||
7250 | $user_id, |
||
7251 | $origin_course_code, |
||
7252 | [$data['lp_id']], |
||
7253 | $new_session_id |
||
7254 | ); |
||
7255 | $result_message_compare['LP_VIEW'][$data['lp_id']] = [ |
||
7256 | 'score' => $score, |
||
7257 | 'progress' => $progress, |
||
7258 | ]; |
||
7259 | } |
||
7260 | } |
||
7261 | } |
||
7262 | |||
7263 | // 6. Agenda |
||
7264 | // calendar_event_attachment no problems no session_id |
||
7265 | $sql = "SELECT ref FROM $TBL_ITEM_PROPERTY |
||
7266 | WHERE tool = 'calendar_event' AND insert_user_id = $user_id AND c_id = $course_id "; |
||
7267 | $res = Database::query($sql); |
||
7268 | while ($row = Database::fetch_assoc($res)) { |
||
7269 | $id = $row['ref']; |
||
7270 | if ($update_database) { |
||
7271 | $sql = "UPDATE $TBL_AGENDA SET session_id = $new_session_id WHERE c_id = $course_id AND iid = $id "; |
||
7272 | if ($debug) { |
||
7273 | var_dump($sql); |
||
7274 | } |
||
7275 | $res_update = Database::query($sql); |
||
7276 | if ($debug) { |
||
7277 | var_dump($res_update); |
||
7278 | } |
||
7279 | if (!isset($result_message['agenda'])) { |
||
7280 | $result_message['agenda'] = 0; |
||
7281 | } |
||
7282 | $result_message['agenda']++; |
||
7283 | } |
||
7284 | } |
||
7285 | |||
7286 | // 7. Forum ?? So much problems when trying to import data |
||
7287 | // 8. Student publication - Works |
||
7288 | $sql = "SELECT ref FROM $TBL_ITEM_PROPERTY |
||
7289 | WHERE tool = 'work' AND insert_user_id = $user_id AND c_id = $course_id"; |
||
7290 | if ($debug) { |
||
7291 | echo $sql; |
||
7292 | } |
||
7293 | $res = Database::query($sql); |
||
7294 | while ($row = Database::fetch_assoc($res)) { |
||
7295 | $id = $row['ref']; |
||
7296 | $sql = "SELECT * FROM $TBL_STUDENT_PUBLICATION |
||
7297 | WHERE iid = $id AND session_id = $origin_session_id AND c_id = $course_id"; |
||
7298 | $sub_res = Database::query($sql); |
||
7299 | if (Database::num_rows($sub_res) > 0) { |
||
7300 | $data = Database::fetch_assoc($sub_res); |
||
7301 | if ($debug) { |
||
7302 | var_dump($data); |
||
7303 | } |
||
7304 | $parent_id = $data['parent_id']; |
||
7305 | if (isset($data['parent_id']) && !empty($data['parent_id'])) { |
||
7306 | $sql = "SELECT * FROM $TBL_STUDENT_PUBLICATION |
||
7307 | WHERE iid = $parent_id AND c_id = $course_id"; |
||
7308 | $select_res = Database::query($sql); |
||
7309 | $parent_data = Database::fetch_assoc($select_res); |
||
7310 | if ($debug) { |
||
7311 | var_dump($parent_data); |
||
7312 | } |
||
7313 | |||
7314 | $sys_course_path = api_get_path(SYS_COURSE_PATH); |
||
7315 | $course_dir = $sys_course_path.$course_info['path']; |
||
7316 | $base_work_dir = $course_dir.'/work'; |
||
7317 | |||
7318 | // Creating the parent folder in the session if does not exists already |
||
7319 | //@todo ugly fix |
||
7320 | $search_this = "folder_moved_from_session_id_$origin_session_id"; |
||
7321 | $search_this2 = $parent_data['url']; |
||
7322 | $sql = "SELECT * FROM $TBL_STUDENT_PUBLICATION |
||
7323 | WHERE description like '%$search_this%' AND |
||
7324 | url LIKE '%$search_this2%' AND |
||
7325 | session_id = $new_session_id AND |
||
7326 | c_id = $course_id |
||
7327 | ORDER BY id desc LIMIT 1"; |
||
7328 | if ($debug) { |
||
7329 | echo $sql; |
||
7330 | } |
||
7331 | $sub_res = Database::query($sql); |
||
7332 | $num_rows = Database::num_rows($sub_res); |
||
7333 | |||
7334 | $new_parent_id = 0; |
||
7335 | if ($num_rows > 0) { |
||
7336 | $new_result = Database::fetch_assoc($sub_res); |
||
7337 | $created_dir = $new_result['url']; |
||
7338 | $new_parent_id = $new_result['id']; |
||
7339 | } else { |
||
7340 | if ($update_database) { |
||
7341 | $dir_name = substr($parent_data['url'], 1); |
||
7342 | $created_dir = create_unexisting_work_directory($base_work_dir, $dir_name); |
||
7343 | $created_dir = '/'.$created_dir; |
||
7344 | $now = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC')); |
||
7345 | // Creating directory |
||
7346 | $publication = (new CStudentPublication()) |
||
7347 | ->setTitle($parent_data['title']) |
||
7348 | ->setDescription( |
||
7349 | $parent_data['description']."folder_moved_from_session_id_$origin_session_id" |
||
7350 | ) |
||
7351 | ->setActive(false) |
||
7352 | ->setAccepted(true) |
||
7353 | ->setPostGroupId(0) |
||
7354 | ->setHasProperties($parent_data['has_properties']) |
||
7355 | ->setWeight($parent_data['weight']) |
||
7356 | ->setContainsFile($parent_data['contains_file']) |
||
7357 | ->setFiletype('folder') |
||
7358 | ->setSentDate($now) |
||
7359 | ->setQualification($parent_data['qualification']) |
||
7360 | ->setParentId(0) |
||
7361 | ->setQualificatorId(0) |
||
7362 | ->setUserId($parent_data['user_id']) |
||
7363 | ->setAllowTextAssignment($parent_data['allow_text_assignment']) |
||
7364 | ->setSession($session); |
||
7365 | |||
7366 | $publication->setDocumentId($parent_data['document_id']); |
||
7367 | |||
7368 | Database::getManager()->persist($publication); |
||
7369 | Database::getManager()->flush(); |
||
7370 | $id = $publication->getIid(); |
||
7371 | //Folder created |
||
7372 | //api_item_property_update($course_info, 'work', $id, 'DirectoryCreated', api_get_user_id()); |
||
7373 | $new_parent_id = $id; |
||
7374 | if (!isset($result_message[$TBL_STUDENT_PUBLICATION.' - new folder created called: '.$created_dir])) { |
||
7375 | $result_message[$TBL_STUDENT_PUBLICATION.' - new folder created called: '.$created_dir] = 0; |
||
7376 | } |
||
7377 | $result_message[$TBL_STUDENT_PUBLICATION.' - new folder created called: '.$created_dir]++; |
||
7378 | } |
||
7379 | } |
||
7380 | |||
7381 | //Creating student_publication_assignment if exists |
||
7382 | $sql = "SELECT * FROM $TBL_STUDENT_PUBLICATION_ASSIGNMENT |
||
7383 | WHERE publication_id = $parent_id AND c_id = $course_id"; |
||
7384 | if ($debug) { |
||
7385 | var_dump($sql); |
||
7386 | } |
||
7387 | $rest_select = Database::query($sql); |
||
7388 | if (Database::num_rows($rest_select) > 0) { |
||
7389 | if ($update_database && $new_parent_id) { |
||
7390 | $assignment_data = Database::fetch_assoc($rest_select); |
||
7391 | $sql_add_publication = "INSERT INTO ".$TBL_STUDENT_PUBLICATION_ASSIGNMENT." SET |
||
7392 | c_id = '$course_id', |
||
7393 | expires_on = '".$assignment_data['expires_on']."', |
||
7394 | ends_on = '".$assignment_data['ends_on']."', |
||
7395 | add_to_calendar = '".$assignment_data['add_to_calendar']."', |
||
7396 | enable_qualification = '".$assignment_data['enable_qualification']."', |
||
7397 | publication_id = '".$new_parent_id."'"; |
||
7398 | if ($debug) { |
||
7399 | echo $sql_add_publication; |
||
7400 | } |
||
7401 | Database::query($sql_add_publication); |
||
7402 | $id = (int) Database::insert_id(); |
||
7403 | if ($id) { |
||
7404 | $sql_update = "UPDATE $TBL_STUDENT_PUBLICATION |
||
7405 | SET has_properties = '".$id."', |
||
7406 | view_properties = '1' |
||
7407 | WHERE iid = ".$new_parent_id; |
||
7408 | if ($debug) { |
||
7409 | echo $sql_update; |
||
7410 | } |
||
7411 | Database::query($sql_update); |
||
7412 | if (!isset($result_message[$TBL_STUDENT_PUBLICATION_ASSIGNMENT])) { |
||
7413 | $result_message[$TBL_STUDENT_PUBLICATION_ASSIGNMENT] = 0; |
||
7414 | } |
||
7415 | $result_message[$TBL_STUDENT_PUBLICATION_ASSIGNMENT]++; |
||
7416 | } |
||
7417 | } |
||
7418 | } |
||
7419 | |||
7420 | $doc_url = $data['url']; |
||
7421 | $new_url = str_replace($parent_data['url'], $created_dir, $doc_url); |
||
7422 | |||
7423 | if ($update_database) { |
||
7424 | // Creating a new work |
||
7425 | $data['sent_date'] = new DateTime($data['sent_date'], new DateTimeZone('UTC')); |
||
7426 | |||
7427 | $data['post_group_id'] = (int) $data['post_group_id']; |
||
7428 | $publication = (new CStudentPublication()) |
||
7429 | ->setTitle($data['title']) |
||
7430 | ->setDescription($data['description'].' file moved') |
||
7431 | ->setActive($data['active']) |
||
7432 | ->setAccepted($data['accepted']) |
||
7433 | ->setPostGroupId($data['post_group_id']) |
||
7434 | ->setSentDate($data['sent_date']) |
||
7435 | ->setParentId($new_parent_id) |
||
7436 | ->setWeight($data['weight']) |
||
7437 | ->setHasProperties(0) |
||
7438 | ->setWeight($data['weight']) |
||
7439 | ->setContainsFile($data['contains_file']) |
||
7440 | ->setSession($session) |
||
7441 | ->setUserId($data['user_id']) |
||
7442 | ->setFiletype('file') |
||
7443 | ->setDocumentId(0) |
||
7444 | ; |
||
7445 | |||
7446 | $em->persist($publication); |
||
7447 | $em->flush(); |
||
7448 | |||
7449 | $id = $publication->getIid(); |
||
7450 | /*api_item_property_update( |
||
7451 | $course_info, |
||
7452 | 'work', |
||
7453 | $id, |
||
7454 | 'DocumentAdded', |
||
7455 | $user_id, |
||
7456 | null, |
||
7457 | null, |
||
7458 | null, |
||
7459 | null, |
||
7460 | $new_session_id |
||
7461 | );*/ |
||
7462 | if (!isset($result_message[$TBL_STUDENT_PUBLICATION])) { |
||
7463 | $result_message[$TBL_STUDENT_PUBLICATION] = 0; |
||
7464 | } |
||
7465 | $result_message[$TBL_STUDENT_PUBLICATION]++; |
||
7466 | $full_file_name = $course_dir.'/'.$doc_url; |
||
7467 | $new_file = $course_dir.'/'.$new_url; |
||
7468 | |||
7469 | if (file_exists($full_file_name)) { |
||
7470 | // deleting old assignment |
||
7471 | $result = copy($full_file_name, $new_file); |
||
7472 | if ($result) { |
||
7473 | unlink($full_file_name); |
||
7474 | if (isset($data['id'])) { |
||
7475 | $sql = "DELETE FROM $TBL_STUDENT_PUBLICATION WHERE id= ".$data['id']; |
||
7476 | if ($debug) { |
||
7477 | var_dump($sql); |
||
7478 | } |
||
7479 | Database::query($sql); |
||
7480 | } |
||
7481 | api_item_property_update( |
||
7482 | $course_info, |
||
7483 | 'work', |
||
7484 | $data['id'], |
||
7485 | 'DocumentDeleted', |
||
7486 | api_get_user_id() |
||
7487 | ); |
||
7488 | } |
||
7489 | } |
||
7490 | } |
||
7491 | } |
||
7492 | } |
||
7493 | } |
||
7494 | |||
7495 | //9. Survey Pending |
||
7496 | //10. Dropbox - not neccesary to move categories (no presence of session_id) |
||
7497 | $sql = "SELECT id FROM $TBL_DROPBOX_FILE |
||
7498 | WHERE uploader_id = $user_id AND session_id = $origin_session_id AND c_id = $course_id"; |
||
7499 | if ($debug) { |
||
7500 | var_dump($sql); |
||
7501 | } |
||
7502 | $res = Database::query($sql); |
||
7503 | while ($row = Database::fetch_assoc($res)) { |
||
7504 | $id = (int) $row['id']; |
||
7505 | if ($update_database) { |
||
7506 | $sql = "UPDATE $TBL_DROPBOX_FILE SET session_id = $new_session_id WHERE c_id = $course_id AND iid = $id"; |
||
7507 | if ($debug) { |
||
7508 | var_dump($sql); |
||
7509 | } |
||
7510 | Database::query($sql); |
||
7511 | if ($debug) { |
||
7512 | var_dump($res); |
||
7513 | } |
||
7514 | |||
7515 | $sql = "UPDATE $TBL_DROPBOX_POST SET session_id = $new_session_id WHERE file_id = $id"; |
||
7516 | if ($debug) { |
||
7517 | var_dump($sql); |
||
7518 | } |
||
7519 | Database::query($sql); |
||
7520 | if ($debug) { |
||
7521 | var_dump($res); |
||
7522 | } |
||
7523 | if (!isset($result_message[$TBL_DROPBOX_FILE])) { |
||
7524 | $result_message[$TBL_DROPBOX_FILE] = 0; |
||
7525 | } |
||
7526 | $result_message[$TBL_DROPBOX_FILE]++; |
||
7527 | } |
||
7528 | } |
||
7529 | |||
7530 | // 11. Notebook |
||
7531 | /*$sql = "SELECT notebook_id FROM $TBL_NOTEBOOK |
||
7532 | WHERE |
||
7533 | user_id = $user_id AND |
||
7534 | session_id = $origin_session_id AND |
||
7535 | course = '$origin_course_code' AND |
||
7536 | c_id = $course_id"; |
||
7537 | if ($debug) { |
||
7538 | var_dump($sql); |
||
7539 | } |
||
7540 | $res = Database::query($sql); |
||
7541 | while ($row = Database::fetch_assoc($res)) { |
||
7542 | $id = $row['notebook_id']; |
||
7543 | if ($update_database) { |
||
7544 | $sql = "UPDATE $TBL_NOTEBOOK |
||
7545 | SET session_id = $new_session_id |
||
7546 | WHERE c_id = $course_id AND notebook_id = $id"; |
||
7547 | if ($debug) { |
||
7548 | var_dump($sql); |
||
7549 | } |
||
7550 | $res = Database::query($sql); |
||
7551 | if ($debug) { |
||
7552 | var_dump($res); |
||
7553 | } |
||
7554 | } |
||
7555 | }*/ |
||
7556 | |||
7557 | if ($update_database) { |
||
7558 | echo Display::return_message(get_lang('StatsMoved')); |
||
7559 | if (is_array($result_message)) { |
||
7560 | foreach ($result_message as $table => $times) { |
||
7561 | echo 'Table '.$table.' - '.$times.' records updated <br />'; |
||
7562 | } |
||
7563 | } |
||
7564 | } else { |
||
7565 | echo '<h4>'.get_lang('UserInformationOfThisCourse').'</h4>'; |
||
7566 | echo '<br />'; |
||
7567 | echo '<table class="table" width="100%">'; |
||
7568 | echo '<tr>'; |
||
7569 | echo '<td width="50%" valign="top">'; |
||
7570 | |||
7571 | if (0 == $origin_session_id) { |
||
7572 | echo '<h5>'.get_lang('OriginCourse').'</h5>'; |
||
7573 | } else { |
||
7574 | echo '<h5>'.get_lang('OriginSession').' #'.$origin_session_id.'</h5>'; |
||
7575 | } |
||
7576 | self::compareUserData($result_message); |
||
7577 | echo '</td>'; |
||
7578 | echo '<td width="50%" valign="top">'; |
||
7579 | if (0 == $new_session_id) { |
||
7580 | echo '<h5>'.get_lang('DestinyCourse').'</h5>'; |
||
7581 | } else { |
||
7582 | echo '<h5>'.get_lang('DestinySession').' #'.$new_session_id.'</h5>'; |
||
7583 | } |
||
7584 | self::compareUserData($result_message_compare); |
||
7585 | echo '</td>'; |
||
7586 | echo '</tr>'; |
||
7587 | echo '</table>'; |
||
7588 | } |
||
7589 | } |
||
7590 | |||
7591 | public static function compareUserData($result_message) |
||
7592 | { |
||
7593 | foreach ($result_message as $table => $data) { |
||
7594 | $title = $table; |
||
7595 | if ('TRACK_E_EXERCISES' === $table) { |
||
7596 | $title = get_lang('Exercises'); |
||
7597 | } elseif ('TRACK_E_EXERCISES_IN_LP' === $table) { |
||
7598 | $title = get_lang('ExercisesInLp'); |
||
7599 | } elseif ('LP_VIEW' === $table) { |
||
7600 | $title = get_lang('LearningPaths'); |
||
7601 | } |
||
7602 | echo '<br / ><h3>'.get_lang($title).' </h3><hr />'; |
||
7603 | |||
7604 | if (is_array($data)) { |
||
7605 | foreach ($data as $id => $item) { |
||
7606 | if ('TRACK_E_EXERCISES' === $table || 'TRACK_E_EXERCISES_IN_LP' === $table) { |
||
7607 | echo "<br /><h3>".get_lang('Attempt')." #$id</h3>"; |
||
7608 | echo '<h3>'; |
||
7609 | echo get_lang('Exercise').' #'.$item['exe_exo_id']; |
||
7610 | echo '</h3>'; |
||
7611 | if (!empty($item['orig_lp_id'])) { |
||
7612 | echo '<h3>'; |
||
7613 | echo get_lang('LearningPath').' #'.$item['orig_lp_id']; |
||
7614 | echo '</h3>'; |
||
7615 | } |
||
7616 | // Process data. |
||
7617 | $array = [ |
||
7618 | 'exe_date' => get_lang('Date'), |
||
7619 | 'score' => get_lang('Score'), |
||
7620 | 'max_score' => get_lang('Weighting'), |
||
7621 | ]; |
||
7622 | foreach ($item as $key => $value) { |
||
7623 | if (in_array($key, array_keys($array))) { |
||
7624 | $key = $array[$key]; |
||
7625 | echo "$key = $value <br />"; |
||
7626 | } |
||
7627 | } |
||
7628 | } else { |
||
7629 | echo "<br /><h3>".get_lang('Id')." #$id</h3>"; |
||
7630 | // process data |
||
7631 | foreach ($item as $key => $value) { |
||
7632 | echo "$key = $value <br />"; |
||
7633 | } |
||
7634 | } |
||
7635 | } |
||
7636 | } else { |
||
7637 | echo get_lang('NoResults'); |
||
7638 | } |
||
7639 | } |
||
7640 | } |
||
7641 | |||
7642 | private static function generateQuizzesTable(array $courseInfo, int $sessionId = 0): string |
||
7643 | { |
||
7644 | if (empty($sessionId)) { |
||
7645 | $userList = CourseManager::get_user_list_from_course_code( |
||
7646 | $courseInfo['code'], |
||
7647 | $sessionId, |
||
7648 | null, |
||
7649 | null, |
||
7650 | STUDENT |
||
7651 | ); |
||
7652 | } else { |
||
7653 | $userList = CourseManager::get_user_list_from_course_code($courseInfo['code'], $sessionId, null, null, 0); |
||
7654 | } |
||
7655 | |||
7656 | $exerciseList = ExerciseLib::get_all_exercises($courseInfo, $sessionId, false, null); |
||
7657 | |||
7658 | if (empty($exerciseList)) { |
||
7659 | return Display::return_message(get_lang('NoEx')); |
||
7660 | } |
||
7661 | |||
7662 | $toGraphExerciseResult = []; |
||
7663 | |||
7664 | $quizzesTable = new SortableTableFromArray([], 0, 0, 'quizzes'); |
||
7665 | $quizzesTable->setHeaders( |
||
7666 | [ |
||
7667 | get_lang('Exercises'), |
||
7668 | get_lang('Attempts'), |
||
7669 | get_lang('BestAttempt'), |
||
7670 | get_lang('Ranking'), |
||
7671 | get_lang('BestResultInCourse'), |
||
7672 | get_lang('Statistics').Display::getMdiIcon( |
||
7673 | ActionIcon::INFORMATION, |
||
7674 | 'ch-tool-icon', |
||
7675 | null, |
||
7676 | ICON_SIZE_SMALL, |
||
7677 | get_lang('OnlyBestResultsPerStudent') |
||
7678 | ), |
||
7679 | ] |
||
7680 | ); |
||
7681 | |||
7682 | $webCodePath = api_get_path(WEB_CODE_PATH); |
||
7683 | |||
7684 | foreach ($exerciseList as $exercices) { |
||
7685 | $objExercise = new Exercise($courseInfo['real_id']); |
||
7686 | $objExercise->read($exercices['id']); |
||
7687 | $visibleReturn = $objExercise->is_visible(); |
||
7688 | |||
7689 | // Getting count of attempts by user |
||
7690 | $attempts = Event::count_exercise_attempts_by_user( |
||
7691 | api_get_user_id(), |
||
7692 | $exercices['id'], |
||
7693 | $courseInfo['real_id'], |
||
7694 | $sessionId |
||
7695 | ); |
||
7696 | |||
7697 | $url = $webCodePath.'exercise/overview.php?' |
||
7698 | .http_build_query( |
||
7699 | ['cidReq' => $courseInfo['code'], 'id_session' => $sessionId, 'exerciseId' => $exercices['id']] |
||
7700 | ); |
||
7701 | |||
7702 | if (true == $visibleReturn['value']) { |
||
7703 | $exercices['title'] = Display::url( |
||
7704 | $exercices['title'], |
||
7705 | $url, |
||
7706 | ['target' => SESSION_LINK_TARGET] |
||
7707 | ); |
||
7708 | } elseif (-1 == $exercices['active']) { |
||
7709 | $exercices['title'] = sprintf(get_lang('XParenthesisDeleted'), $exercices['title']); |
||
7710 | } |
||
7711 | |||
7712 | $quizData = [ |
||
7713 | $exercices['title'], |
||
7714 | $attempts, |
||
7715 | '-', |
||
7716 | '-', |
||
7717 | '-', |
||
7718 | '-', |
||
7719 | ]; |
||
7720 | |||
7721 | // Exercise configuration show results or show only score |
||
7722 | if (!in_array($exercices['results_disabled'], [0, 2]) |
||
7723 | || empty($attempts) |
||
7724 | ) { |
||
7725 | $quizzesTable->addRow($quizData); |
||
7726 | |||
7727 | continue; |
||
7728 | } |
||
7729 | |||
7730 | //For graphics |
||
7731 | $bestExerciseAttempts = Event::get_best_exercise_results_by_user( |
||
7732 | $exercices['id'], |
||
7733 | $courseInfo['real_id'], |
||
7734 | $sessionId |
||
7735 | ); |
||
7736 | |||
7737 | $toGraphExerciseResult[$exercices['id']] = [ |
||
7738 | 'title' => $exercices['title'], |
||
7739 | 'data' => $bestExerciseAttempts, |
||
7740 | ]; |
||
7741 | |||
7742 | // Getting best results |
||
7743 | $bestScoreData = ExerciseLib::get_best_attempt_in_course( |
||
7744 | $exercices['id'], |
||
7745 | $courseInfo['real_id'], |
||
7746 | $sessionId |
||
7747 | ); |
||
7748 | |||
7749 | if (!empty($bestScoreData)) { |
||
7750 | $quizData[5] = ExerciseLib::show_score( |
||
7751 | $bestScoreData['score'], |
||
7752 | $bestScoreData['max_score'] |
||
7753 | ); |
||
7754 | } |
||
7755 | |||
7756 | $exerciseAttempt = ExerciseLib::get_best_attempt_by_user( |
||
7757 | api_get_user_id(), |
||
7758 | $exercices['id'], |
||
7759 | $courseInfo['real_id'], |
||
7760 | $sessionId |
||
7761 | ); |
||
7762 | |||
7763 | if (!empty($exerciseAttempt)) { |
||
7764 | // Always getting the BEST attempt |
||
7765 | $score = $exerciseAttempt['score']; |
||
7766 | $weighting = $exerciseAttempt['max_score']; |
||
7767 | $exeId = $exerciseAttempt['exe_id']; |
||
7768 | |||
7769 | $latestAttemptUrl = $webCodePath.'exercise/result.php?' |
||
7770 | .http_build_query( |
||
7771 | [ |
||
7772 | 'id' => $exeId, |
||
7773 | 'cidReq' => $courseInfo['code'], |
||
7774 | 'show_headers' => 1, |
||
7775 | 'id_session' => $sessionId, |
||
7776 | ] |
||
7777 | ); |
||
7778 | |||
7779 | $quizData[3] = Display::url( |
||
7780 | ExerciseLib::show_score($score, $weighting), |
||
7781 | $latestAttemptUrl |
||
7782 | ); |
||
7783 | |||
7784 | $myScore = !empty($weighting) && 0 != intval($weighting) ? $score / $weighting : 0; |
||
7785 | |||
7786 | //@todo this function slows the page |
||
7787 | if (is_int($userList)) { |
||
7788 | $userList = [$userList]; |
||
7789 | } |
||
7790 | |||
7791 | $quizData[4] = ExerciseLib::get_exercise_result_ranking( |
||
7792 | $myScore, |
||
7793 | $exeId, |
||
7794 | $exercices['id'], |
||
7795 | $courseInfo['code'], |
||
7796 | $sessionId, |
||
7797 | $userList |
||
7798 | ); |
||
7799 | $graph = self::generate_exercise_result_thumbnail_graph($toGraphExerciseResult[$exercices['id']]); |
||
7800 | $normalGraph = self::generate_exercise_result_graph($toGraphExerciseResult[$exercices['id']]); |
||
7801 | |||
7802 | $quizData[6] = Display::url( |
||
7803 | Display::img($graph, '', [], false), |
||
7804 | $normalGraph, |
||
7805 | ['id' => $exercices['id'], 'class' => 'expand-image'] |
||
7806 | ); |
||
7807 | } |
||
7808 | |||
7809 | $quizzesTable->addRow($quizData); |
||
7810 | } |
||
7811 | |||
7812 | return Display::div( |
||
7813 | $quizzesTable->toHtml(), |
||
7814 | ['class' => 'table-responsive'] |
||
7815 | ); |
||
7816 | } |
||
7817 | |||
7818 | private static function generateLearningPathsTable(int $userId, array $courseInfo, int $sessionId = 0): string |
||
7819 | { |
||
7820 | $columnHeaders = [ |
||
7821 | 'lp' => get_lang('LearningPath'), |
||
7822 | 'time' => get_lang('LatencyTimeSpent'), |
||
7823 | 'progress' => get_lang('Progress'), |
||
7824 | 'score' => get_lang('Score'), |
||
7825 | 'best_score' => get_lang('BestScore'), |
||
7826 | 'last_connection' => get_lang('LastConnexion'), |
||
7827 | ]; |
||
7828 | |||
7829 | $trackingColumns = api_get_setting('session.tracking_columns', true); |
||
7830 | |||
7831 | if (isset($trackingColumns['my_progress_lp'])) { |
||
7832 | $columnHeaders = array_filter( |
||
7833 | $columnHeaders, |
||
7834 | function ($columHeader, $key) use ($trackingColumns) { |
||
7835 | if (!isset($trackingColumns['my_progress_lp'][$key]) |
||
7836 | || false == $trackingColumns['my_progress_lp'][$key] |
||
7837 | ) { |
||
7838 | return false; |
||
7839 | } |
||
7840 | |||
7841 | return true; |
||
7842 | }, |
||
7843 | ARRAY_FILTER_USE_BOTH |
||
7844 | ); |
||
7845 | } |
||
7846 | |||
7847 | if (true === api_get_configuration_value('student_follow_page_add_LP_subscription_info')) { |
||
7848 | $columnHeaders['student_follow_page_add_LP_subscription_info'] = get_lang('Unlock'); |
||
7849 | } |
||
7850 | |||
7851 | if ('true' === api_get_setting('lp.student_follow_page_add_lp_acquisition_info')) { |
||
7852 | $columnHeaders['student_follow_page_add_lp_acquisition_info'] = get_lang('Acquisition'); |
||
7853 | } |
||
7854 | |||
7855 | $addLpInvisibleCheckbox = api_get_setting('lp.student_follow_page_add_lp_invisible_checkbox'); |
||
7856 | |||
7857 | $columnHeadersKeys = array_keys($columnHeaders); |
||
7858 | |||
7859 | $learningpathsTable = new SortableTableFromArray([], 0, 0, 'learningpaths'); |
||
7860 | $learningpathsTable->setHeaders($columnHeaders); |
||
7861 | |||
7862 | // LP table results |
||
7863 | $list = new LearnpathList( |
||
7864 | api_get_user_id(), |
||
7865 | $courseInfo, |
||
7866 | $sessionId, |
||
7867 | 'resource.publishedOn ASC', |
||
7868 | true, |
||
7869 | null, |
||
7870 | true |
||
7871 | ); |
||
7872 | |||
7873 | $lpList = $list->get_flat_list(); |
||
7874 | |||
7875 | if (empty($lpList)) { |
||
7876 | return Display::return_message(get_lang('NoLearnpath')); |
||
7877 | } |
||
7878 | |||
7879 | $webCodePath = api_get_path(WEB_CODE_PATH); |
||
7880 | |||
7881 | foreach ($lpList as $lpId => $learnpath) { |
||
7882 | $learningpathData = []; |
||
7883 | |||
7884 | if (!$learnpath['lp_visibility']) { |
||
7885 | continue; |
||
7886 | } |
||
7887 | |||
7888 | if ($addLpInvisibleCheckbox) { |
||
7889 | if (!StudentFollowPage::isViewVisible($lpId, $userId, $courseInfo['real_id'], $sessionId)) { |
||
7890 | continue; |
||
7891 | } |
||
7892 | } |
||
7893 | |||
7894 | $url = $webCodePath.'lp/lp_controller.php?' |
||
7895 | .http_build_query( |
||
7896 | ['cidReq' => $courseInfo['code'], 'id_session' => $sessionId, 'lp_id' => $lpId, 'action' => 'view'] |
||
7897 | ); |
||
7898 | |||
7899 | if (in_array('lp', $columnHeadersKeys)) { |
||
7900 | if (0 == $learnpath['lp_visibility']) { |
||
7901 | $learningpathData[] = $learnpath['lp_name']; |
||
7902 | } else { |
||
7903 | $learningpathData[] = Display::url( |
||
7904 | $learnpath['lp_name'], |
||
7905 | $url, |
||
7906 | ['target' => SESSION_LINK_TARGET] |
||
7907 | ); |
||
7908 | } |
||
7909 | } |
||
7910 | |||
7911 | if (in_array('time', $columnHeadersKeys)) { |
||
7912 | $time_spent_in_lp = self::get_time_spent_in_lp( |
||
7913 | $userId, |
||
7914 | $courseInfo['code'], |
||
7915 | [$lpId], |
||
7916 | $sessionId |
||
7917 | ); |
||
7918 | |||
7919 | $learningpathData[] = api_time_to_hms($time_spent_in_lp); |
||
7920 | } |
||
7921 | |||
7922 | if (in_array('progress', $columnHeadersKeys)) { |
||
7923 | $progress = self::get_avg_student_progress( |
||
7924 | $userId, |
||
7925 | $courseInfo['code'], |
||
7926 | [$lpId], |
||
7927 | $sessionId |
||
7928 | ); |
||
7929 | |||
7930 | if (is_numeric($progress)) { |
||
7931 | $progress = sprintf(get_lang('XPercent'), $progress); |
||
7932 | } |
||
7933 | |||
7934 | $learningpathData[] = $progress; |
||
7935 | } |
||
7936 | |||
7937 | if (in_array('score', $columnHeadersKeys)) { |
||
7938 | $percentage_score = self::get_avg_student_score( |
||
7939 | $userId, |
||
7940 | $courseInfo['code'], |
||
7941 | [$lpId], |
||
7942 | $sessionId |
||
7943 | ); |
||
7944 | |||
7945 | if (is_numeric($percentage_score)) { |
||
7946 | $percentage_score = sprintf(get_lang('XPercent'), $percentage_score); |
||
7947 | } else { |
||
7948 | $percentage_score = sprintf(get_lang('XPercent'), 0); |
||
7949 | } |
||
7950 | |||
7951 | $learningpathData[] = $percentage_score; |
||
7952 | } |
||
7953 | |||
7954 | if (in_array('best_score', $columnHeadersKeys)) { |
||
7955 | $bestScore = self::get_avg_student_score( |
||
7956 | $userId, |
||
7957 | $courseInfo['code'], |
||
7958 | [$lpId], |
||
7959 | $sessionId, |
||
7960 | false, |
||
7961 | false, |
||
7962 | true |
||
7963 | ); |
||
7964 | |||
7965 | if (is_numeric($bestScore)) { |
||
7966 | $bestScore = sprintf(get_lang('XPercent'), $bestScore); |
||
7967 | } else { |
||
7968 | $bestScore = '-'; |
||
7969 | } |
||
7970 | |||
7971 | $learningpathData[] = $bestScore; |
||
7972 | } |
||
7973 | |||
7974 | if (in_array('last_connection', $columnHeadersKeys)) { |
||
7975 | $lastConnectionInLp = self::get_last_connection_time_in_lp( |
||
7976 | $userId, |
||
7977 | $courseInfo['code'], |
||
7978 | $lpId, |
||
7979 | $sessionId |
||
7980 | ); |
||
7981 | |||
7982 | $lastConnection = '-'; |
||
7983 | |||
7984 | if (!empty($lastConnectionInLp)) { |
||
7985 | $lastConnection = api_convert_and_format_date($lastConnectionInLp, DATE_TIME_FORMAT_LONG); |
||
7986 | } |
||
7987 | |||
7988 | $learningpathData[] = $lastConnection; |
||
7989 | } |
||
7990 | |||
7991 | if (in_array('student_follow_page_add_LP_subscription_info', $columnHeadersKeys)) { |
||
7992 | $learningpathData[] = StudentFollowPage::getLpSubscription( |
||
7993 | $learnpath, |
||
7994 | $userId, |
||
7995 | $courseInfo['real_id'], |
||
7996 | $sessionId |
||
7997 | ); |
||
7998 | } |
||
7999 | |||
8000 | if (in_array('student_follow_page_add_lp_acquisition_info', $columnHeadersKeys)) { |
||
8001 | $learningpathData[] = StudentFollowPage::getLpAcquisition( |
||
8002 | $learnpath, |
||
8003 | $userId, |
||
8004 | $courseInfo['real_id'], |
||
8005 | $sessionId |
||
8006 | ); |
||
8007 | } |
||
8008 | |||
8009 | $learningpathsTable->addRow($learningpathData); |
||
8010 | } |
||
8011 | |||
8012 | return Display::div( |
||
8013 | $learningpathsTable->toHtml(), |
||
8014 | ['class' => 'table-responsive'] |
||
8015 | ); |
||
8016 | } |
||
8017 | |||
8018 | /** |
||
8019 | * Counts the number of student publications for a given course, session, and group. |
||
8020 | * |
||
8021 | * @param int $courseId |
||
8022 | * @param int|null $sessionId |
||
8023 | * @param int|null $groupId |
||
8024 | * |
||
8025 | * @return int The number of student publications. |
||
8026 | */ |
||
8027 | public static function countStudentPublications(int $courseId, ?int $sessionId = null, ?int $groupId = null): int |
||
8028 | { |
||
8029 | $repo = Container::getStudentPublicationRepository(); |
||
8030 | |||
8031 | $course = api_get_course_entity($courseId); |
||
8032 | $session = api_get_session_entity($sessionId); |
||
8033 | $group = api_get_group_entity($groupId); |
||
8034 | |||
8035 | $qb = $repo->getResourcesByCourse($course, $session, $group); |
||
8036 | $qb->select('COUNT(resource.iid)'); |
||
8037 | |||
8038 | return (int) $qb->getQuery()->getSingleScalarResult(); |
||
8039 | } |
||
8040 | |||
8041 | /** |
||
8042 | * Counts the number of forum posts for a given course, session, and group. |
||
8043 | * |
||
8044 | * @param int $courseId |
||
8045 | * @param int|null $sessionId |
||
8046 | * @param int|null $groupId |
||
8047 | * |
||
8048 | * @return int The number of forum posts. |
||
8049 | */ |
||
8050 | public static function countStudentMessages(int $courseId, ?int $sessionId = null, ?int $groupId = null): int |
||
8051 | { |
||
8052 | $repo = Container::getForumPostRepository(); |
||
8053 | |||
8054 | $course = api_get_course_entity($courseId); |
||
8055 | $session = api_get_session_entity($sessionId); |
||
8056 | $group = api_get_group_entity($groupId); |
||
8057 | |||
8058 | $qb = $repo->getResourcesByCourse($course, $session, $group); |
||
8059 | $qb->select('COUNT(resource.iid)'); |
||
8060 | |||
8061 | return (int) $qb->getQuery()->getSingleScalarResult(); |
||
8062 | } |
||
8063 | |||
8064 | /** |
||
8065 | * It gets the last finalization date of learnpaths in a course. |
||
8066 | * |
||
8067 | * @return string finalization date formatted or false if it is empty. |
||
8068 | */ |
||
8069 | public static function getCourseLpFinalizationDate( |
||
8070 | int $userId, |
||
8071 | int $courseId, |
||
8072 | int $sessionId, |
||
8073 | bool $convertDate = true |
||
8074 | ) { |
||
8075 | $tblLpView = Database::get_course_table(TABLE_LP_VIEW); |
||
8076 | $tblLpItem = Database::get_course_table(TABLE_LP_ITEM); |
||
8077 | $tblLpItemView = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
8078 | |||
8079 | $sql = "SELECT FROM_UNIXTIME(liv.start_time) as start_date |
||
8080 | FROM $tblLpItemView liv |
||
8081 | INNER JOIN |
||
8082 | $tblLpView lv ON lv.iid = liv.lp_view_id |
||
8083 | INNER JOIN |
||
8084 | $tblLpItem li ON li.iid = liv.lp_item_id |
||
8085 | WHERE |
||
8086 | lv.user_id = $userId AND |
||
8087 | lv.c_id = $courseId AND |
||
8088 | lv.session_id = $sessionId AND |
||
8089 | li.item_type = '".TOOL_LP_FINAL_ITEM."' AND |
||
8090 | liv.status = 'completed' |
||
8091 | ORDER BY start_date DESC |
||
8092 | LIMIT 1"; |
||
8093 | |||
8094 | $rs = Database::query($sql); |
||
8095 | $lpFinalDate = Database::result($rs, 0, 0); |
||
8096 | |||
8097 | if (empty($lpFinalDate)) { |
||
8098 | return false; |
||
8099 | } |
||
8100 | |||
8101 | if ($convertDate) { |
||
8102 | return api_convert_and_format_date($lpFinalDate, DATE_FORMAT_SHORT); |
||
8103 | } |
||
8104 | |||
8105 | return $lpFinalDate; |
||
8106 | } |
||
8107 | |||
8108 | /** |
||
8109 | * It gets the last finalization date of exercises in a course. |
||
8110 | * |
||
8111 | * @return string finalization date formatted or false if it is empty. |
||
8112 | */ |
||
8113 | public static function getCourseQuizLastFinalizationDate( |
||
8114 | int $userId, |
||
8115 | int $courseId, |
||
8116 | int $sessionId, |
||
8117 | bool $convertDate = true |
||
8118 | ) { |
||
8119 | $tblTrackExercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
8120 | |||
8121 | $sql = "SELECT ex.exe_date |
||
8122 | FROM $tblTrackExercise AS ex |
||
8123 | WHERE |
||
8124 | ex.c_id = $courseId AND |
||
8125 | ex.session_id = $sessionId AND |
||
8126 | ex.exe_user_id = $userId AND |
||
8127 | ex.status = '' |
||
8128 | ORDER BY ex.exe_date DESC |
||
8129 | LIMIT 1"; |
||
8130 | $rs = Database::query($sql); |
||
8131 | $exeDate = Database::result($rs, 0, 0); |
||
8132 | |||
8133 | if (empty($exeDate)) { |
||
8134 | return false; |
||
8135 | } |
||
8136 | |||
8137 | if ($convertDate) { |
||
8138 | return api_convert_and_format_date($exeDate, DATE_FORMAT_SHORT); |
||
8139 | } |
||
8140 | |||
8141 | return $exeDate; |
||
8142 | } |
||
8143 | |||
8144 | /** |
||
8145 | * Return the total time spent in courses (no the total in platform). |
||
8146 | * |
||
8147 | * @return int |
||
8148 | * @throws \Doctrine\DBAL\Exception |
||
8149 | * @throws Exception |
||
8150 | */ |
||
8151 | public static function getTotalTimeSpentInCourses( |
||
8152 | string $dateFrom = '', |
||
8153 | string $dateUntil = '' |
||
8154 | ): int { |
||
8155 | $tableTrackLogin = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
8156 | $tableUrlRelUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); |
||
8157 | $tableUrl = null; |
||
8158 | $urlCondition = null; |
||
8159 | $conditionTime = null; |
||
8160 | $accessUrlUtil = Container::getAccessUrlUtil(); |
||
8161 | if ($accessUrlUtil->isMultiple()) { |
||
8162 | $accessUrlId = $accessUrlUtil->getCurrent()->getId(); |
||
8163 | $tableUrl = ", ".$tableUrlRelUser." as url_users"; |
||
8164 | $urlCondition = " AND u.user_id = url_users.user_id AND access_url_id = $accessUrlId"; |
||
8165 | } |
||
8166 | if (!empty($dateFrom) && !empty($dateUntil)) { |
||
8167 | $dateFrom = Database::escape_string($dateFrom); |
||
8168 | $dateUntil = Database::escape_string($dateUntil); |
||
8169 | $conditionTime = " (login_course_date >= '$dateFrom' AND logout_course_date <= '$dateUntil' ) "; |
||
8170 | } |
||
8171 | $sql = "SELECT SUM(TIMESTAMPDIFF(HOUR, login_course_date, logout_course_date)) diff |
||
8172 | FROM $tableTrackLogin u $tableUrl |
||
8173 | WHERE $conditionTime $urlCondition"; |
||
8174 | $rs = Database::query($sql); |
||
8175 | $row = Database::fetch_array($rs, 'ASSOC'); |
||
8176 | $diff = $row['diff']; |
||
8177 | if ($diff >= 0 and !empty($diff)) { |
||
8178 | return $diff; |
||
8179 | } |
||
8180 | return 0; |
||
8181 | } |
||
8182 | } |
||
8183 |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.