Completed
Push — master ( 88715c...d7c14e )
by Julito
09:34
created

Tracking   F

Complexity

Total Complexity 791

Size/Duplication

Total Lines 7111
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 3988
dl 0
loc 7111
rs 0.8
c 0
b 0
f 0
wmc 791

59 Methods

Rating   Name   Duplication   Size   Complexity  
B get_group_reporting() 0 84 9
F generate_exercise_result_thumbnail_graph() 0 182 17
A count_number_of_forums_by_course() 0 44 5
B generate_session_exercise_graph() 0 153 2
F generate_exercise_result_graph() 0 177 17
A get_course_list_in_session_from_student() 0 20 2
A count_student_visited_links() 0 19 1
F show_course_detail() 0 376 35
A get_tools_most_used_by_course() 0 31 4
B count_student_messages() 0 62 6
A get_links_most_visited_by_course() 0 34 4
A count_number_of_posts_by_course() 0 45 4
A get_courses_list_from_session() 0 22 2
A get_student_followed_by_drh() 0 15 2
A count_login_per_student() 0 18 1
A chat_last_connection() 0 31 2
F get_exercise_progress() 0 224 26
B getInactiveStudentsInCourse() 0 74 6
A count_student_uploaded_documents() 0 43 4
A setUserSearchForm() 0 30 1
A count_student_downloaded_documents() 0 17 1
A get_documents_most_downloaded_by_course() 0 33 4
A getLastStudentPublication() 0 29 1
A chat_connections_during_last_x_days_by_course() 0 31 3
A count_number_of_threads_by_course() 0 54 5
A displayUserSkills() 0 9 3
F show_user_progress() 0 791 98
A count_student_assignments() 0 46 4
F getLpStats() 0 1093 167
B get_time_spent_on_the_platform() 0 53 9
F getStats() 0 306 29
A count_course_per_student() 0 21 2
C get_teachers_progress_by_course() 0 166 9
F get_avg_student_exercise_score() 0 133 21
B get_first_connection_date_on_the_course() 0 59 9
A get_exercise_student_progress() 0 36 4
B get_last_connection_date() 0 38 6
A get_exercise_student_average_best_attempt() 0 26 5
C get_last_connection_date_on_the_course() 0 115 15
A get_first_connection_date() 0 21 3
B get_course_connections_count() 0 61 10
F get_avg_student_progress() 0 142 21
A count_student_exercise_attempts() 0 40 3
A getInactiveUsers() 0 32 5
B get_ip_from_user_event() 0 32 7
A isAllowToTrack() 0 10 5
A getCoursesAndSessions() 0 20 6
B getToolInformation() 0 82 8
F getCalculateTime() 0 152 36
F get_avg_student_score() 0 391 62
C get_time_spent_in_lp() 0 141 14
A get_last_connection_time_in_lp() 0 46 4
B get_time_spent_on_the_course() 0 44 7
F get_courses_followed_by_coach() 0 90 12
F get_sessions_coached_by_user() 0 123 19
A get_student_followed_by_coach_in_a_session() 0 44 5
A is_allowed_to_coach_student() 0 32 3
B get_student_followed_by_coach() 0 88 8
B getAverageStudentScore() 0 63 8

How to fix   Complexity   

Complex Class

Complex classes like Tracking often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Tracking, and based on these observations, apply Extract Interface, too.

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\Course;
5
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
6
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
7
use Chamilo\UserBundle\Entity\User;
8
use ChamiloSession as Session;
9
use CpChart\Cache as pCache;
10
use CpChart\Data as pData;
11
use CpChart\Image as pImage;
12
13
/**
14
 *  Class Tracking.
15
 *
16
 *  @author  Julio Montoya <[email protected]>
17
 *
18
 *  @package chamilo.library
19
 */
20
class Tracking
21
{
22
    /**
23
     * Get group reporting.
24
     *
25
     * @param int    $course_id
26
     * @param int    $sessionId
27
     * @param int    $group_id
28
     * @param string $type
29
     * @param int    $start
30
     * @param int    $limit
31
     * @param int    $sidx
32
     * @param string $sord
33
     * @param array  $where_condition
34
     *
35
     * @return array|null
36
     */
37
    public static function get_group_reporting(
38
        $course_id,
39
        $sessionId = 0,
40
        $group_id = 0,
41
        $type = 'all',
42
        $start = 0,
43
        $limit = 1000,
44
        $sidx = 1,
45
        $sord = 'desc',
46
        $where_condition = []
47
    ) {
48
        $course_id = (int) $course_id;
49
        $sessionId = (int) $sessionId;
50
51
        if (empty($course_id)) {
52
            return null;
53
        }
54
        $courseInfo = api_get_course_info_by_id($course_id);
55
        if ($type == 'count') {
56
            return GroupManager::get_group_list(null, $courseInfo, null, $sessionId, true);
57
        }
58
59
        $groupList = GroupManager::get_group_list(null, $courseInfo, null, $sessionId);
60
        $parsedResult = [];
61
        if (!empty($groupList)) {
62
            foreach ($groupList as $group) {
63
                $users = GroupManager::get_users($group['id'], true, null, null, false, $courseInfo['real_id']);
64
                $time = 0;
65
                $avg_student_score = 0;
66
                $avg_student_progress = 0;
67
                $work = 0;
68
                $messages = 0;
69
70
                foreach ($users as $user_data) {
71
                    $time += self::get_time_spent_on_the_course(
72
                        $user_data['user_id'],
73
                        $courseInfo['real_id'],
74
                        $sessionId
75
                    );
76
                    $average = self::get_avg_student_score(
77
                        $user_data['user_id'],
78
                        $courseInfo['code'],
79
                        [],
80
                        $sessionId
81
                    );
82
                    if (is_numeric($average)) {
83
                        $avg_student_score += $average;
84
                    }
85
                    $avg_student_progress += self::get_avg_student_progress(
86
                        $user_data['user_id'],
87
                        $courseInfo['code'],
88
                        [],
89
                        $sessionId
90
                    );
91
                    $work += self::count_student_assignments(
92
                        $user_data['user_id'],
93
                        $courseInfo['code'],
94
                        $sessionId
95
                    );
96
                    $messages += self::count_student_messages(
97
                        $user_data['user_id'],
98
                        $courseInfo['code'],
99
                        $sessionId
100
                    );
101
                }
102
103
                $countUsers = count($users);
104
                $averageProgress = empty($countUsers) ? 0 : round($avg_student_progress / $countUsers, 2);
105
                $averageScore = empty($countUsers) ? 0 : round($avg_student_score / $countUsers, 2);
106
107
                $groupItem = [
108
                    'id' => $group['id'],
109
                    'name' => $group['name'],
110
                    'time' => api_time_to_hms($time),
111
                    'progress' => $averageProgress,
112
                    'score' => $averageScore,
113
                    'works' => $work,
114
                    'messages' => $messages,
115
                ];
116
                $parsedResult[] = $groupItem;
117
            }
118
        }
119
120
        return $parsedResult;
121
    }
122
123
    /**
124
     * @param int    $user_id
125
     * @param array  $courseInfo
126
     * @param int    $session_id
127
     * @param string $origin
128
     * @param bool   $export_csv
129
     * @param int    $lp_id
130
     * @param int    $lp_item_id
131
     * @param int    $extendId
132
     * @param int    $extendAttemptId
133
     * @param string $extendedAttempt
134
     * @param string $extendedAll
135
     * @param string $type            classic or simple
136
     * @param bool   $allowExtend     Optional. Allow or not extend te results
137
     *
138
     * @return string
139
     */
140
    public static function getLpStats(
141
        $user_id,
142
        $courseInfo,
143
        $session_id,
144
        $origin,
145
        $export_csv,
146
        $lp_id,
147
        $lp_item_id = null,
148
        $extendId = null,
149
        $extendAttemptId = null,
150
        $extendedAttempt = null,
151
        $extendedAll = null,
152
        $type = 'classic',
153
        $allowExtend = true
154
    ) {
155
        if (empty($courseInfo) || empty($lp_id)) {
156
            return '';
157
        }
158
159
        $hideTime = api_get_configuration_value('hide_lp_time');
160
        $lp_id = (int) $lp_id;
161
        $lp_item_id = (int) $lp_item_id;
162
        $user_id = (int) $user_id;
163
        $session_id = (int) $session_id;
164
        $origin = Security::remove_XSS($origin);
165
        $list = learnpath::get_flat_ordered_items_list($lp_id, 0, $courseInfo['real_id']);
166
        $is_allowed_to_edit = api_is_allowed_to_edit(null, true);
167
        $course_id = $courseInfo['real_id'];
168
        $courseCode = $courseInfo['code'];
169
        $session_condition = api_get_session_condition($session_id);
170
171
        // Extend all button
172
        $output = '';
173
        $extend_all = 0;
174
        if ($origin == 'tracking') {
175
            $url_suffix = '&session_id='.$session_id.'&course='.$courseCode.'&student_id='.$user_id.'&lp_id='.$lp_id.'&origin='.$origin;
176
        } else {
177
            $url_suffix = '&lp_id='.$lp_id;
178
        }
179
180
        if (!empty($extendedAll)) {
181
            $extend_all_link = Display::url(
182
                Display::return_icon('view_less_stats.gif', get_lang('HideAllAttempts')),
183
                api_get_self().'?action=stats'.$url_suffix
184
            );
185
            $extend_all = 1;
186
        } else {
187
            $extend_all_link = Display::url(
188
                Display::return_icon('view_more_stats.gif', get_lang('ShowAllAttempts')),
189
                api_get_self().'?action=stats&extend_all=1'.$url_suffix
190
            );
191
        }
192
193
        if ($origin != 'tracking') {
194
            $output .= '<div class="section-status">';
195
            $output .= Display::page_header(get_lang('ScormMystatus'));
196
            $output .= '</div>';
197
        }
198
199
        $actionColumn = null;
200
        if ($type == 'classic') {
201
            $actionColumn = ' <th>'.get_lang('Actions').'</th>';
202
        }
203
204
        $timeHeader = '<th class="lp_time" colspan="2">'.get_lang('ScormTime').'</th>';
205
        if ($hideTime) {
206
            $timeHeader = '';
207
        }
208
        $output .= '<div class="table-responsive">';
209
        $output .= '<table id="lp_tracking" class="table tracking">
210
            <thead>
211
            <tr class="table-header">
212
                <th width="16">'.($allowExtend == true ? $extend_all_link : '&nbsp;').'</th>
213
                <th colspan="4">
214
                    '.get_lang('ScormLessonTitle').'
215
                </th>
216
                <th colspan="2">
217
                    '.get_lang('ScormStatus').'
218
                </th>
219
                <th colspan="2">
220
                    '.get_lang('ScormScore').'
221
                </th>
222
                '.$timeHeader.'
223
                '.$actionColumn.'
224
                </tr>
225
            </thead>
226
            <tbody>
227
        ';
228
229
        // Going through the items using the $items[] array instead of the database order ensures
230
        // we get them in the same order as in the imsmanifest file, which is rather random when using
231
        // the database table.
232
        $TBL_LP_ITEM = Database::get_course_table(TABLE_LP_ITEM);
233
        $TBL_LP_ITEM_VIEW = Database::get_course_table(TABLE_LP_ITEM_VIEW);
234
        $TBL_LP_VIEW = Database::get_course_table(TABLE_LP_VIEW);
235
        $tbl_quiz_questions = Database::get_course_table(TABLE_QUIZ_QUESTION);
236
        $TBL_QUIZ = Database::get_course_table(TABLE_QUIZ_TEST);
237
        $tbl_stats_exercices = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
238
        $tbl_stats_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
239
240
        $sql = "SELECT max(view_count)
241
                FROM $TBL_LP_VIEW
242
                WHERE
243
                    c_id = $course_id AND
244
                    lp_id = $lp_id AND
245
                    user_id = $user_id
246
                    $session_condition";
247
        $res = Database::query($sql);
248
        $view = '';
249
        if (Database::num_rows($res) > 0) {
250
            $myrow = Database::fetch_array($res);
251
            $view = $myrow[0];
252
        }
253
254
        $counter = 0;
255
        $total_time = 0;
256
        $h = get_lang('h');
257
258
        if (!empty($export_csv)) {
259
            $csvHeaders = [
260
                get_lang('ScormLessonTitle'),
261
                get_lang('ScormStatus'),
262
                get_lang('ScormScore'),
263
            ];
264
265
            if ($hideTime === false) {
266
                $csvHeaders[] = get_lang('ScormTime');
267
            }
268
269
            $csv_content[] = $csvHeaders;
270
        }
271
272
        $result_disabled_ext_all = true;
273
        $chapterTypes = learnpath::getChapterTypes();
274
275
        // Show lp items
276
        if (is_array($list) && count($list) > 0) {
277
            foreach ($list as $my_item_id) {
278
                $extend_this = 0;
279
                $order = 'DESC';
280
                if ((!empty($extendId) && $extendId == $my_item_id) || $extend_all) {
281
                    $extend_this = 1;
282
                    $order = 'ASC';
283
                }
284
285
                // Prepare statement to go through each attempt.
286
                $viewCondition = null;
287
                if (!empty($view)) {
288
                    $viewCondition = " AND v.view_count = $view  ";
289
                }
290
291
                $sql = "SELECT
292
                    iv.status as mystatus,
293
                    v.view_count as mycount,
294
                    iv.score as myscore,
295
                    iv.total_time as mytime,
296
                    i.iid as myid,
297
                    i.lp_id as mylpid,
298
                    iv.lp_view_id as mylpviewid,
299
                    i.title as mytitle,
300
                    i.max_score as mymaxscore,
301
                    iv.max_score as myviewmaxscore,
302
                    i.item_type as item_type,
303
                    iv.view_count as iv_view_count,
304
                    iv.id as iv_id,
305
                    path
306
                FROM $TBL_LP_ITEM as i
307
                INNER JOIN $TBL_LP_ITEM_VIEW as iv
308
                ON (i.iid = iv.lp_item_id AND i.c_id = iv.c_id)
309
                INNER JOIN $TBL_LP_VIEW as v
310
                ON (iv.lp_view_id = v.id AND v.c_id = iv.c_id)
311
                WHERE
312
                    v.c_id = $course_id AND
313
                    i.iid = $my_item_id AND
314
                    i.lp_id = $lp_id  AND
315
                    v.user_id = $user_id AND
316
                    v.session_id = $session_id
317
                    $viewCondition
318
                ORDER BY iv.view_count $order ";
319
320
                $result = Database::query($sql);
321
                $num = Database::num_rows($result);
322
                $time_for_total = 0;
323
324
                // Extend all
325
                if (($extend_this || $extend_all) && $num > 0) {
326
                    $row = Database::fetch_array($result);
327
                    $result_disabled_ext_all = false;
328
                    if ($row['item_type'] == 'quiz') {
329
                        // Check results_disabled in quiz table.
330
                        $my_path = Database::escape_string($row['path']);
331
                        $sql = "SELECT results_disabled
332
                                FROM $TBL_QUIZ
333
                                WHERE
334
                                    c_id = $course_id AND
335
                                    id ='".$my_path."'";
336
                        $res_result_disabled = Database::query($sql);
337
                        $row_result_disabled = Database::fetch_row($res_result_disabled);
338
339
                        if (Database::num_rows($res_result_disabled) > 0 &&
340
                            (int) $row_result_disabled[0] === 1
341
                        ) {
342
                            $result_disabled_ext_all = true;
343
                        }
344
                    }
345
346
                    // If there are several attempts, and the link to extend has been clicked, show each attempt...
347
                    $oddclass = 'row_even';
348
                    if (($counter % 2) == 0) {
349
                        $oddclass = 'row_odd';
350
                    }
351
                    $extend_link = '';
352
                    if (!empty($inter_num)) {
353
                        $extend_link = Display::url(
354
                            Display::return_icon(
355
                                'visible.png',
356
                                get_lang('HideAttemptView')
357
                            ),
358
                            api_get_self().'?action=stats&fold_id='.$my_item_id.$url_suffix
359
                        );
360
                    }
361
                    $title = $row['mytitle'];
362
363
                    if (empty($title)) {
364
                        $title = learnpath::rl_get_resource_name($courseInfo['code'], $lp_id, $row['myid']);
365
                    }
366
367
                    if (in_array($row['item_type'], $chapterTypes)) {
368
                        $title = "<h4> $title </h4>";
369
                    }
370
                    $lesson_status = $row['mystatus'];
371
                    $title = Security::remove_XSS($title);
372
                    $counter++;
373
374
                    $action = null;
375
                    if ($type == 'classic') {
376
                        $action = '<td></td>';
377
                    }
378
379
                    if (in_array($row['item_type'], $chapterTypes)) {
380
                        $output .= '<tr class="'.$oddclass.'">
381
                                <td>'.$extend_link.'</td>
382
                                <td colspan="4">
383
                                   '.$title.'
384
                                </td>
385
                                <td colspan="2">'.learnpathItem::humanize_status($lesson_status, true, $type).'</td>
386
                                <td colspan="2"></td>
387
                                <td colspan="2"></td>
388
                                '.$action.'
389
                            </tr>';
390
                        continue;
391
                    } else {
392
                        $output .= '<tr class="'.$oddclass.'">
393
                                <td>'.$extend_link.'</td>
394
                                <td colspan="4">
395
                                   '.$title.'
396
                                </td>
397
                                <td colspan="2"></td>
398
                                <td colspan="2"></td>
399
                                <td colspan="2"></td>
400
                                '.$action.'
401
                            </tr>';
402
                    }
403
404
                    $attemptCount = 1;
405
                    do {
406
                        // Check if there are interactions below.
407
                        $extend_attempt_link = '';
408
                        $extend_this_attempt = 0;
409
410
                        if ((learnpath::get_interactions_count_from_db($row['iv_id'], $course_id) > 0 ||
411
                            learnpath::get_objectives_count_from_db($row['iv_id'], $course_id) > 0) &&
412
                            !$extend_all
413
                        ) {
414
                            if ($extendAttemptId == $row['iv_id']) {
415
                                // The extend button for this attempt has been clicked.
416
                                $extend_this_attempt = 1;
417
                                $extend_attempt_link = Display::url(
418
                                    Display::return_icon('visible.png', get_lang('HideAttemptView')),
419
                                    api_get_self().'?action=stats&extend_id='.$my_item_id.'&fold_attempt_id='.$row['iv_id'].$url_suffix
420
                                );
421
                            } else { // Same case if fold_attempt_id is set, so not implemented explicitly.
422
                                // The extend button for this attempt has not been clicked.
423
                                $extend_attempt_link = Display::url(
424
                                    Display::return_icon('invisible.png', get_lang('ExtendAttemptView')),
425
                                    api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix
426
                                );
427
                            }
428
                        }
429
430
                        $oddclass = 'row_even';
431
                        if (($counter % 2) == 0) {
432
                            $oddclass = 'row_odd';
433
                        }
434
435
                        $lesson_status = $row['mystatus'];
436
                        $score = $row['myscore'];
437
                        $time_for_total = $row['mytime'];
438
439
                        if (api_get_configuration_value('lp_minimum_time')) {
440
                            $timeCourse = self::getCalculateTime($user_id, $course_id, $session_id);
441
                            Session::write('trackTimeCourse', $timeCourse);
442
                            $lp_time = $timeCourse[TOOL_LEARNPATH];
443
                            $lpTime = (int) $lp_time[$lp_id];
444
                            $time_for_total = $lpTime;
445
                        }
446
447
                        $time = learnpathItem::getScormTimeFromParameter('js', $row['mytime']);
448
449
                        if ($score == 0) {
450
                            $maxscore = $row['mymaxscore'];
451
                        } else {
452
                            if ($row['item_type'] === 'sco') {
453
                                if (!empty($row['myviewmaxscore']) && $row['myviewmaxscore'] > 0) {
454
                                    $maxscore = $row['myviewmaxscore'];
455
                                } elseif ($row['myviewmaxscore'] === '') {
456
                                    $maxscore = 0;
457
                                } else {
458
                                    $maxscore = $row['mymaxscore'];
459
                                }
460
                            } else {
461
                                $maxscore = $row['mymaxscore'];
462
                            }
463
                        }
464
465
                        // Remove "NaN" if any (@todo: locate the source of these NaN)
466
                        $time = str_replace('NaN', '00'.$h.'00\'00"', $time);
467
468
                        if ($row['item_type'] != 'dir') {
469
                            if (!$is_allowed_to_edit && $result_disabled_ext_all) {
470
                                $view_score = Display::return_icon(
471
                                    'invisible.png',
472
                                    get_lang('ResultsHiddenByExerciseSetting')
473
                                );
474
                            } else {
475
                                switch ($row['item_type']) {
476
                                    case 'sco':
477
                                        if ($maxscore == 0) {
478
                                            $view_score = $score;
479
                                        } else {
480
                                            $view_score = ExerciseLib::show_score(
481
                                                $score,
482
                                                $maxscore,
483
                                                false
484
                                            );
485
                                        }
486
                                        break;
487
                                    case 'document':
488
                                        $view_score = ($score == 0 ? '/' : ExerciseLib::show_score($score, $maxscore, false));
489
                                        break;
490
                                    default:
491
                                        $view_score = ExerciseLib::show_score(
492
                                            $score,
493
                                            $maxscore,
494
                                            false
495
                                        );
496
                                        break;
497
                                }
498
                            }
499
500
                            $action = null;
501
                            if ($type == 'classic') {
502
                                $action = '<td></td>';
503
                            }
504
                            $timeRow = '<td class="lp_time" colspan="2">'.$time.'</td>';
505
                            if ($hideTime) {
506
                                $timeRow = '';
507
                            }
508
                            $output .= '<tr class="'.$oddclass.'">
509
                                    <td></td>
510
                                    <td>'.$extend_attempt_link.'</td>
511
                                    <td colspan="3">'.get_lang('Attempt').' '.$attemptCount.'</td>
512
                                    <td colspan="2">'.learnpathItem::humanize_status($lesson_status, true, $type).'</td>
513
                                    <td colspan="2">'.$view_score.'</td>
514
                                    '.$timeRow.'
515
                                    '.$action.'
516
                                </tr>';
517
                            $attemptCount++;
518
                            if (!empty($export_csv)) {
519
                                $temp = [];
520
                                $temp[] = $title = Security::remove_XSS($title);
521
                                $temp[] = Security::remove_XSS(
522
                                    learnpathItem::humanize_status($lesson_status, false, $type)
523
                                );
524
525
                                if ($row['item_type'] == 'quiz') {
526
                                    if (!$is_allowed_to_edit && $result_disabled_ext_all) {
527
                                        $temp[] = '/';
528
                                    } else {
529
                                        $temp[] = ($score == 0 ? '0/'.$maxscore : ($maxscore == 0 ? $score : $score.'/'.float_format($maxscore, 1)));
530
                                    }
531
                                } else {
532
                                    $temp[] = ($score == 0 ? '/' : ($maxscore == 0 ? $score : $score.'/'.float_format($maxscore, 1)));
533
                                }
534
535
                                if ($hideTime === false) {
536
                                    $temp[] = $time;
537
                                }
538
                                $csv_content[] = $temp;
539
                            }
540
                        }
541
542
                        $counter++;
543
                        $action = null;
544
                        if ($type == 'classic') {
545
                            $action = '<td></td>';
546
                        }
547
548
                        if ($extend_this_attempt || $extend_all) {
549
                            $list1 = learnpath::get_iv_interactions_array($row['iv_id']);
550
                            foreach ($list1 as $id => $interaction) {
551
                                $oddclass = 'row_even';
552
                                if (($counter % 2) == 0) {
553
                                    $oddclass = 'row_odd';
554
                                }
555
                                $student_response = urldecode($interaction['student_response']);
556
                                $content_student_response = explode('__|', $student_response);
557
558
                                if (count($content_student_response) > 0) {
559
                                    if (count($content_student_response) >= 3) {
560
                                        // Pop the element off the end of array.
561
                                        array_pop($content_student_response);
562
                                    }
563
                                    $student_response = implode(',', $content_student_response);
564
                                }
565
566
                                $timeRow = '<td class="lp_time">'.$interaction['time'].'</td>';
567
                                if ($hideTime) {
568
                                    $timeRow = '';
569
                                }
570
571
                                $output .= '<tr class="'.$oddclass.'">
572
                                        <td></td>
573
                                        <td></td>
574
                                        <td></td>
575
                                        <td>'.$interaction['order_id'].'</td>
576
                                        <td>'.$interaction['id'].'</td>
577
                                        <td colspan="2">'.$interaction['type'].'</td>
578
                                        <td>'.$student_response.'</td>
579
                                        <td>'.$interaction['result'].'</td>
580
                                        <td>'.$interaction['latency'].'</td>
581
                                        '.$timeRow.'
582
                                        '.$action.'
583
                                    </tr>';
584
                                $counter++;
585
                            }
586
                            $list2 = learnpath::get_iv_objectives_array($row['iv_id']);
587
                            foreach ($list2 as $id => $interaction) {
588
                                if (($counter % 2) == 0) {
589
                                    $oddclass = 'row_odd';
590
                                } else {
591
                                    $oddclass = 'row_even';
592
                                }
593
                                $output .= '<tr class="'.$oddclass.'">
594
                                        <td></td>
595
                                        <td></td>
596
                                        <td></td>
597
                                        <td>'.$interaction['order_id'].'</td>
598
                                        <td colspan="2">'.$interaction['objective_id'].'</td>
599
                                        <td colspan="2">'.$interaction['status'].'</td>
600
                                        <td>'.$interaction['score_raw'].'</td>
601
                                        <td>'.$interaction['score_max'].'</td>
602
                                        <td>'.$interaction['score_min'].'</td>
603
                                        '.$action.'
604
                                     </tr>';
605
                                $counter++;
606
                            }
607
                        }
608
                    } while ($row = Database::fetch_array($result));
609
                } elseif ($num > 0) {
610
                    // Not extended.
611
                    $row = Database::fetch_array($result, 'ASSOC');
612
                    $my_id = $row['myid'];
613
                    $my_lp_id = $row['mylpid'];
614
                    $my_lp_view_id = $row['mylpviewid'];
615
                    $my_path = $row['path'];
616
                    $result_disabled_ext_all = false;
617
                    if ($row['item_type'] == 'quiz') {
618
                        // Check results_disabled in quiz table.
619
                        $my_path = Database::escape_string($my_path);
620
                        $sql = "SELECT results_disabled
621
                                FROM $TBL_QUIZ
622
                                WHERE c_id = $course_id AND id ='".$my_path."'";
623
                        $res_result_disabled = Database::query($sql);
624
                        $row_result_disabled = Database::fetch_row($res_result_disabled);
625
626
                        if (Database::num_rows($res_result_disabled) > 0 &&
627
                            (int) $row_result_disabled[0] === 1
628
                        ) {
629
                            $result_disabled_ext_all = true;
630
                        }
631
                    }
632
633
                    // Check if there are interactions below
634
                    $extend_this_attempt = 0;
635
                    $inter_num = learnpath::get_interactions_count_from_db($row['iv_id'], $course_id);
636
                    $objec_num = learnpath::get_objectives_count_from_db($row['iv_id'], $course_id);
637
                    $extend_attempt_link = '';
638
                    if ($inter_num > 0 || $objec_num > 0) {
639
                        if (!empty($extendAttemptId) && $extendAttemptId == $row['iv_id']) {
640
                            // The extend button for this attempt has been clicked.
641
                            $extend_this_attempt = 1;
642
                            $extend_attempt_link = Display::url(
643
                                Display::return_icon('visible.png', get_lang('HideAttemptView')),
644
                                api_get_self().'?action=stats&extend_id='.$my_item_id.'&fold_attempt_id='.$row['iv_id'].$url_suffix
645
                            );
646
                        } else {
647
                            // Same case if fold_attempt_id is set, so not implemented explicitly.
648
                            // The extend button for this attempt has not been clicked.
649
                            $extend_attempt_link = Display::url(
650
                                Display::return_icon('invisible.png', get_lang('ExtendAttemptView')),
651
                                api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix
652
                            );
653
                        }
654
                    }
655
656
                    $oddclass = 'row_even';
657
                    if (($counter % 2) == 0) {
658
                        $oddclass = 'row_odd';
659
                    }
660
661
                    $extend_link = '';
662
                    if ($inter_num > 1) {
663
                        $extend_link = Display::url(
664
                            Display::return_icon('invisible.png', get_lang('ExtendAttemptView')),
665
                            api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix
666
                        );
667
                    }
668
669
                    $lesson_status = $row['mystatus'];
670
                    $score = $row['myscore'];
671
                    $subtotal_time = $row['mytime'];
672
673
                    while ($tmp_row = Database::fetch_array($result)) {
674
                        $subtotal_time += $tmp_row['mytime'];
675
                    }
676
677
                    $title = $row['mytitle'];
678
                    // Selecting the exe_id from stats attempts tables in order to look the max score value.
679
                    $sql = 'SELECT * FROM '.$tbl_stats_exercices.'
680
                            WHERE
681
                                exe_exo_id="'.$row['path'].'" AND
682
                                exe_user_id="'.$user_id.'" AND
683
                                orig_lp_id = "'.$lp_id.'" AND
684
                                orig_lp_item_id = "'.$row['myid'].'" AND
685
                                c_id = '.$course_id.' AND
686
                                status <> "incomplete" AND
687
                                session_id = '.$session_id.'
688
                             ORDER BY exe_date DESC
689
                             LIMIT 1';
690
691
                    $resultLastAttempt = Database::query($sql);
692
                    $num = Database::num_rows($resultLastAttempt);
693
                    $id_last_attempt = null;
694
                    if ($num > 0) {
695
                        while ($rowLA = Database::fetch_array($resultLastAttempt)) {
696
                            $id_last_attempt = $rowLA['exe_id'];
697
                        }
698
                    }
699
700
                    switch ($row['item_type']) {
701
                        case 'sco':
702
                            if (!empty($row['myviewmaxscore']) && $row['myviewmaxscore'] > 0) {
703
                                $maxscore = $row['myviewmaxscore'];
704
                            } elseif ($row['myviewmaxscore'] === '') {
705
                                $maxscore = 0;
706
                            } else {
707
                                $maxscore = $row['mymaxscore'];
708
                            }
709
                            break;
710
                        case 'quiz':
711
                            // Get score and total time from last attempt of a exercise en lp.
712
                            $sql = "SELECT iid, score
713
                                    FROM $TBL_LP_ITEM_VIEW
714
                                    WHERE
715
                                        c_id = $course_id AND
716
                                        lp_item_id = '".(int) $my_id."' AND
717
                                        lp_view_id = '".(int) $my_lp_view_id."'
718
                                    ORDER BY view_count DESC 
719
                                    LIMIT 1";
720
                            $res_score = Database::query($sql);
721
                            $row_score = Database::fetch_array($res_score);
722
723
                            $sql = "SELECT SUM(total_time) as total_time
724
                                    FROM $TBL_LP_ITEM_VIEW
725
                                    WHERE
726
                                        c_id = $course_id AND
727
                                        lp_item_id = '".(int) $my_id."' AND
728
                                        lp_view_id = '".(int) $my_lp_view_id."'";
729
                            $res_time = Database::query($sql);
730
                            $row_time = Database::fetch_array($res_time);
731
732
                            $score = 0;
733
                            $subtotal_time = 0;
734
                            if (Database::num_rows($res_score) > 0 &&
735
                                Database::num_rows($res_time) > 0
736
                            ) {
737
                                $score = (float) $row_score['score'];
738
                                $subtotal_time = (int) $row_time['total_time'];
739
                            }
740
                            // Selecting the max score from an attempt.
741
                            $sql = "SELECT SUM(t.ponderation) as maxscore
742
                                    FROM (
743
                                        SELECT DISTINCT
744
                                            question_id, marks, ponderation
745
                                        FROM $tbl_stats_attempts as at
746
                                        INNER JOIN $tbl_quiz_questions as q
747
                                        ON (q.id = at.question_id AND q.c_id = $course_id)
748
                                        WHERE exe_id ='$id_last_attempt'
749
                                    ) as t";
750
751
                            $result = Database::query($sql);
752
                            $row_max_score = Database::fetch_array($result);
753
                            $maxscore = $row_max_score['maxscore'];
754
755
                            // Get duration time from track_e_exercises.exe_duration instead of lp_view_item.total_time
756
                            $sql = 'SELECT SUM(exe_duration) exe_duration 
757
                                    FROM '.$tbl_stats_exercices.'
758
                                    WHERE
759
                                        exe_exo_id="'.$row['path'].'" AND
760
                                        exe_user_id="'.$user_id.'" AND
761
                                        orig_lp_id = "'.$lp_id.'" AND
762
                                        orig_lp_item_id = "'.$row['myid'].'" AND
763
                                        c_id = '.$course_id.' AND
764
                                        status <> "incomplete" AND
765
                                        session_id = '.$session_id.'
766
                                     ORDER BY exe_date DESC ';
767
                            $sumScoreResult = Database::query($sql);
768
                            $durationRow = Database::fetch_array($sumScoreResult, 'ASSOC');
769
                            if (!empty($durationRow['exe_duration'])) {
770
                                $exeDuration = $durationRow['exe_duration'];
771
                                if ($exeDuration != $subtotal_time &&
772
                                    !empty($row_score['iid']) &&
773
                                    !empty($exeDuration)
774
                                ) {
775
                                    $subtotal_time = $exeDuration;
776
                                    // Update c_lp_item_view.total_time
777
                                    $sqlUpdate = "UPDATE $TBL_LP_ITEM_VIEW SET total_time = '$exeDuration' 
778
                                                  WHERE iid = ".$row_score['iid'];
779
                                    Database::query($sqlUpdate);
780
                                }
781
                            }
782
                            break;
783
                        default:
784
                            $maxscore = $row['mymaxscore'];
785
                            break;
786
                    }
787
788
                    $time_for_total = $subtotal_time;
789
                    $time = learnpathItem::getScormTimeFromParameter('js', $subtotal_time);
790
                    if (empty($title)) {
791
                        $title = learnpath::rl_get_resource_name(
792
                            $courseInfo['code'],
793
                            $lp_id,
794
                            $row['myid']
795
                        );
796
                    }
797
798
                    $action = null;
799
                    if ($type == 'classic') {
800
                        $action = '<td></td>';
801
                    }
802
803
                    if (in_array($row['item_type'], $chapterTypes)) {
804
                        $title = Security::remove_XSS($title);
805
                        $output .= '<tr class="'.$oddclass.'">
806
                                <td>'.$extend_link.'</td>
807
                                <td colspan="4">
808
                                <h4>'.$title.'</h4>
809
                                </td>
810
                                <td colspan="2">'.learnpathitem::humanize_status($lesson_status).'</td>
811
                                <td colspan="2"></td>
812
                                <td colspan="2"></td>
813
                                '.$action.'
814
                            </tr>';
815
                    } else {
816
                        $correct_test_link = '-';
817
                        $showRowspan = false;
818
                        if ($row['item_type'] == 'quiz') {
819
                            $my_url_suffix = '&course='.$courseCode.'&student_id='.$user_id.'&lp_id='.intval($row['mylpid']).'&origin='.$origin;
820
                            $sql = 'SELECT * FROM '.$tbl_stats_exercices.'
821
                                     WHERE
822
                                        exe_exo_id="'.$row['path'].'" AND
823
                                        exe_user_id="'.$user_id.'" AND
824
                                        orig_lp_id = "'.$lp_id.'" AND
825
                                        orig_lp_item_id = "'.$row['myid'].'" AND
826
                                        c_id = '.$course_id.' AND
827
                                        status <> "incomplete" AND
828
                                        session_id = '.$session_id.'
829
                                     ORDER BY exe_date DESC ';
830
831
                            $resultLastAttempt = Database::query($sql);
832
                            $num = Database::num_rows($resultLastAttempt);
833
                            $showRowspan = false;
834
                            if ($num > 0) {
835
                                $linkId = 'link_'.$my_id;
836
                                if ($extendedAttempt == 1 &&
837
                                    $lp_id == $my_lp_id &&
838
                                    $lp_item_id == $my_id
839
                                ) {
840
                                    $showRowspan = true;
841
                                    $correct_test_link = Display::url(
842
                                        Display::return_icon(
843
                                            'view_less_stats.gif',
844
                                            get_lang('HideAllAttempts')
845
                                        ),
846
                                        api_get_self().'?action=stats'.$my_url_suffix.'&session_id='.$session_id.'&lp_item_id='.$my_id.'#'.$linkId,
847
                                        ['id' => $linkId]
848
                                    );
849
                                } else {
850
                                    $correct_test_link = Display::url(
851
                                        Display::return_icon(
852
                                            'view_more_stats.gif',
853
                                            get_lang(
854
                                                'ShowAllAttemptsByExercise'
855
                                            )
856
                                        ),
857
                                        api_get_self().'?action=stats&extend_attempt=1'.$my_url_suffix.'&session_id='.$session_id.'&lp_item_id='.$my_id.'#'.$linkId,
858
                                        ['id' => $linkId]
859
                                    );
860
                                }
861
                            }
862
                        }
863
864
                        $title = Security::remove_XSS($title);
865
                        $action = null;
866
                        if ($type == 'classic') {
867
                            $action = '<td '.($showRowspan ? 'rowspan="2"' : '').'>'.$correct_test_link.'</td>';
868
                        }
869
870
                        if ($lp_id == $my_lp_id && false) {
871
                            $output .= '<tr class ='.$oddclass.'>
872
                                    <td>'.$extend_link.'</td>
873
                                    <td colspan="4">'.$title.'</td>
874
                                    <td colspan="2">&nbsp;</td>
875
                                    <td colspan="2">&nbsp;</td>
876
                                    <td colspan="2">&nbsp;</td>
877
                                    '.$action.'
878
                                </tr>';
879
                            $output .= '</tr>';
880
                        } else {
881
                            if ($lp_id == $my_lp_id && $lp_item_id == $my_id) {
882
                                $output .= "<tr class='$oddclass'>";
883
                            } else {
884
                                $output .= "<tr class='$oddclass'>";
885
                            }
886
887
                            $scoreItem = null;
888
                            if ($row['item_type'] == 'quiz') {
889
                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
890
                                    $scoreItem .= Display::return_icon(
891
                                        'invisible.png',
892
                                        get_lang('ResultsHiddenByExerciseSetting')
893
                                    );
894
                                } else {
895
                                    $scoreItem .= ExerciseLib::show_score($score, $maxscore, false);
896
                                }
897
                            } else {
898
                                $scoreItem .= $score == 0 ? '/' : ($maxscore == 0 ? $score : $score.'/'.$maxscore);
899
                            }
900
901
                            $timeRow = '<td class="lp_time" colspan="2">'.$time.'</td>';
902
                            if ($hideTime) {
903
                                $timeRow = '';
904
                            }
905
906
                            $output .= '
907
                                <td>'.$extend_link.'</td>
908
                                <td colspan="4">'.$title.'</td>
909
                                <td colspan="2">'.learnpathitem::humanize_status($lesson_status).'</td>
910
                                <td colspan="2">'.$scoreItem.'</td>
911
                                '.$timeRow.'
912
                                '.$action.'
913
                             ';
914
                            $output .= '</tr>';
915
                        }
916
917
                        if (!empty($export_csv)) {
918
                            $temp = [];
919
                            $temp[] = api_html_entity_decode($title, ENT_QUOTES);
920
                            $temp[] = api_html_entity_decode($lesson_status, ENT_QUOTES);
921
922
                            if ($row['item_type'] == 'quiz') {
923
                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
924
                                    $temp[] = '/';
925
                                } else {
926
                                    $temp[] = ($score == 0 ? '0/'.$maxscore : ($maxscore == 0 ? $score : $score.'/'.float_format($maxscore, 1)));
927
                                }
928
                            } else {
929
                                $temp[] = ($score == 0 ? '/' : ($maxscore == 0 ? $score : $score.'/'.float_format($maxscore, 1)));
930
                            }
931
932
                            if ($hideTime === false) {
933
                                $temp[] = $time;
934
                            }
935
                            $csv_content[] = $temp;
936
                        }
937
                    }
938
939
                    $counter++;
940
                    $action = null;
941
                    if ($type == 'classic') {
942
                        $action = '<td></td>';
943
                    }
944
945
                    if ($extend_this_attempt || $extend_all) {
946
                        $list1 = learnpath::get_iv_interactions_array($row['iv_id']);
947
                        foreach ($list1 as $id => $interaction) {
948
                            if (($counter % 2) == 0) {
949
                                $oddclass = 'row_odd';
950
                            } else {
951
                                $oddclass = 'row_even';
952
                            }
953
954
                            $timeRow = '<td class="lp_time">'.$interaction['time'].'</td>';
955
                            if ($hideTime) {
956
                                $timeRow = '';
957
                            }
958
959
                            $output .= '<tr class="'.$oddclass.'">
960
                                    <td></td>
961
                                    <td></td>
962
                                    <td></td>
963
                                    <td>'.$interaction['order_id'].'</td>
964
                                    <td>'.$interaction['id'].'</td>
965
                                    <td colspan="2">'.$interaction['type'].'</td>
966
                                    <td>'.urldecode($interaction['student_response']).'</td>
967
                                    <td>'.$interaction['result'].'</td>
968
                                    <td>'.$interaction['latency'].'</td>
969
                                    '.$timeRow.'
970
                                    '.$action.'
971
                               </tr>';
972
                            $counter++;
973
                        }
974
                        $list2 = learnpath::get_iv_objectives_array($row['iv_id']);
975
                        foreach ($list2 as $id => $interaction) {
976
                            if (($counter % 2) == 0) {
977
                                $oddclass = 'row_odd';
978
                            } else {
979
                                $oddclass = 'row_even';
980
                            }
981
                            $output .= '<tr class="'.$oddclass.'">
982
                                    <td></td>
983
                                    <td></td>
984
                                    <td></td>
985
                                    <td>'.$interaction['order_id'].'</td>
986
                                    <td colspan="2">'.$interaction['objective_id'].'</td>
987
                                    <td colspan="2">'.$interaction['status'].'</td>
988
                                    <td>'.$interaction['score_raw'].'</td>
989
                                    <td>'.$interaction['score_max'].'</td>
990
                                    <td>'.$interaction['score_min'].'</td>
991
                                    '.$action.'
992
                               </tr>';
993
                            $counter++;
994
                        }
995
                    }
996
997
                    // Attempts listing by exercise.
998
                    if ($lp_id == $my_lp_id && $lp_item_id == $my_id && $extendedAttempt) {
999
                        // Get attempts of a exercise.
1000
                        if (!empty($lp_id) &&
1001
                            !empty($lp_item_id) &&
1002
                            $row['item_type'] === 'quiz'
1003
                        ) {
1004
                            $sql = "SELECT path FROM $TBL_LP_ITEM
1005
                                    WHERE
1006
                                        c_id = $course_id AND
1007
                                        iid = '$lp_item_id' AND
1008
                                        lp_id = '$lp_id'";
1009
                            $res_path = Database::query($sql);
1010
                            $row_path = Database::fetch_array($res_path);
1011
1012
                            if (Database::num_rows($res_path) > 0) {
1013
                                $sql = 'SELECT * FROM '.$tbl_stats_exercices.'
1014
                                        WHERE
1015
                                            exe_exo_id="'.(int) $row_path['path'].'" AND
1016
                                            status <> "incomplete" AND
1017
                                            exe_user_id="'.$user_id.'" AND
1018
                                            orig_lp_id = "'.(int) $lp_id.'" AND
1019
                                            orig_lp_item_id = "'.(int) $lp_item_id.'" AND
1020
                                            c_id = '.$course_id.'  AND
1021
                                            session_id = '.$session_id.'
1022
                                        ORDER BY exe_date';
1023
                                $res_attempts = Database::query($sql);
1024
                                $num_attempts = Database::num_rows($res_attempts);
1025
                                if ($num_attempts > 0) {
1026
                                    $n = 1;
1027
                                    while ($row_attempts = Database::fetch_array($res_attempts)) {
1028
                                        $my_score = $row_attempts['score'];
1029
                                        $my_maxscore = $row_attempts['max_score'];
1030
                                        $my_exe_id = $row_attempts['exe_id'];
1031
                                        $mktime_start_date = api_strtotime($row_attempts['start_date'], 'UTC');
1032
                                        $mktime_exe_date = api_strtotime($row_attempts['exe_date'], 'UTC');
1033
                                        $time_attemp = ' - ';
1034
                                        if ($mktime_start_date && $mktime_exe_date) {
1035
                                            $time_attemp = api_format_time($row_attempts['exe_duration'], 'js');
1036
                                        }
1037
                                        if (!$is_allowed_to_edit && $result_disabled_ext_all) {
1038
                                            $view_score = Display::return_icon(
1039
                                                'invisible.png',
1040
                                                get_lang(
1041
                                                    'ResultsHiddenByExerciseSetting'
1042
                                                )
1043
                                            );
1044
                                        } else {
1045
                                            // Show only float when need it
1046
                                            if ($my_score == 0) {
1047
                                                $view_score = ExerciseLib::show_score(
1048
                                                    0,
1049
                                                    $my_maxscore,
1050
                                                    false
1051
                                                );
1052
                                            } else {
1053
                                                if ($my_maxscore == 0) {
1054
                                                    $view_score = $my_score;
1055
                                                } else {
1056
                                                    $view_score = ExerciseLib::show_score(
1057
                                                        $my_score,
1058
                                                        $my_maxscore,
1059
                                                        false
1060
                                                    );
1061
                                                }
1062
                                            }
1063
                                        }
1064
                                        $my_lesson_status = $row_attempts['status'];
1065
                                        if ($my_lesson_status == '') {
1066
                                            $my_lesson_status = learnpathitem::humanize_status('completed');
1067
                                        } elseif ($my_lesson_status == 'incomplete') {
1068
                                            $my_lesson_status = learnpathitem::humanize_status('incomplete');
1069
                                        }
1070
                                        $timeRow = '<td class="lp_time" colspan="2">'.$time_attemp.'</td>';
1071
                                        if ($hideTime) {
1072
                                            $timeRow = '';
1073
                                        }
1074
1075
                                        $output .= '<tr class="'.$oddclass.'" >
1076
                                        <td></td>
1077
                                        <td>'.$extend_attempt_link.'</td>
1078
                                        <td colspan="3">'.get_lang('Attempt').' '.$n.'</td>
1079
                                        <td colspan="2">'.$my_lesson_status.'</td>
1080
                                        <td colspan="2">'.$view_score.'</td>
1081
                                        '.$timeRow;
1082
1083
                                        if ($action == 'classic') {
1084
                                            if ($origin != 'tracking') {
1085
                                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
1086
                                                    $output .= '<td>
1087
                                                            <img src="'.Display::returnIconPath('quiz_na.gif').'" alt="'.get_lang('ShowAttempt').'" title="'.get_lang('ShowAttempt').'">
1088
                                                            </td>';
1089
                                                } else {
1090
                                                    $output .= '<td>
1091
                                                            <a href="../exercise/exercise_show.php?origin='.$origin.'&id='.$my_exe_id.'&cidReq='.$courseCode.'" target="_parent">
1092
                                                            <img src="'.Display::returnIconPath('quiz.png').'" alt="'.get_lang('ShowAttempt').'" title="'.get_lang('ShowAttempt').'">
1093
                                                            </a></td>';
1094
                                                }
1095
                                            } else {
1096
                                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
1097
                                                    $output .= '<td>
1098
                                                                <img src="'.Display::returnIconPath('quiz_na.gif').'" alt="'.get_lang('ShowAndQualifyAttempt').'" title="'.get_lang('ShowAndQualifyAttempt').'"></td>';
1099
                                                } else {
1100
                                                    $output .= '<td>
1101
                                                                    <a href="../exercise/exercise_show.php?cidReq='.$courseCode.'&origin=correct_exercise_in_lp&id='.$my_exe_id.'" target="_parent">
1102
                                                                    <img src="'.Display::returnIconPath('quiz.gif').'" alt="'.get_lang('ShowAndQualifyAttempt').'" title="'.get_lang('ShowAndQualifyAttempt').'"></a></td>';
1103
                                                }
1104
                                            }
1105
                                        }
1106
                                        $output .= '</tr>';
1107
                                        $n++;
1108
                                    }
1109
                                }
1110
                                $output .= '<tr><td colspan="12">&nbsp;</td></tr>';
1111
                            }
1112
                        }
1113
                    }
1114
                }
1115
1116
                $total_time += $time_for_total;
1117
                // QUIZZ IN LP
1118
                $a_my_id = [];
1119
                if (!empty($my_lp_id)) {
1120
                    $a_my_id[] = $my_lp_id;
1121
                }
1122
            }
1123
        }
1124
1125
        // NOT Extend all "left green cross"
1126
        if (!empty($a_my_id)) {
1127
            if ($extendedAttempt) {
1128
                // "Right green cross" extended
1129
                $total_score = self::get_avg_student_score(
1130
                    $user_id,
1131
                    $course_id,
1132
                    $a_my_id,
1133
                    $session_id,
1134
                    false,
1135
                    false
1136
                );
1137
            } else {
1138
                // "Left green cross" extended
1139
                $total_score = self::get_avg_student_score(
1140
                    $user_id,
1141
                    $course_id,
1142
                    $a_my_id,
1143
                    $session_id,
1144
                    false,
1145
                    true
1146
                );
1147
            }
1148
        } else {
1149
            // Extend all "left green cross"
1150
            $total_score = self::get_avg_student_score(
1151
                $user_id,
1152
                $course_id,
1153
                [$lp_id],
1154
                $session_id,
1155
                false,
1156
                false
1157
            );
1158
        }
1159
1160
        $total_time = learnpathItem::getScormTimeFromParameter('js', $total_time);
1161
        $total_time = str_replace('NaN', '00'.$h.'00\'00"', $total_time);
1162
1163
        if (!$is_allowed_to_edit && $result_disabled_ext_all) {
1164
            $final_score = Display::return_icon('invisible.png', get_lang('ResultsHiddenByExerciseSetting'));
1165
            $finalScoreToCsv = get_lang('ResultsHiddenByExerciseSetting');
1166
        } else {
1167
            if (is_numeric($total_score)) {
1168
                $final_score = $total_score.'%';
1169
            } else {
1170
                $final_score = $total_score;
1171
            }
1172
            $finalScoreToCsv = $final_score;
1173
        }
1174
        $progress = learnpath::getProgress($lp_id, $user_id, $course_id, $session_id);
1175
1176
        $oddclass = 'row_even';
1177
        if (($counter % 2) == 0) {
1178
            $oddclass = 'row_odd';
1179
        }
1180
1181
        $action = null;
1182
        if ($type == 'classic') {
1183
            $action = '<td></td>';
1184
        }
1185
1186
        $timeTotal = '<td class="lp_time" colspan="2">'.$total_time.'</div>';
1187
        if ($hideTime) {
1188
            $timeTotal = '';
1189
        }
1190
1191
        $output .= '<tr class="'.$oddclass.'">
1192
                <td></td>
1193
                <td colspan="4">
1194
                    <i>'.get_lang('AccomplishedStepsTotal').'</i>
1195
                </td>
1196
                <td colspan="2">'.$progress.'%</td>
1197
                <td colspan="2">'.$final_score.'</td>
1198
                '.$timeTotal.'
1199
                '.$action.'
1200
           </tr>';
1201
1202
        $output .= '
1203
                    </tbody>
1204
                </table>
1205
            </div>
1206
        ';
1207
1208
        if (!empty($export_csv)) {
1209
            $temp = [
1210
                '',
1211
                '',
1212
                '',
1213
                '',
1214
            ];
1215
            $csv_content[] = $temp;
1216
            $temp = [
1217
                get_lang('AccomplishedStepsTotal'),
1218
                '',
1219
                $finalScoreToCsv,
1220
            ];
1221
1222
            if ($hideTime === false) {
1223
                $temp[] = $total_time;
1224
            }
1225
1226
            $csv_content[] = $temp;
1227
            ob_end_clean();
1228
            Export::arrayToCsv($csv_content, 'reporting_learning_path_details');
1229
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1230
        }
1231
1232
        return $output;
1233
    }
1234
1235
    /**
1236
     * @param int  $userId
1237
     * @param bool $getCount
1238
     *
1239
     * @return array
1240
     */
1241
    public static function getStats($userId, $getCount = false)
1242
    {
1243
        $courses = [];
1244
        $assignedCourses = [];
1245
        $drhCount = 0;
1246
        $teachersCount = 0;
1247
        $studentsCount = 0;
1248
        $studentBossCount = 0;
1249
        $courseCount = 0;
1250
        $sessionCount = 0;
1251
        $assignedCourseCount = 0;
1252
1253
        if (api_is_drh() && api_drh_can_access_all_session_content()) {
1254
            $studentList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1255
                'drh_all',
1256
                $userId,
1257
                false,
1258
                null,
1259
                null,
1260
                null,
1261
                null,
1262
                null,
1263
                null,
1264
                null,
1265
                [],
1266
                [],
1267
                STUDENT
1268
            );
1269
1270
            $students = [];
1271
            if (is_array($studentList)) {
1272
                foreach ($studentList as $studentData) {
1273
                    $students[] = $studentData['user_id'];
1274
                }
1275
            }
1276
1277
            $studentBossesList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1278
                'drh_all',
1279
                $userId,
1280
                $getCount,
1281
                null,
1282
                null,
1283
                null,
1284
                null,
1285
                null,
1286
                null,
1287
                null,
1288
                [],
1289
                [],
1290
                STUDENT_BOSS
1291
            );
1292
1293
            if ($getCount) {
1294
                $studentBossCount = $studentBossesList;
1295
            } else {
1296
                $studentBosses = [];
1297
                if (is_array($studentBossesList)) {
1298
                    foreach ($studentBossesList as $studentBossData) {
1299
                        $studentBosses[] = $studentBossData['user_id'];
1300
                    }
1301
                }
1302
            }
1303
1304
            $teacherList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1305
                'drh_all',
1306
                $userId,
1307
                $getCount,
1308
                null,
1309
                null,
1310
                null,
1311
                null,
1312
                null,
1313
                null,
1314
                null,
1315
                [],
1316
                [],
1317
                COURSEMANAGER
1318
            );
1319
1320
            if ($getCount) {
1321
                $teachersCount = $teacherList;
1322
            } else {
1323
                $teachers = [];
1324
                foreach ($teacherList as $teacherData) {
1325
                    $teachers[] = $teacherData['user_id'];
1326
                }
1327
            }
1328
1329
            $humanResources = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1330
                'drh_all',
1331
                $userId,
1332
                $getCount,
1333
                null,
1334
                null,
1335
                null,
1336
                null,
1337
                null,
1338
                null,
1339
                null,
1340
                [],
1341
                [],
1342
                DRH
1343
            );
1344
1345
            if ($getCount) {
1346
                $drhCount = $humanResources;
1347
            } else {
1348
                $humanResourcesList = [];
1349
                if (is_array($humanResources)) {
1350
                    foreach ($humanResources as $item) {
1351
                        $humanResourcesList[] = $item['user_id'];
1352
                    }
1353
                }
1354
            }
1355
1356
            $platformCourses = SessionManager::getAllCoursesFollowedByUser(
1357
                $userId,
1358
                null,
1359
                null,
1360
                null,
1361
                null,
1362
                null,
1363
                $getCount
1364
            );
1365
1366
            if ($getCount) {
1367
                $courseCount = $platformCourses;
1368
            } else {
1369
                foreach ($platformCourses as $course) {
1370
                    $courses[$course['code']] = $course['code'];
1371
                }
1372
            }
1373
1374
            $sessions = SessionManager::get_sessions_followed_by_drh(
1375
                $userId,
1376
                null,
1377
                null,
1378
                false
1379
            );
1380
        } else {
1381
            $studentList = UserManager::getUsersFollowedByUser(
1382
                $userId,
1383
                STUDENT,
1384
                false,
1385
                false,
1386
                false,
1387
                null,
1388
                null,
1389
                null,
1390
                null,
1391
                null,
1392
                null,
1393
                COURSEMANAGER
1394
            );
1395
1396
            $students = [];
1397
            if (is_array($studentList)) {
1398
                foreach ($studentList as $studentData) {
1399
                    $students[] = $studentData['user_id'];
1400
                }
1401
            }
1402
1403
            $studentBossesList = UserManager::getUsersFollowedByUser(
1404
                $userId,
1405
                STUDENT_BOSS,
1406
                false,
1407
                false,
1408
                $getCount,
1409
                null,
1410
                null,
1411
                null,
1412
                null,
1413
                null,
1414
                null,
1415
                COURSEMANAGER
1416
            );
1417
1418
            if ($getCount) {
1419
                $studentBossCount = $studentBossesList;
1420
            } else {
1421
                $studentBosses = [];
1422
                if (is_array($studentBossesList)) {
1423
                    foreach ($studentBossesList as $studentBossData) {
1424
                        $studentBosses[] = $studentBossData['user_id'];
1425
                    }
1426
                }
1427
            }
1428
1429
            $teacherList = UserManager::getUsersFollowedByUser(
1430
                $userId,
1431
                COURSEMANAGER,
1432
                false,
1433
                false,
1434
                $getCount,
1435
                null,
1436
                null,
1437
                null,
1438
                null,
1439
                null,
1440
                null,
1441
                COURSEMANAGER
1442
            );
1443
1444
            if ($getCount) {
1445
                $teachersCount = $teacherList;
1446
            } else {
1447
                $teachers = [];
1448
                foreach ($teacherList as $teacherData) {
1449
                    $teachers[] = $teacherData['user_id'];
1450
                }
1451
            }
1452
1453
            $humanResources = UserManager::getUsersFollowedByUser(
1454
                $userId,
1455
                DRH,
1456
                false,
1457
                false,
1458
                $getCount,
1459
                null,
1460
                null,
1461
                null,
1462
                null,
1463
                null,
1464
                null,
1465
                COURSEMANAGER
1466
            );
1467
1468
            if ($getCount) {
1469
                $drhCount = $humanResources;
1470
            } else {
1471
                $humanResourcesList = [];
1472
                foreach ($humanResources as $item) {
1473
                    $humanResourcesList[] = $item['user_id'];
1474
                }
1475
            }
1476
1477
            $platformCourses = CourseManager::getCoursesFollowedByUser(
1478
                $userId,
1479
                COURSEMANAGER,
1480
                null,
1481
                null,
1482
                null,
1483
                null,
1484
                $getCount,
1485
                null,
1486
                null,
1487
                true
1488
            );
1489
1490
            if ($getCount) {
1491
                $assignedCourseCount = $platformCourses;
1492
            } else {
1493
                foreach ($platformCourses as $course) {
1494
                    $assignedCourses[$course['code']] = $course['code'];
1495
                }
1496
            }
1497
1498
            $platformCourses = CourseManager::getCoursesFollowedByUser(
1499
                $userId,
1500
                COURSEMANAGER,
1501
                null,
1502
                null,
1503
                null,
1504
                null,
1505
                $getCount
1506
            );
1507
1508
            if ($getCount) {
1509
                $courseCount = $platformCourses;
1510
            } else {
1511
                foreach ($platformCourses as $course) {
1512
                    $courses[$course['code']] = $course['code'];
1513
                }
1514
            }
1515
1516
            $sessions = SessionManager::getSessionsFollowedByUser(
1517
                $userId,
1518
                COURSEMANAGER,
1519
                null,
1520
                null,
1521
                false
1522
            );
1523
        }
1524
1525
        if ($getCount) {
1526
            return [
1527
                'drh' => $drhCount,
1528
                'teachers' => $teachersCount,
1529
                'student_count' => count($students),
1530
                'student_list' => $students,
1531
                'student_bosses' => $studentBossCount,
1532
                'courses' => $courseCount,
1533
                'session_count' => count($sessions),
1534
                'session_list' => $sessions,
1535
                'assigned_courses' => $assignedCourseCount,
1536
            ];
1537
        }
1538
1539
        return [
1540
            'drh' => $humanResourcesList,
1541
            'teachers' => $teachers,
1542
            'student_list' => $students,
1543
            'student_bosses' => $studentBosses,
1544
            'courses' => $courses,
1545
            'sessions' => $sessions,
1546
            'assigned_courses' => $assignedCourses,
1547
        ];
1548
    }
1549
1550
    /**
1551
     * Calculates the time spent on the platform by a user.
1552
     *
1553
     * @param   int|array User id
1554
     * @param string $timeFilter type of time filter: 'last_week' or 'custom'
1555
     * @param string $start_date start date date('Y-m-d H:i:s')
1556
     * @param string $end_date   end date date('Y-m-d H:i:s')
1557
     *
1558
     * @return int $nb_seconds
1559
     */
1560
    public static function get_time_spent_on_the_platform(
1561
        $userId,
1562
        $timeFilter = 'last_7_days',
1563
        $start_date = null,
1564
        $end_date = null
1565
    ) {
1566
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1567
        $condition_time = '';
1568
1569
        if (is_array($userId)) {
1570
            $userList = array_map('intval', $userId);
1571
            $userCondition = " login_user_id IN ('".implode("','", $userList)."')";
1572
        } else {
1573
            $userCondition = " login_user_id = ".intval($userId);
1574
        }
1575
1576
        if (empty($timeFilter)) {
1577
            $timeFilter = 'last_week';
1578
        }
1579
1580
        $today = new DateTime('now', new DateTimeZone('UTC'));
1581
1582
        switch ($timeFilter) {
1583
            case 'last_7_days':
1584
                $newDate = new DateTime('-7 day', new DateTimeZone('UTC'));
1585
                $condition_time = " AND (login_date >= '{$newDate->format('Y-m-d H:i:s')}'";
1586
                $condition_time .= " AND logout_date <= '{$today->format('Y-m-d H:i:s')}') ";
1587
                break;
1588
            case 'last_30_days':
1589
                $newDate = new DateTime('-30 days', new DateTimeZone('UTC'));
1590
                $condition_time = " AND (login_date >= '{$newDate->format('Y-m-d H:i:s')}'";
1591
                $condition_time .= "AND logout_date <= '{$today->format('Y-m-d H:i:s')}') ";
1592
                break;
1593
            case 'custom':
1594
                if (!empty($start_date) && !empty($end_date)) {
1595
                    $start_date = Database::escape_string($start_date);
1596
                    $end_date = Database::escape_string($end_date);
1597
                    $condition_time = ' AND (login_date >= "'.$start_date.'" AND logout_date <= "'.$end_date.'" ) ';
1598
                }
1599
                break;
1600
        }
1601
1602
        $sql = 'SELECT SUM(TIMESTAMPDIFF(SECOND, login_date, logout_date)) diff
1603
    	        FROM '.$tbl_track_login.'
1604
                WHERE '.$userCondition.$condition_time;
1605
        $rs = Database::query($sql);
1606
        $row = Database::fetch_array($rs, 'ASSOC');
1607
        $diff = $row['diff'];
1608
1609
        if ($diff >= 0) {
1610
            return $diff;
1611
        } else {
1612
            return -1;
1613
        }
1614
    }
1615
1616
    /**
1617
     * Calculates the time spent on the course.
1618
     *
1619
     * @param int $user_id
1620
     * @param int $courseId
1621
     * @param int Session id (optional)
1622
     *
1623
     * @return int Time in seconds
1624
     */
1625
    public static function get_time_spent_on_the_course(
1626
        $user_id,
1627
        $courseId,
1628
        $session_id = 0
1629
    ) {
1630
        $courseId = (int) $courseId;
1631
1632
        if (empty($courseId) || empty($user_id)) {
1633
            return 0;
1634
        }
1635
1636
        if (api_get_configuration_value('lp_minimum_time')) {
1637
            $courseTime = self::getCalculateTime($user_id, $courseId, $session_id);
1638
            $time = isset($courseTime['total_time']) ? $courseTime['total_time'] : 0;
1639
1640
            return $time;
1641
        }
1642
1643
        $session_id = (int) $session_id;
1644
        if (is_array($user_id)) {
1645
            $user_id = array_map('intval', $user_id);
1646
            $conditionUser = " AND user_id IN (".implode(',', $user_id).") ";
1647
        } else {
1648
            $user_id = (int) $user_id;
1649
            $conditionUser = " AND user_id = $user_id ";
1650
        }
1651
1652
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1653
        $sql = "SELECT
1654
                SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as nb_seconds
1655
                FROM $table
1656
                WHERE 
1657
                    UNIX_TIMESTAMP(logout_course_date) > UNIX_TIMESTAMP(login_course_date) AND 
1658
                    c_id = '$courseId' ";
1659
1660
        if ($session_id != -1) {
1661
            $sql .= "AND session_id = '$session_id' ";
1662
        }
1663
1664
        $sql .= $conditionUser;
1665
        $rs = Database::query($sql);
1666
        $row = Database::fetch_array($rs);
1667
1668
        return $row['nb_seconds'];
1669
    }
1670
1671
    /**
1672
     * Get first connection date for a student.
1673
     *
1674
     * @param int $student_id
1675
     *
1676
     * @return string|bool Date format long without day or false if there are no connections
1677
     */
1678
    public static function get_first_connection_date($student_id)
1679
    {
1680
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1681
        $sql = 'SELECT login_date
1682
                FROM '.$table.'
1683
                WHERE login_user_id = '.intval($student_id).'
1684
                ORDER BY login_date ASC
1685
                LIMIT 0,1';
1686
1687
        $rs = Database::query($sql);
1688
        if (Database::num_rows($rs) > 0) {
1689
            if ($first_login_date = Database::result($rs, 0, 0)) {
1690
                return api_convert_and_format_date(
1691
                    $first_login_date,
1692
                    DATE_FORMAT_SHORT,
1693
                    date_default_timezone_get()
1694
                );
1695
            }
1696
        }
1697
1698
        return false;
1699
    }
1700
1701
    /**
1702
     * Get las connection date for a student.
1703
     *
1704
     * @param int  $student_id
1705
     * @param bool $warning_message  Show a warning message (optional)
1706
     * @param bool $return_timestamp True for returning results in timestamp (optional)
1707
     *
1708
     * @return string|int|bool Date format long without day, false if there are no connections or
1709
     *                         timestamp if parameter $return_timestamp is true
1710
     */
1711
    public static function get_last_connection_date(
1712
        $student_id,
1713
        $warning_message = false,
1714
        $return_timestamp = false
1715
    ) {
1716
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1717
        $sql = 'SELECT login_date
1718
                FROM '.$table.'
1719
                WHERE login_user_id = '.intval($student_id).'
1720
                ORDER BY login_date
1721
                DESC LIMIT 0,1';
1722
1723
        $rs = Database::query($sql);
1724
        if (Database::num_rows($rs) > 0) {
1725
            if ($last_login_date = Database::result($rs, 0, 0)) {
1726
                $last_login_date = api_get_local_time($last_login_date);
1727
                if ($return_timestamp) {
1728
                    return api_strtotime($last_login_date, 'UTC');
1729
                } else {
1730
                    if (!$warning_message) {
1731
                        return api_format_date($last_login_date, DATE_FORMAT_SHORT);
1732
                    } else {
1733
                        $timestamp = api_strtotime($last_login_date, 'UTC');
1734
                        $currentTimestamp = time();
1735
1736
                        //If the last connection is > than 7 days, the text is red
1737
                        //345600 = 7 days in seconds
1738
                        if ($currentTimestamp - $timestamp > 604800) {
1739
                            return '<span style="color: #F00;">'.api_format_date($last_login_date, DATE_FORMAT_SHORT).'</span>';
1740
                        } else {
1741
                            return api_format_date($last_login_date, DATE_FORMAT_SHORT);
1742
                        }
1743
                    }
1744
                }
1745
            }
1746
        }
1747
1748
        return false;
1749
    }
1750
1751
    /**
1752
     * Get las connection date for a student.
1753
     *
1754
     * @param array $studentList Student id array
1755
     * @param int   $days
1756
     * @param bool  $getCount
1757
     *
1758
     * @return int
1759
     */
1760
    public static function getInactiveUsers($studentList, $days, $getCount = true)
1761
    {
1762
        if (empty($studentList)) {
1763
            return 0;
1764
        }
1765
        $days = intval($days);
1766
        $date = api_get_utc_datetime(strtotime($days.' days ago'));
1767
        $studentList = array_map('intval', $studentList);
1768
1769
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1770
        $select = " SELECT login_user_id ";
1771
        if ($getCount) {
1772
            $select = " SELECT count(DISTINCT login_user_id) as count";
1773
        }
1774
        $sql = "$select
1775
                FROM $tbl_track_login
1776
                WHERE
1777
                    login_user_id IN (' ".implode("','", $studentList)."' ) AND
1778
                    login_date < '$date'
1779
                ";
1780
        $rs = Database::query($sql);
1781
        if (Database::num_rows($rs) > 0) {
1782
            if ($getCount) {
1783
                $count = Database::fetch_array($rs);
1784
1785
                return $count['count'];
1786
            }
1787
1788
            return Database::store_result($rs, 'ASSOC');
1789
        }
1790
1791
        return false;
1792
    }
1793
1794
    /**
1795
     * Get first user's connection date on the course.
1796
     *
1797
     * @param int User id
1798
     * @param int $courseId
1799
     * @param int Session id (optional, default=0)
1800
     * @param bool $convert_date
1801
     *
1802
     * @return string|bool Date with format long without day or false if there is no date
1803
     */
1804
    public static function get_first_connection_date_on_the_course(
1805
        $student_id,
1806
        $courseId,
1807
        $session_id = 0,
1808
        $convert_date = true
1809
    ) {
1810
        $student_id = (int) $student_id;
1811
        $courseId = (int) $courseId;
1812
        $session_id = (int) $session_id;
1813
1814
        if (api_get_configuration_value('lp_minimum_time')) {
1815
            $tbl_track_e_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
1816
            $sql = 'SELECT access_date
1817
                    FROM '.$tbl_track_e_access.'
1818
                    WHERE   access_user_id = '.$student_id.' AND
1819
                            c_id = "'.$courseId.'" AND
1820
                            access_session_id = '.$session_id.'
1821
                    ORDER BY access_date ASC
1822
                    LIMIT 0,1';
1823
1824
            $rs = Database::query($sql);
1825
            if (Database::num_rows($rs) > 0) {
1826
                if ($last_login_date = Database::result($rs, 0, 0)) {
1827
                    if (empty($last_login_date)) {
1828
                        return false;
1829
                    }
1830
                    if ($convert_date) {
1831
                        return api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
1832
                    } else {
1833
                        return $last_login_date;
1834
                    }
1835
                }
1836
            }
1837
        } else {
1838
            $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1839
            $sql = 'SELECT login_course_date
1840
                    FROM '.$tbl_track_login.'
1841
                    WHERE
1842
                        user_id = '.$student_id.' AND
1843
                        c_id = '.$courseId.' AND
1844
                        session_id = '.$session_id.'
1845
                    ORDER BY login_course_date ASC 
1846
                    LIMIT 0,1';
1847
            $rs = Database::query($sql);
1848
            if (Database::num_rows($rs) > 0) {
1849
                if ($first_login_date = Database::result($rs, 0, 0)) {
1850
                    if ($convert_date) {
1851
                        return api_convert_and_format_date(
1852
                            $first_login_date,
1853
                            DATE_FORMAT_SHORT
1854
                        );
1855
                    } else {
1856
                        return $first_login_date;
1857
                    }
1858
                }
1859
            }
1860
        }
1861
1862
        return false;
1863
    }
1864
1865
    /**
1866
     * Get last user's connection date on the course.
1867
     *
1868
     * @param     int         User id
1869
     * @param array $courseInfo real_id and code are used
1870
     * @param    int            Session id (optional, default=0)
1871
     * @param bool $convert_date
1872
     *
1873
     * @return string|bool Date with format long without day or false if there is no date
1874
     */
1875
    public static function get_last_connection_date_on_the_course(
1876
        $student_id,
1877
        $courseInfo,
1878
        $session_id = 0,
1879
        $convert_date = true
1880
    ) {
1881
        // protect data
1882
        $student_id = (int) $student_id;
1883
        $session_id = (int) $session_id;
1884
        $courseId = $courseInfo['real_id'];
1885
1886
        if (api_get_configuration_value('lp_minimum_time')) {
1887
            // Show the last date on which the user acceed the session when it was active
1888
            $where_condition = '';
1889
            $userInfo = api_get_user_info($student_id);
1890
            if ($userInfo['status'] == 5 && $session_id > 0) {
1891
                // fin de acceso a la sesión
1892
                $sessionInfo = SessionManager::fetch($session_id);
1893
                $last_access = $sessionInfo['access_end_date'];
1894
                $where_condition = ' AND access_date < "'.$last_access.'" ';
1895
            }
1896
1897
        $tbl_track_e_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
1898
        $sql = 'SELECT access_date
1899
                FROM '.$tbl_track_e_access.'
1900
                WHERE   access_user_id = '.$student_id.' AND
1901
                        c_id = "'.$courseId.'" AND
1902
                        access_session_id = '.$session_id.$where_condition.'
1903
                ORDER BY access_date DESC
1904
                LIMIT 0,1';
1905
1906
        $rs = Database::query($sql);
1907
        if (Database::num_rows($rs) > 0) {
1908
            if ($last_login_date = Database::result($rs, 0, 0)) {
1909
                if (empty($last_login_date)) {
1910
                    return false;
1911
                }
1912
                //see #5736
1913
                $last_login_date_timestamp = api_strtotime($last_login_date);
1914
                $now = time();
1915
                //If the last connection is > than 7 days, the text is red
1916
                //345600 = 7 days in seconds
1917
                    /*
1918
                if ($now - $last_login_date_timestamp > 604800) {
1919
                    if ($convert_date) {
1920
                        $last_login_date = api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
1921
                        $icon = api_is_allowed_to_edit() ?
1922
                            '<a href="'.api_get_path(WEB_CODE_PATH).'announcements/announcements.php?action=add&remind_inactive='.$student_id.'&cidReq='.$courseInfo['code'].'" title="'.get_lang('RemindInactiveUser').'">
1923
                                  '.Display::return_icon('messagebox_warning.gif').'
1924
                                 </a>'
1925
                                : null;
1926
                            return $icon.Display::label($last_login_date, 'warning');
1927
                        } else {
1928
                            return $last_login_date;
1929
                        }
1930
                    } else {
1931
                    */
1932
                    if ($convert_date) {
1933
                        return api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
1934
                    } else {
1935
                        return $last_login_date;
1936
                    }
1937
                    //}
1938
                }
1939
            }
1940
        } else {
1941
            $tbl_track_e_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
1942
            $sql = 'SELECT access_date
1943
                    FROM '.$tbl_track_e_access.'
1944
                    WHERE   access_user_id = '.$student_id.' AND
1945
                            c_id = "'.$courseId.'" AND
1946
                            access_session_id = '.$session_id.'
1947
                    ORDER BY access_date DESC
1948
                    LIMIT 0,1';
1949
1950
            $rs = Database::query($sql);
1951
            if (Database::num_rows($rs) > 0) {
1952
                if ($last_login_date = Database::result($rs, 0, 0)) {
1953
                    if (empty($last_login_date)) {
1954
                        return false;
1955
                    }
1956
                    //see #5736
1957
                    $last_login_date_timestamp = api_strtotime($last_login_date);
1958
                    $now = time();
1959
                    //If the last connection is > than 7 days, the text is red
1960
                    //345600 = 7 days in seconds
1961
                    if ($now - $last_login_date_timestamp > 604800) {
1962
                        if ($convert_date) {
1963
                                $last_login_date = api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
1964
                                $icon = api_is_allowed_to_edit() ?
1965
                                    '<a href="'.api_get_path(
1966
                                        WEB_CODE_PATH
1967
                                    ).'announcements/announcements.php?action=add&remind_inactive='.$student_id.'&cidReq='.$courseInfo['code'].'" title="'.get_lang(
1968
                                        'RemindInactiveUser'
1969
                                    ).'">
1970
                                      '.Display::return_icon('messagebox_warning.gif').'
1971
                                 </a>'
1972
                                : null;
1973
1974
                            return $icon.Display::label($last_login_date, 'warning');
1975
                        } else {
1976
                            return $last_login_date;
1977
                        }
1978
                    } else {
1979
                        if ($convert_date) {
1980
                            return api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
1981
                        } else {
1982
                            return $last_login_date;                        
1983
                        }
1984
                    }
1985
                }
1986
            }
1987
        }
1988
1989
        return false;
1990
    }
1991
1992
    /**
1993
     * Get count of the connections to the course during a specified period.
1994
     *
1995
     * @param int $courseId
1996
     * @param   int     Session id (optional)
1997
     * @param   int     Datetime from which to collect data (defaults to 0)
1998
     * @param   int     Datetime to which to collect data (defaults to now)
1999
     *
2000
     * @return int count connections
2001
     */
2002
    public static function get_course_connections_count(
2003
        $courseId,
2004
        $session_id = 0,
2005
        $start = 0,
2006
        $stop = null
2007
    ) {
2008
        if ($start < 0) {
2009
            $start = 0;
2010
        }
2011
        if (!isset($stop) or ($stop < 0)) {
2012
            $stop = api_get_utc_datetime();
2013
        }
2014
2015
        // Given we're storing in cache, round the start and end times
2016
        // to the lower minute
2017
        $roundedStart = substr($start, 0, -2).'00';
2018
        $roundedStop = substr($stop, 0, -2).'00';
2019
        $roundedStart = Database::escape_string($roundedStart);
2020
        $roundedStop = Database::escape_string($roundedStop);
2021
        $month_filter = " AND login_course_date > '$roundedStart' AND login_course_date < '$roundedStop' ";
2022
        $courseId = intval($courseId);
2023
        $session_id = intval($session_id);
2024
        $count = 0;
2025
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2026
        $sql = "SELECT count(*) as count_connections
2027
                FROM $table
2028
                WHERE
2029
                    c_id = $courseId AND
2030
                    session_id = $session_id
2031
                    $month_filter";
2032
2033
        //This query can be very slow (several seconds on an indexed table
2034
        // with 14M rows). As such, we'll try to use APCu if it is
2035
        // available to store the resulting value for a few seconds
2036
        $cacheAvailable = api_get_configuration_value('apc');
2037
        if ($cacheAvailable === true) {
2038
            $apc = apcu_cache_info(true);
2039
            $apc_end = $apc['start_time'] + $apc['ttl'];
2040
            $apc_var = api_get_configuration_value('apc_prefix').'course_access_'.$courseId.'_'.$session_id.'_'.strtotime($roundedStart).'_'.strtotime($roundedStop);
2041
            if (apcu_exists($apc_var) && (time() < $apc_end) &&
2042
                apcu_fetch($apc_var) > 0
2043
            ) {
2044
                $count = apcu_fetch($apc_var);
2045
            } else {
2046
                $rs = Database::query($sql);
2047
                if (Database::num_rows($rs) > 0) {
2048
                    $row = Database::fetch_object($rs);
2049
                    $count = $row->count_connections;
2050
                }
2051
                apcu_clear_cache();
2052
                apcu_store($apc_var, $count, 60);
2053
            }
2054
        } else {
2055
            $rs = Database::query($sql);
2056
            if (Database::num_rows($rs) > 0) {
2057
                $row = Database::fetch_object($rs);
2058
                $count = $row->count_connections;
2059
            }
2060
        }
2061
2062
        return $count;
2063
    }
2064
2065
    /**
2066
     * Get count courses per student.
2067
     *
2068
     * @param int  $user_id          Student id
2069
     * @param bool $include_sessions Include sessions (optional)
2070
     *
2071
     * @return int count courses
2072
     */
2073
    public static function count_course_per_student($user_id, $include_sessions = true)
2074
    {
2075
        $user_id = intval($user_id);
2076
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2077
        $tbl_session_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2078
2079
        $sql = 'SELECT DISTINCT c_id
2080
                FROM '.$tbl_course_rel_user.'
2081
                WHERE user_id = '.$user_id.' AND relation_type<>'.COURSE_RELATION_TYPE_RRHH;
2082
        $rs = Database::query($sql);
2083
        $nb_courses = Database::num_rows($rs);
2084
2085
        if ($include_sessions) {
2086
            $sql = 'SELECT DISTINCT c_id
2087
                    FROM '.$tbl_session_course_rel_user.'
2088
                    WHERE user_id = '.$user_id;
2089
            $rs = Database::query($sql);
2090
            $nb_courses += Database::num_rows($rs);
2091
        }
2092
2093
        return $nb_courses;
2094
    }
2095
2096
    /**
2097
     * Gets the score average from all tests in a course by student.
2098
     *
2099
     * @param $student_id
2100
     * @param $course_code
2101
     * @param int  $exercise_id
2102
     * @param null $session_id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $session_id is correct as it would always require null to be passed?
Loading history...
2103
     * @param int  $active_filter 2 for consider all tests
2104
     *                            1 for active <> -1
2105
     *                            0 for active <> 0
2106
     * @param int  $into_lp       1 for all exercises
2107
     *                            0 for without LP
2108
     * @param mixed id
2109
     * @param string code
2110
     * @param int id (optional), filtered by exercise
2111
     * @param int id (optional), if param $session_id is null
2112
     *                                                it'll return results including sessions, 0 = session is not filtered
2113
     *
2114
     * @return string value (number %) Which represents a round integer about the score average
2115
     */
2116
    public static function get_avg_student_exercise_score(
2117
        $student_id,
2118
        $course_code,
2119
        $exercise_id = 0,
2120
        $session_id = null,
2121
        $active_filter = 1,
2122
        $into_lp = 0
2123
    ) {
2124
        $course_code = Database::escape_string($course_code);
2125
        $course_info = api_get_course_info($course_code);
2126
        if (!empty($course_info)) {
2127
            // table definition
2128
            $tbl_course_quiz = Database::get_course_table(TABLE_QUIZ_TEST);
2129
            $tbl_stats_exercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2130
2131
            // Compose a filter based on optional exercise given
2132
            $condition_quiz = "";
2133
            if (!empty($exercise_id)) {
2134
                $exercise_id = intval($exercise_id);
2135
                $condition_quiz = " AND id = $exercise_id ";
2136
            }
2137
2138
            // Compose a filter based on optional session id given
2139
            $condition_session = '';
2140
            if (isset($session_id)) {
2141
                $session_id = intval($session_id);
2142
                $condition_session = " AND session_id = $session_id ";
2143
            }
2144
            if ($active_filter == 1) {
2145
                $condition_active = 'AND active <> -1';
2146
            } elseif ($active_filter == 0) {
2147
                $condition_active = 'AND active <> 0';
2148
            } else {
2149
                $condition_active = '';
2150
            }
2151
            $condition_into_lp = '';
2152
            $select_lp_id = '';
2153
            if ($into_lp == 0) {
2154
                $condition_into_lp = 'AND orig_lp_id = 0 AND orig_lp_item_id = 0';
2155
            } else {
2156
                $select_lp_id = ', orig_lp_id as lp_id ';
2157
            }
2158
2159
            $sql = "SELECT count(id) 
2160
    		        FROM $tbl_course_quiz
2161
    				WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz ";
2162
            $count_quiz = 0;
2163
            $countQuizResult = Database::query($sql);
2164
            if (!empty($countQuizResult)) {
2165
                $count_quiz = Database::fetch_row($countQuizResult);
2166
            }
2167
2168
            if (!empty($count_quiz[0]) && !empty($student_id)) {
2169
                if (is_array($student_id)) {
2170
                    $student_id = array_map('intval', $student_id);
2171
                    $condition_user = " AND exe_user_id IN (".implode(',', $student_id).") ";
2172
                } else {
2173
                    $student_id = intval($student_id);
2174
                    $condition_user = " AND exe_user_id = '$student_id' ";
2175
                }
2176
2177
                if (empty($exercise_id)) {
2178
                    $sql = "SELECT id FROM $tbl_course_quiz
2179
                            WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz";
2180
                    $result = Database::query($sql);
2181
                    $exercise_list = [];
2182
                    $exercise_id = null;
2183
                    if (!empty($result) && Database::num_rows($result)) {
2184
                        while ($row = Database::fetch_array($result)) {
2185
                            $exercise_list[] = $row['id'];
2186
                        }
2187
                    }
2188
                    if (!empty($exercise_list)) {
2189
                        $exercise_id = implode("','", $exercise_list);
2190
                    }
2191
                }
2192
2193
                $count_quiz = Database::fetch_row(Database::query($sql));
2194
                $sql = "SELECT
2195
                        SUM(score/max_score*100) as avg_score,
2196
                        COUNT(*) as num_attempts
2197
                        $select_lp_id
2198
                        FROM $tbl_stats_exercise
2199
                        WHERE
2200
                            exe_exo_id IN ('".$exercise_id."')
2201
                            $condition_user AND
2202
                            status = '' AND
2203
                            c_id = {$course_info['real_id']}
2204
                            $condition_session
2205
                            $condition_into_lp
2206
                        ORDER BY exe_date DESC";
2207
2208
                $res = Database::query($sql);
2209
                $row = Database::fetch_array($res);
2210
                $quiz_avg_score = null;
2211
2212
                if (!empty($row['avg_score'])) {
2213
                    $quiz_avg_score = round($row['avg_score'], 2);
2214
                }
2215
2216
                if (!empty($row['num_attempts'])) {
2217
                    $quiz_avg_score = round($quiz_avg_score / $row['num_attempts'], 2);
2218
                }
2219
                if (is_array($student_id)) {
2220
                    $quiz_avg_score = round($quiz_avg_score / count($student_id), 2);
2221
                }
2222
                if ($into_lp == 0) {
2223
                    return $quiz_avg_score;
2224
                } else {
2225
                    if (!empty($row['lp_id'])) {
2226
                        $tbl_lp = Database::get_course_table(TABLE_LP_MAIN);
2227
                        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2228
                        $sql = "SELECT lp.name
2229
                                FROM $tbl_lp as lp, $tbl_course as c
2230
                                WHERE
2231
                                    c.code = '$course_code' AND
2232
                                    lp.id = ".$row['lp_id']." AND
2233
                                    lp.c_id = c.id
2234
                                LIMIT 1;
2235
                        ";
2236
                        $result = Database::query($sql);
2237
                        $row_lp = Database::fetch_row($result);
2238
                        $lp_name = $row_lp[0];
2239
2240
                        return [$quiz_avg_score, $lp_name];
2241
                    } else {
2242
                        return [$quiz_avg_score, null];
2243
                    }
2244
                }
2245
            }
2246
        }
2247
2248
        return null;
2249
    }
2250
2251
    /**
2252
     * Get count student's exercise COMPLETED attempts.
2253
     *
2254
     * @param int $student_id
2255
     * @param int $courseId
2256
     * @param int $exercise_id
2257
     * @param int $lp_id
2258
     * @param int $lp_item_id
2259
     * @param int $session_id
2260
     * @param int $find_all_lp 0 = just LP specified
2261
     *                         1 = LP specified or whitout LP,
2262
     *                         2 = all rows
2263
     *
2264
     * @internal param \Student $int id
2265
     * @internal param \Course $string code
2266
     * @internal param \Exercise $int id
2267
     * @internal param \Learning $int path id (optional),
2268
     * for showing attempts inside a learning path $lp_id and $lp_item_id params are required
2269
     * @internal param \Learning $int path item id (optional),
2270
     * for showing attempts inside a learning path $lp_id and $lp_item_id params are required
2271
     *
2272
     * @return int count of attempts
2273
     */
2274
    public static function count_student_exercise_attempts(
2275
        $student_id,
2276
        $courseId,
2277
        $exercise_id,
2278
        $lp_id = 0,
2279
        $lp_item_id = 0,
2280
        $session_id = 0,
2281
        $find_all_lp = 0
2282
    ) {
2283
        $courseId = intval($courseId);
2284
        $student_id = intval($student_id);
2285
        $exercise_id = intval($exercise_id);
2286
        $session_id = intval($session_id);
2287
2288
        $lp_id = intval($lp_id);
2289
        $lp_item_id = intval($lp_item_id);
2290
        $tbl_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2291
2292
        $sql = "SELECT COUNT(ex.exe_id) as essais 
2293
                FROM $tbl_stats_exercises AS ex
2294
                WHERE  
2295
                    ex.c_id = $courseId AND 
2296
                    ex.exe_exo_id = $exercise_id AND 
2297
                    status = '' AND 
2298
                    exe_user_id= $student_id AND 
2299
                    session_id = $session_id ";
2300
2301
        if ($find_all_lp == 1) {
2302
            $sql .= "AND (orig_lp_id = $lp_id OR orig_lp_id = 0)
2303
                AND (orig_lp_item_id = $lp_item_id OR orig_lp_item_id = 0)";
2304
        } elseif ($find_all_lp == 0) {
2305
            $sql .= "AND orig_lp_id = $lp_id
2306
                AND orig_lp_item_id = $lp_item_id";
2307
        }
2308
2309
        $rs = Database::query($sql);
2310
        $row = Database::fetch_row($rs);
2311
        $count_attempts = $row[0];
2312
2313
        return $count_attempts;
2314
    }
2315
2316
    /**
2317
     * Get count student's exercise progress.
2318
     *
2319
     * @param array $exercise_list
2320
     * @param int   $user_id
2321
     * @param int   $courseId
2322
     * @param int   $session_id
2323
     *
2324
     * @return string
2325
     */
2326
    public static function get_exercise_student_progress(
2327
        $exercise_list,
2328
        $user_id,
2329
        $courseId,
2330
        $session_id
2331
    ) {
2332
        $courseId = intval($courseId);
2333
        $user_id = intval($user_id);
2334
        $session_id = intval($session_id);
2335
2336
        if (empty($exercise_list)) {
2337
            return '0%';
2338
        }
2339
        $tbl_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2340
        $exercise_list = array_keys($exercise_list);
2341
        $exercise_list = array_map('intval', $exercise_list);
2342
2343
        $exercise_list_imploded = implode("' ,'", $exercise_list);
2344
2345
        $sql = "SELECT COUNT(DISTINCT ex.exe_exo_id)
2346
                FROM $tbl_stats_exercises AS ex
2347
                WHERE
2348
                    ex.c_id = $courseId AND
2349
                    ex.session_id  = $session_id AND
2350
                    ex.exe_user_id = $user_id AND
2351
                    ex.exe_exo_id IN ('$exercise_list_imploded') ";
2352
2353
        $rs = Database::query($sql);
2354
        $count = 0;
2355
        if ($rs) {
2356
            $row = Database::fetch_row($rs);
2357
            $count = $row[0];
2358
        }
2359
        $count = ($count != 0) ? 100 * round(intval($count) / count($exercise_list), 2).'%' : '0%';
2360
2361
        return $count;
2362
    }
2363
2364
    /**
2365
     * @param array $exercise_list
2366
     * @param int   $user_id
2367
     * @param int   $courseId
2368
     * @param int   $session_id
2369
     *
2370
     * @return string
2371
     */
2372
    public static function get_exercise_student_average_best_attempt(
2373
        $exercise_list,
2374
        $user_id,
2375
        $courseId,
2376
        $session_id
2377
    ) {
2378
        $result = 0;
2379
        if (!empty($exercise_list)) {
2380
            foreach ($exercise_list as $exercise_data) {
2381
                $exercise_id = $exercise_data['id'];
2382
                $best_attempt = Event::get_best_attempt_exercise_results_per_user(
2383
                    $user_id,
2384
                    $exercise_id,
2385
                    $courseId,
2386
                    $session_id
2387
                );
2388
2389
                if (!empty($best_attempt) && !empty($best_attempt['max_score'])) {
2390
                    $result += $best_attempt['score'] / $best_attempt['max_score'];
2391
                }
2392
            }
2393
            $result = $result / count($exercise_list);
2394
            $result = round($result, 2) * 100;
2395
        }
2396
2397
        return $result.'%';
2398
    }
2399
2400
    /**
2401
     * get teacher progress by course and session.
2402
     *
2403
     * @param int course id
2404
     * @param int session id
2405
     *
2406
     * @return array
2407
     */
2408
    public static function get_teachers_progress_by_course($courseId, $sessionId)
2409
    {
2410
        $course = api_get_course_info_by_id($courseId);
2411
        $sessionId = intval($sessionId);
2412
        $courseId = intval($courseId);
2413
2414
        $sessionCourseUserTable = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2415
        $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
2416
2417
        //get teachers
2418
        $sql = "SELECT scu.session_id, scu.user_id, s.name
2419
                FROM $sessionCourseUserTable scu, $sessionTable s
2420
                WHERE
2421
                    scu.session_id = s.id
2422
                    AND scu.status = 2
2423
                    AND scu.visibility = 1
2424
                    AND scu.c_id = '%s'
2425
                    AND scu.session_id = %s";
2426
        $query = sprintf($sql, intval($courseId), $sessionId);
2427
        $rs = Database::query($query);
2428
        $teachers = [];
2429
        while ($teacher = Database::fetch_array($rs, 'ASSOC')) {
2430
            $teachers[] = $teacher;
2431
        }
2432
        $data = [];
2433
        foreach ($teachers as $teacher) {
2434
            //total documents added
2435
            $sql = "SELECT count(*) as total
2436
                    FROM c_item_property
2437
                    WHERE lastedit_type = 'DocumentAdded'
2438
                    AND c_id = %s
2439
                    AND insert_user_id = %s
2440
                    AND session_id = %s";
2441
            $query = sprintf(
2442
                $sql,
2443
                $courseId,
2444
                $teacher['user_id'],
2445
                $teacher['session_id']
2446
            );
2447
2448
            $rs = Database::query($query);
2449
            $totalDocuments = 0;
2450
            if ($rs) {
2451
                $row = Database::fetch_row($rs);
2452
                $totalDocuments = $row[0];
2453
            }
2454
            // Total links added
2455
            $sql = "SELECT count(*) as total
2456
                    FROM c_item_property
2457
                    WHERE lastedit_type = 'LinkAdded'
2458
                    AND c_id = %s
2459
                    AND insert_user_id = %s
2460
                    AND session_id = %s";
2461
            $query = sprintf(
2462
                $sql,
2463
                $courseId,
2464
                $teacher['user_id'],
2465
                $teacher['session_id']
2466
            );
2467
            $rs = Database::query($query);
2468
2469
            $totalLinks = 0;
2470
            if ($rs) {
2471
                $row = Database::fetch_row($rs);
2472
                $totalLinks = $row[0];
2473
            }
2474
            //total forums added
2475
            $sql = "SELECT count(*) as total
2476
                    FROM c_item_property
2477
                    WHERE lastedit_type = 'ForumthreadVisible'
2478
                    AND c_id = %s
2479
                    AND insert_user_id = %s
2480
                    AND session_id = %s";
2481
            $query = sprintf(
2482
                $sql,
2483
                $courseId,
2484
                $teacher['user_id'],
2485
                $teacher['session_id']
2486
            );
2487
            $rs = Database::query($query);
2488
2489
            $totalForums = 0;
2490
            if ($rs) {
2491
                $row = Database::fetch_row($rs);
2492
                $totalForums = $row[0];
2493
            }
2494
2495
            //total wikis added
2496
            $sql = "SELECT COUNT(DISTINCT(ref)) as total
2497
                    FROM c_item_property
2498
                    WHERE lastedit_type = 'WikiAdded'
2499
                    AND c_id = %s
2500
                    AND insert_user_id = %s
2501
                    AND session_id = %s";
2502
2503
            $query = sprintf(
2504
                $sql,
2505
                $courseId,
2506
                $teacher['user_id'],
2507
                $teacher['session_id']
2508
            );
2509
2510
            $rs = Database::query($query);
2511
2512
            $totalWikis = 0;
2513
            if ($rs) {
2514
                $row = Database::fetch_row($rs);
2515
                $totalWikis = $row[0];
2516
            }
2517
2518
            // Total works added
2519
            $sql = "SELECT COUNT(*) as total
2520
                    FROM c_item_property
2521
                    WHERE lastedit_type = 'DirectoryCreated'
2522
                    AND tool = 'work'
2523
                    AND c_id = %s
2524
                    AND insert_user_id = %s
2525
                    AND session_id = %s";
2526
            $query = sprintf(
2527
                $sql,
2528
                $courseId,
2529
                $teacher['user_id'],
2530
                $teacher['session_id']
2531
            );
2532
            $rs = Database::query($query);
2533
2534
            $totalWorks = 0;
2535
            if ($rs) {
2536
                $row = Database::fetch_row($rs);
2537
                $totalWorks = $row[0];
2538
            }
2539
            //total announcements added
2540
            $sql = "SELECT COUNT(*) as total
2541
                    FROM c_item_property
2542
                    WHERE lastedit_type = 'AnnouncementAdded'
2543
                    AND c_id = %s
2544
                    AND insert_user_id = %s
2545
                    AND session_id = %s";
2546
            $query = sprintf(
2547
                $sql,
2548
                $courseId,
2549
                $teacher['user_id'],
2550
                $teacher['session_id']
2551
            );
2552
            $rs = Database::query($query);
2553
2554
            $totalAnnouncements = 0;
2555
            if ($rs) {
2556
                $row = Database::fetch_row($rs);
2557
                $totalAnnouncements = $row[0];
2558
            }
2559
            $tutor = api_get_user_info($teacher['user_id']);
2560
            $data[] = [
2561
                'course' => $course['title'],
2562
                'session' => $teacher['name'],
2563
                'tutor' => $tutor['username'].' - '.$tutor['lastname'].' '.$tutor['firstname'],
2564
                'documents' => $totalDocuments,
2565
                'links' => $totalLinks,
2566
                'forums' => $totalForums,
2567
                'works' => $totalWorks,
2568
                'wikis' => $totalWikis,
2569
                'announcements' => $totalAnnouncements,
2570
            ];
2571
        }
2572
2573
        return $data;
2574
    }
2575
2576
    /**
2577
     * Returns the average student progress in the learning paths of the given
2578
     * course, it will take into account the progress that were not started.
2579
     *
2580
     * @param int|array $studentId
2581
     * @param string    $courseCode
2582
     * @param array     $lpIdList        Limit average to listed lp ids
2583
     * @param int       $sessionId       Session id (optional),
2584
     *                                   if parameter $session_id is null(default) it'll return results including
2585
     *                                   sessions, 0 = session is not filtered
2586
     * @param bool      $returnArray     Will return an array of the type:
2587
     *                                   [sum_of_progresses, number] if it is set to true
2588
     * @param bool      $onlySeriousGame Optional. Limit average to lp on seriousgame mode
2589
     *
2590
     * @return float Average progress of the user in this course
2591
     */
2592
    public static function get_avg_student_progress(
2593
        $studentId,
2594
        $courseCode = null,
2595
        $lpIdList = [],
2596
        $sessionId = null,
2597
        $returnArray = false,
2598
        $onlySeriousGame = false
2599
    ) {
2600
        // If there is at least one learning path and one student.
2601
        if (empty($studentId)) {
2602
            return false;
2603
        }
2604
2605
        $sessionId = intval($sessionId);
2606
        $courseInfo = api_get_course_info($courseCode);
2607
2608
        if (empty($courseInfo)) {
2609
            return false;
2610
        }
2611
2612
        $lPTable = Database::get_course_table(TABLE_LP_MAIN);
2613
        $lpViewTable = Database::get_course_table(TABLE_LP_VIEW);
2614
        $lpConditions = [];
2615
        $lpConditions['c_id = ? '] = $courseInfo['real_id'];
2616
2617
        if ($sessionId > 0) {
2618
            $lpConditions['AND (session_id = ? OR session_id = 0 OR session_id IS NULL)'] = $sessionId;
2619
        } else {
2620
            $lpConditions['AND session_id = ?'] = $sessionId;
2621
        }
2622
2623
        if (is_array($lpIdList) && count($lpIdList) > 0) {
2624
            $placeHolders = [];
2625
            for ($i = 0; $i < count($lpIdList); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
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
}
Loading history...
2626
                $placeHolders[] = '?';
2627
            }
2628
            $lpConditions['AND id IN('.implode(', ', $placeHolders).') '] = $lpIdList;
2629
        }
2630
2631
        if ($onlySeriousGame) {
2632
            $lpConditions['AND seriousgame_mode = ? '] = true;
2633
        }
2634
2635
        $resultLP = Database::select(
2636
            'id',
2637
            $lPTable,
2638
            ['where' => $lpConditions]
2639
        );
2640
        $filteredLP = array_keys($resultLP);
2641
2642
        if (empty($filteredLP)) {
2643
            return false;
2644
        }
2645
2646
        $conditions = [
2647
            " c_id = {$courseInfo['real_id']} ",
2648
            " lp_view.lp_id IN(".implode(', ', $filteredLP).") ",
2649
        ];
2650
2651
        $groupBy = 'GROUP BY lp_id';
2652
2653
        if (is_array($studentId)) {
2654
            $studentId = array_map('intval', $studentId);
2655
            $conditions[] = " lp_view.user_id IN (".implode(',', $studentId).")  ";
2656
        } else {
2657
            $studentId = intval($studentId);
2658
            $conditions[] = " lp_view.user_id = '$studentId' ";
2659
2660
            if (empty($lpIdList)) {
2661
                $lpList = new LearnpathList(
2662
                    $studentId,
2663
                    $courseCode,
2664
                    $sessionId,
2665
                    null,
2666
                    false,
2667
                    null,
2668
                    true
2669
                );
2670
                $lpList = $lpList->get_flat_list();
2671
                if (!empty($lpList)) {
2672
                    /** @var $lp */
2673
                    foreach ($lpList as $lpId => $lp) {
2674
                        $lpIdList[] = $lp['lp_old_id'];
2675
                    }
2676
                }
2677
            }
2678
        }
2679
2680
        if (!empty($sessionId)) {
2681
            $conditions[] = " session_id = $sessionId ";
2682
        } else {
2683
            $conditions[] = ' (session_id = 0 OR session_id IS NULL) ';
2684
        }
2685
2686
        $conditionToString = implode('AND', $conditions);
2687
        $sql = "SELECT lp_id, view_count, progress 
2688
                FROM $lpViewTable lp_view
2689
                WHERE
2690
                    $conditionToString
2691
                    $groupBy
2692
                ORDER BY view_count DESC";
2693
2694
        $result = Database::query($sql);
2695
2696
        $progress = [];
2697
        $viewCount = [];
2698
        while ($row = Database::fetch_array($result, 'ASSOC')) {
2699
            if (!isset($viewCount[$row['lp_id']])) {
2700
                $progress[$row['lp_id']] = $row['progress'];
2701
            }
2702
            $viewCount[$row['lp_id']] = $row['view_count'];
2703
        }
2704
2705
        // Fill with lp ids
2706
        $newProgress = [];
2707
        if (!empty($lpIdList)) {
2708
            foreach ($lpIdList as $lpId) {
2709
                if (isset($progress[$lpId])) {
2710
                    $newProgress[] = $progress[$lpId];
2711
                }
2712
            }
2713
            $total = count($lpIdList);
2714
        } else {
2715
            $newProgress = $progress;
2716
            $total = count($newProgress);
2717
        }
2718
2719
        $average = 0;
2720
        $sum = 0;
2721
        if (!empty($newProgress)) {
2722
            $sum = array_sum($newProgress);
2723
            $average = $sum / $total;
2724
        }
2725
2726
        if ($returnArray) {
2727
            return [
2728
                $sum,
2729
                $total,
2730
            ];
2731
        }
2732
2733
        return round($average, 1);
2734
    }
2735
2736
    /**
2737
     * This function gets:
2738
     * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores.
2739
     * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores.
2740
     * 3. And finally it will return the average between 1. and 2.
2741
     *
2742
     * @todo improve performance, when loading 1500 users with 20 lps the script dies
2743
     * This function does not take the results of a Test out of a LP
2744
     *
2745
     * @param mixed  $student_id                      Array of user ids or an user id
2746
     * @param string $course_code
2747
     * @param array  $lp_ids                          List of LP ids
2748
     * @param int    $session_id                      Session id (optional),
2749
     *                                                if param $session_id is null(default) it'll return results
2750
     *                                                including sessions, 0 = session is not filtered
2751
     * @param bool   $return_array                    Returns an array of the
2752
     *                                                type [sum_score, num_score] if set to true
2753
     * @param bool   $get_only_latest_attempt_results get only the latest attempts or ALL attempts
2754
     * @param bool   $getOnlyBestAttempt
2755
     *
2756
     * @return string value (number %) Which represents a round integer explain in got in 3
2757
     */
2758
    public static function get_avg_student_score(
2759
        $student_id,
2760
        $course_code,
2761
        $lp_ids = [],
2762
        $session_id = null,
2763
        $return_array = false,
2764
        $get_only_latest_attempt_results = false,
2765
        $getOnlyBestAttempt = false
2766
    ) {
2767
        $debug = false;
2768
        if ($debug) {
2769
            echo '<h1>Tracking::get_avg_student_score</h1>';
2770
        }
2771
        $tbl_stats_exercices = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2772
        $tbl_stats_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
2773
        $course = api_get_course_info($course_code);
2774
        if (!empty($course)) {
2775
            // Get course tables names
2776
            $tbl_quiz_questions = Database::get_course_table(TABLE_QUIZ_QUESTION);
2777
            $lp_table = Database::get_course_table(TABLE_LP_MAIN);
2778
            $lp_item_table = Database::get_course_table(TABLE_LP_ITEM);
2779
            $lp_view_table = Database::get_course_table(TABLE_LP_VIEW);
2780
            $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW);
2781
            $course_id = $course['real_id'];
2782
2783
            // Compose a filter based on optional learning paths list given
2784
            $condition_lp = '';
2785
            if (count($lp_ids) > 0) {
2786
                $condition_lp = " AND id IN(".implode(',', $lp_ids).") ";
2787
            }
2788
2789
            // Compose a filter based on optional session id
2790
            $session_id = intval($session_id);
2791
            if (count($lp_ids) > 0) {
2792
                $condition_session = " AND session_id = $session_id ";
2793
            } else {
2794
                $condition_session = " WHERE session_id = $session_id ";
2795
            }
2796
2797
            // Check the real number of LPs corresponding to the filter in the
2798
            // database (and if no list was given, get them all)
2799
            if (empty($session_id)) {
2800
                $sql = "SELECT DISTINCT(id), use_max_score
2801
                        FROM $lp_table
2802
                        WHERE 
2803
                            c_id = $course_id AND 
2804
                            (session_id = 0 OR session_id IS NULL) $condition_lp ";
2805
            } else {
2806
                $sql = "SELECT DISTINCT(id), use_max_score
2807
                        FROM $lp_table
2808
                        WHERE c_id = $course_id $condition_lp ";
2809
            }
2810
2811
            $res_row_lp = Database::query($sql);
2812
            $count_row_lp = Database::num_rows($res_row_lp);
2813
2814
            $lp_list = $use_max_score = [];
2815
            while ($row_lp = Database::fetch_array($res_row_lp)) {
2816
                $lp_list[] = $row_lp['id'];
2817
                $use_max_score[$row_lp['id']] = $row_lp['use_max_score'];
2818
            }
2819
2820
            if ($debug) {
2821
                echo '$lp_list: ';
2822
                var_dump($lp_list);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($lp_list) looks like debug code. Are you sure you do not want to remove it?
Loading history...
2823
                echo 'Use max score or not list: ';
2824
                var_dump($use_max_score);
2825
            }
2826
2827
            // prepare filter on users
2828
            if (is_array($student_id)) {
2829
                array_walk($student_id, 'intval');
2830
                $condition_user1 = " AND user_id IN (".implode(',', $student_id).") ";
2831
            } else {
2832
                $condition_user1 = " AND user_id = $student_id ";
2833
            }
2834
2835
            if ($count_row_lp > 0 && !empty($student_id)) {
2836
                // Getting latest LP result for a student
2837
                //@todo problem when a  course have more than 1500 users
2838
                $sql = "SELECT MAX(view_count) as vc, id, progress, lp_id, user_id
2839
                        FROM $lp_view_table
2840
                        WHERE
2841
                            c_id = $course_id AND
2842
                            lp_id IN (".implode(',', $lp_list).")
2843
                            $condition_user1 AND
2844
                            session_id = $session_id
2845
                        GROUP BY lp_id, user_id";
2846
                if ($debug) {
2847
                    echo 'get LP results';
2848
                    var_dump($sql);
2849
                }
2850
2851
                $rs_last_lp_view_id = Database::query($sql);
2852
                $global_result = 0;
2853
2854
                if (Database::num_rows($rs_last_lp_view_id) > 0) {
2855
                    // Cycle through each line of the results (grouped by lp_id, user_id)
2856
                    while ($row_lp_view = Database::fetch_array($rs_last_lp_view_id)) {
2857
                        $count_items = 0;
2858
                        $lpPartialTotal = 0;
2859
                        $list = [];
2860
                        $lp_view_id = $row_lp_view['id'];
2861
                        $lp_id = $row_lp_view['lp_id'];
2862
                        $user_id = $row_lp_view['user_id'];
2863
2864
                        if ($debug) {
2865
                            echo '<h2>LP id '.$lp_id.'</h2>';
2866
                            echo "get_only_latest_attempt_results: $get_only_latest_attempt_results <br />";
2867
                            echo "getOnlyBestAttempt: $getOnlyBestAttempt <br />";
2868
                        }
2869
2870
                        if ($get_only_latest_attempt_results || $getOnlyBestAttempt) {
2871
                            // Getting lp_items done by the user
2872
                            $sql = "SELECT DISTINCT lp_item_id
2873
                                    FROM $lp_item_view_table
2874
                                    WHERE
2875
                                        c_id = $course_id AND
2876
                                        lp_view_id = $lp_view_id
2877
                                    ORDER BY lp_item_id";
2878
                            $res_lp_item = Database::query($sql);
2879
                            if ($debug) {
2880
                                echo 'Getting lp_items done by the user<br />';
2881
                                var_dump($sql);
2882
                            }
2883
2884
                            while ($row_lp_item = Database::fetch_array($res_lp_item, 'ASSOC')) {
2885
                                $my_lp_item_id = $row_lp_item['lp_item_id'];
2886
                                $order = ' view_count DESC';
2887
                                if ($getOnlyBestAttempt) {
2888
                                    $order = ' lp_iv.score DESC';
2889
                                }
2890
2891
                                // Getting the most recent attempt
2892
                                $sql = "SELECT  
2893
                                            lp_iv.id as lp_item_view_id,
2894
                                            lp_iv.score as score,
2895
                                            lp_i.max_score,
2896
                                            lp_iv.max_score as max_score_item_view,
2897
                                            lp_i.path,
2898
                                            lp_i.item_type,
2899
                                            lp_i.id as iid
2900
                                        FROM $lp_item_view_table as lp_iv
2901
                                        INNER JOIN $lp_item_table as lp_i
2902
                                        ON (
2903
                                            lp_i.id = lp_iv.lp_item_id AND 
2904
                                            lp_iv.c_id = lp_i.c_id
2905
                                        )                                            
2906
                                        WHERE
2907
                                            lp_iv.c_id = $course_id AND
2908
                                            lp_i.c_id  = $course_id AND
2909
                                            lp_item_id = $my_lp_item_id AND
2910
                                            lp_view_id = $lp_view_id AND
2911
                                            (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."')
2912
                                        ORDER BY $order
2913
                                        LIMIT 1";
2914
2915
                                $res_lp_item_result = Database::query($sql);
2916
                                while ($row_max_score = Database::fetch_array($res_lp_item_result, 'ASSOC')) {
2917
                                    $list[] = $row_max_score;
2918
                                }
2919
                            }
2920
                        } else {
2921
                            // For the currently analysed view, get the score and
2922
                            // max_score of each item if it is a sco or a TOOL_QUIZ
2923
                            $sql = "SELECT
2924
                                        lp_iv.id as lp_item_view_id,
2925
                                        lp_iv.score as score,
2926
                                        lp_i.max_score,
2927
                                        lp_iv.max_score as max_score_item_view,
2928
                                        lp_i.path,
2929
                                        lp_i.item_type,
2930
                                        lp_i.id as iid
2931
                                      FROM $lp_item_view_table as lp_iv
2932
                                      INNER JOIN $lp_item_table as lp_i
2933
                                      ON lp_i.id = lp_iv.lp_item_id AND
2934
                                         lp_iv.c_id = lp_i.c_id
2935
                                      WHERE 
2936
                                        lp_iv.c_id = $course_id AND 
2937
                                        lp_i.c_id  = $course_id AND
2938
                                        lp_view_id = $lp_view_id AND
2939
                                        (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."')
2940
                                    ";
2941
                            $res_max_score = Database::query($sql);
2942
                            while ($row_max_score = Database::fetch_array($res_max_score, 'ASSOC')) {
2943
                                $list[] = $row_max_score;
2944
                            }
2945
                        }
2946
2947
                        // Go through each scorable element of this view
2948
                        $score_of_scorm_calculate = 0;
2949
                        foreach ($list as $row_max_score) {
2950
                            // Came from the original lp_item
2951
                            $max_score = $row_max_score['max_score'];
2952
                            // Came from the lp_item_view
2953
                            $max_score_item_view = $row_max_score['max_score_item_view'];
2954
                            $score = $row_max_score['score'];
2955
                            if ($debug) {
2956
                                echo '<h3>Item Type: '.$row_max_score['item_type'].'</h3>';
2957
                            }
2958
2959
                            if ($row_max_score['item_type'] == 'sco') {
2960
                                /* Check if it is sco (easier to get max_score)
2961
                                   when there's no max score, we assume 100 as the max score,
2962
                                   as the SCORM 1.2 says that the value should always be between 0 and 100.
2963
                                */
2964
                                if ($max_score == 0 || is_null($max_score) || $max_score == '') {
2965
                                    // Chamilo style
2966
                                    if ($use_max_score[$lp_id]) {
2967
                                        $max_score = 100;
2968
                                    } else {
2969
                                        // Overwrites max score = 100 to use the one that came in the lp_item_view see BT#1613
2970
                                        $max_score = $max_score_item_view;
2971
                                    }
2972
                                }
2973
                                // Avoid division by zero errors
2974
                                if (!empty($max_score)) {
2975
                                    $lpPartialTotal += $score / $max_score;
2976
                                }
2977
                                if ($debug) {
2978
                                    var_dump("lpPartialTotal: $lpPartialTotal");
2979
                                    var_dump("score: $score");
2980
                                    var_dump("max_score: $max_score");
2981
                                }
2982
                            } else {
2983
                                // Case of a TOOL_QUIZ element
2984
                                $item_id = $row_max_score['iid'];
2985
                                $item_path = $row_max_score['path'];
2986
                                $lp_item_view_id = (int) $row_max_score['lp_item_view_id'];
2987
2988
                                $lpItemCondition = '';
2989
                                if (empty($lp_item_view_id)) {
2990
                                    $lpItemCondition = ' (orig_lp_item_view_id = 0 OR orig_lp_item_view_id IS NULL) ';
2991
                                } else {
2992
                                    $lpItemCondition = " orig_lp_item_view_id = $lp_item_view_id ";
2993
                                }
2994
2995
                                // Get last attempt to this exercise through
2996
                                // the current lp for the current user
2997
                                $order = 'exe_date DESC';
2998
                                if ($getOnlyBestAttempt) {
2999
                                    $order = 'score DESC';
3000
                                }
3001
                                $sql = "SELECT exe_id, score
3002
                                        FROM $tbl_stats_exercices
3003
                                        WHERE
3004
                                            exe_exo_id = '$item_path' AND
3005
                                            exe_user_id = $user_id AND
3006
                                            orig_lp_item_id = $item_id AND
3007
                                            $lpItemCondition AND
3008
                                            c_id = $course_id AND
3009
                                            session_id = $session_id AND
3010
                                            status = ''
3011
                                        ORDER BY $order
3012
                                        LIMIT 1";
3013
3014
                                $result_last_attempt = Database::query($sql);
3015
                                if ($debug) {
3016
                                    var_dump($sql);
3017
                                }
3018
                                $num = Database::num_rows($result_last_attempt);
3019
                                if ($num > 0) {
3020
                                    $attemptResult = Database::fetch_array($result_last_attempt, 'ASSOC');
3021
                                    $id_last_attempt = $attemptResult['exe_id'];
3022
                                    // We overwrite the score with the best one not the one saved in the LP (latest)
3023
                                    if ($getOnlyBestAttempt && $get_only_latest_attempt_results == false) {
3024
                                        if ($debug) {
3025
                                            echo "Following score comes from the track_exercise table not in the LP because the score is the best<br />";
3026
                                        }
3027
                                        $score = $attemptResult['score'];
3028
                                    }
3029
3030
                                    if ($debug) {
3031
                                        echo "Attempt id: $id_last_attempt with score $score<br />";
3032
                                    }
3033
                                    // Within the last attempt number tracking, get the sum of
3034
                                    // the max_scores of all questions that it was
3035
                                    // made of (we need to make this call dynamic because of random questions selection)
3036
                                    $sql = "SELECT SUM(t.ponderation) as maxscore FROM
3037
                                            (
3038
                                                SELECT DISTINCT
3039
                                                    question_id,
3040
                                                    marks,
3041
                                                    ponderation
3042
                                                FROM $tbl_stats_attempts AS at
3043
                                                INNER JOIN $tbl_quiz_questions AS q
3044
                                                ON (q.id = at.question_id AND q.c_id = q.c_id)
3045
                                                WHERE
3046
                                                    exe_id ='$id_last_attempt' AND
3047
                                                    q.c_id = $course_id
3048
                                            )
3049
                                            AS t";
3050
3051
                                    $res_max_score_bis = Database::query($sql);
3052
                                    $row_max_score_bis = Database::fetch_array($res_max_score_bis);
3053
3054
                                    if (!empty($row_max_score_bis['maxscore'])) {
3055
                                        $max_score = $row_max_score_bis['maxscore'];
3056
                                    }
3057
                                    if (!empty($max_score) && floatval($max_score) > 0) {
3058
                                        $lpPartialTotal += $score / $max_score;
3059
                                    }
3060
                                    if ($debug) {
3061
                                        var_dump("score: $score");
3062
                                        var_dump("max_score: $max_score");
3063
                                        var_dump("lpPartialTotal: $lpPartialTotal");
3064
                                    }
3065
                                }
3066
                            }
3067
3068
                            if (in_array($row_max_score['item_type'], ['quiz', 'sco'])) {
3069
                                // Normal way
3070
                                if ($use_max_score[$lp_id]) {
3071
                                    $count_items++;
3072
                                } else {
3073
                                    if ($max_score != '') {
3074
                                        $count_items++;
3075
                                    }
3076
                                }
3077
                                if ($debug) {
3078
                                    echo '$count_items: '.$count_items;
3079
                                }
3080
                            }
3081
                        } //end for
3082
3083
                        $score_of_scorm_calculate += $count_items ? (($lpPartialTotal / $count_items) * 100) : 0;
3084
                        $global_result += $score_of_scorm_calculate;
3085
3086
                        if ($debug) {
3087
                            var_dump("count_items: $count_items");
3088
                            var_dump("score_of_scorm_calculate: $score_of_scorm_calculate");
3089
                            var_dump("global_result: $global_result");
3090
                        }
3091
                    } // end while
3092
                }
3093
3094
                $lp_with_quiz = 0;
3095
                foreach ($lp_list as $lp_id) {
3096
                    // Check if LP have a score we assume that all SCO have an score
3097
                    $sql = "SELECT count(id) as count
3098
                            FROM $lp_item_table
3099
                            WHERE
3100
                                c_id = $course_id AND
3101
                                (item_type = 'quiz' OR item_type = 'sco') AND
3102
                                lp_id = ".$lp_id;
3103
                    if ($debug) {
3104
                        var_dump($sql);
3105
                    }
3106
                    $result_have_quiz = Database::query($sql);
3107
                    if (Database::num_rows($result_have_quiz) > 0) {
3108
                        $row = Database::fetch_array($result_have_quiz, 'ASSOC');
3109
                        if (is_numeric($row['count']) && $row['count'] != 0) {
3110
                            $lp_with_quiz++;
3111
                        }
3112
                    }
3113
                }
3114
3115
                if ($debug) {
3116
                    echo '<h3>$lp_with_quiz '.$lp_with_quiz.' </h3>';
3117
                }
3118
                if ($debug) {
3119
                    echo '<h3>Final return</h3>';
3120
                }
3121
3122
                if ($lp_with_quiz != 0) {
3123
                    if (!$return_array) {
3124
                        $score_of_scorm_calculate = round(($global_result / $lp_with_quiz), 2);
3125
                        if ($debug) {
3126
                            var_dump($score_of_scorm_calculate);
3127
                        }
3128
                        if (empty($lp_ids)) {
3129
                            if ($debug) {
3130
                                echo '<h2>All lps fix: '.$score_of_scorm_calculate.'</h2>';
3131
                            }
3132
                        }
3133
3134
                        return $score_of_scorm_calculate;
3135
                    } else {
3136
                        if ($debug) {
3137
                            var_dump($global_result, $lp_with_quiz);
3138
                        }
3139
3140
                        return [$global_result, $lp_with_quiz];
3141
                    }
3142
                } else {
3143
                    return '-';
3144
                }
3145
            }
3146
        }
3147
3148
        return null;
3149
    }
3150
3151
    /**
3152
     * This function gets:
3153
     * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores.
3154
     * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores.
3155
     * 3. And finally it will return the average between 1. and 2.
3156
     * This function does not take the results of a Test out of a LP.
3157
     *
3158
     * @param   int|array   Array of user ids or an user id
3159
     * @param string $course_code Course code
3160
     * @param array  $lp_ids      List of LP ids
3161
     * @param int    $session_id  Session id (optional), if param $session_id is 0(default)
3162
     *                            it'll return results including sessions, 0 = session is not filtered
3163
     * @param   bool        Returns an array of the type [sum_score, num_score] if set to true
3164
     * @param   bool        get only the latest attempts or ALL attempts
3165
     *
3166
     * @return string value (number %) Which represents a round integer explain in got in 3
3167
     */
3168
    public static function getAverageStudentScore(
3169
        $student_id,
3170
        $course_code = '',
3171
        $lp_ids = [],
3172
        $session_id = 0
3173
    ) {
3174
        if (empty($student_id)) {
3175
            return 0;
3176
        }
3177
3178
        $conditions = [];
3179
        if (!empty($course_code)) {
3180
            $course = api_get_course_info($course_code);
3181
            $courseId = $course['real_id'];
3182
            $conditions[] = " c_id = $courseId";
3183
        }
3184
3185
        // Get course tables names
3186
        $lp_table = Database::get_course_table(TABLE_LP_MAIN);
3187
        $lp_item_table = Database::get_course_table(TABLE_LP_ITEM);
3188
        $lp_view_table = Database::get_course_table(TABLE_LP_VIEW);
3189
        $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3190
3191
        // Compose a filter based on optional learning paths list given
3192
        if (!empty($lp_ids) && count($lp_ids) > 0) {
3193
            $conditions[] = " id IN(".implode(',', $lp_ids).") ";
3194
        }
3195
3196
        // Compose a filter based on optional session id
3197
        $session_id = intval($session_id);
3198
        if (!empty($session_id)) {
3199
            $conditions[] = " session_id = $session_id ";
3200
        }
3201
3202
        if (is_array($student_id)) {
3203
            array_walk($student_id, 'intval');
3204
            $conditions[] = " lp_view.user_id IN (".implode(',', $student_id).") ";
3205
        } else {
3206
            $conditions[] = " lp_view.user_id = $student_id ";
3207
        }
3208
3209
        $conditionsToString = implode('AND ', $conditions);
3210
        $sql = "SELECT
3211
                    SUM(lp_iv.score) sum_score,
3212
                    SUM(lp_i.max_score) sum_max_score
3213
                FROM $lp_table as lp
3214
                INNER JOIN $lp_item_table as lp_i
3215
                ON lp.id = lp_id AND lp.c_id = lp_i.c_id
3216
                INNER JOIN $lp_view_table as lp_view
3217
                ON lp_view.lp_id = lp_i.lp_id AND lp_view.c_id = lp_i.c_id
3218
                INNER JOIN $lp_item_view_table as lp_iv
3219
                ON lp_i.id = lp_iv.lp_item_id AND lp_view.c_id = lp_iv.c_id AND lp_iv.lp_view_id = lp_view.id
3220
                WHERE (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."') AND
3221
                $conditionsToString
3222
        ";
3223
        $result = Database::query($sql);
3224
        $row = Database::fetch_array($result, 'ASSOC');
3225
3226
        if (empty($row['sum_max_score'])) {
3227
            return 0;
3228
        }
3229
3230
        return ($row['sum_score'] / $row['sum_max_score']) * 100;
3231
    }
3232
3233
    /**
3234
     * This function gets time spent in learning path for a student inside a course.
3235
     *
3236
     * @param int|array $student_id  Student id(s)
3237
     * @param string    $course_code Course code
3238
     * @param array     $lp_ids      Limit average to listed lp ids
3239
     * @param int       $session_id  Session id (optional), if param $session_id is null(default)
3240
     *                               it'll return results including sessions, 0 = session is not filtered
3241
     *
3242
     * @return int Total time
3243
     */
3244
    public static function get_time_spent_in_lp(
3245
        $student_id,
3246
        $course_code,
3247
        $lp_ids = [],
3248
        $session_id = 0
3249
    ) {
3250
        $course = api_get_course_info($course_code);
3251
        $student_id = (int) $student_id;
3252
        $session_id = (int) $session_id;
3253
        $total_time = 0;
3254
3255
        if (!empty($course)) {
3256
            $lpTable = Database::get_course_table(TABLE_LP_MAIN);
3257
            $lpItemTable = Database::get_course_table(TABLE_LP_ITEM);
3258
            $lpViewTable = Database::get_course_table(TABLE_LP_VIEW);
3259
            $lpItemViewTable = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3260
            $trackExercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
3261
            $course_id = $course['real_id'];
3262
3263
            // Compose a filter based on optional learning paths list given
3264
            $condition_lp = '';
3265
            if (count($lp_ids) > 0) {
3266
                $condition_lp = " AND id IN(".implode(',', $lp_ids).") ";
3267
            }
3268
3269
            // Check the real number of LPs corresponding to the filter in the
3270
            // database (and if no list was given, get them all)
3271
            $sql = "SELECT DISTINCT(id) FROM $lpTable 
3272
                    WHERE c_id = $course_id $condition_lp";
3273
            $result = Database::query($sql);
3274
            $session_condition = api_get_session_condition($session_id);
3275
3276
            // calculates time
3277
            if (Database::num_rows($result) > 0) {
3278
                while ($row = Database::fetch_array($result)) {
3279
                    $lp_id = (int) $row['id'];
3280
3281
                    // Start Exercise in LP total_time
3282
                    // Get duration time from track_e_exercises.exe_duration instead of lp_view_item.total_time
3283
                    $list = learnpath::get_flat_ordered_items_list($lp_id, 0, $course_id);
3284
                    foreach ($list as $itemId) {
3285
                        $sql = "SELECT max(view_count)
3286
                                FROM $lpViewTable
3287
                                WHERE
3288
                                    c_id = $course_id AND
3289
                                    lp_id = $lp_id AND
3290
                                    user_id = $student_id
3291
                                    $session_condition";
3292
                        $res = Database::query($sql);
3293
                        $view = '';
3294
                        if (Database::num_rows($res) > 0) {
3295
                            $myrow = Database::fetch_array($res);
3296
                            $view = $myrow[0];
3297
                        }
3298
                        $viewCondition = null;
3299
                        if (!empty($view)) {
3300
                            $viewCondition = " AND v.view_count = $view  ";
3301
                        }
3302
                        $sql = "SELECT
3303
                            iv.iid,                                             
3304
                            iv.total_time as mytime,
3305
                            i.id as myid,
3306
                            iv.view_count as iv_view_count,                            
3307
                            path
3308
                        FROM $lpItemTable as i
3309
                        INNER JOIN $lpItemViewTable as iv
3310
                        ON (i.id = iv.lp_item_id AND i.c_id = iv.c_id)
3311
                        INNER JOIN $lpViewTable as v
3312
                        ON (iv.lp_view_id = v.id AND v.c_id = iv.c_id)
3313
                        WHERE
3314
                            v.c_id = $course_id AND
3315
                            i.id = $itemId AND
3316
                            i.lp_id = $lp_id  AND
3317
                            v.user_id = $student_id AND
3318
                            item_type = 'quiz' AND 
3319
                            path <> '' AND
3320
                            v.session_id = $session_id
3321
                            $viewCondition
3322
                        ORDER BY iv.view_count DESC ";
3323
3324
                        $resultRow = Database::query($sql);
3325
                        if (Database::num_rows($resultRow)) {
3326
                            $row = Database::fetch_array($resultRow);
3327
                            $totalTimeInLpItemView = $row['mytime'];
3328
                            $lpItemViewId = $row['iid'];
3329
3330
                            $sql = 'SELECT SUM(exe_duration) exe_duration 
3331
                                    FROM '.$trackExercises.'
3332
                                    WHERE
3333
                                        exe_exo_id="'.$row['path'].'" AND
3334
                                        exe_user_id="'.$student_id.'" AND
3335
                                        orig_lp_id = "'.$lp_id.'" AND
3336
                                        orig_lp_item_id = "'.$row['myid'].'" AND
3337
                                        c_id = '.$course_id.' AND
3338
                                        status <> "incomplete" AND
3339
                                        session_id = '.$session_id.'
3340
                                     ORDER BY exe_date DESC ';
3341
3342
                            $sumScoreResult = Database::query($sql);
3343
                            $durationRow = Database::fetch_array($sumScoreResult, 'ASSOC');
3344
                            if (!empty($durationRow['exe_duration'])) {
3345
                                $exeDuration = $durationRow['exe_duration'];
3346
                                if ($exeDuration != $totalTimeInLpItemView &&
3347
                                    !empty($lpItemViewId) &&
3348
                                    !empty($exeDuration)
3349
                                ) {
3350
                                    // Update c_lp_item_view.total_time
3351
                                    $sqlUpdate = "UPDATE $lpItemViewTable SET total_time = '$exeDuration' 
3352
                                                  WHERE iid = ".$lpItemViewId;
3353
                                    Database::query($sqlUpdate);
3354
                                }
3355
                            }
3356
                        }
3357
                    }
3358
3359
                    // End total_time fix
3360
3361
                    // Calculate total time
3362
                    $sql = "SELECT SUM(total_time)
3363
                            FROM $lpItemViewTable AS item_view
3364
                            INNER JOIN $lpViewTable AS view
3365
                            ON (
3366
                                item_view.lp_view_id = view.id AND
3367
                                item_view.c_id = view.c_id
3368
                            )
3369
                            WHERE
3370
                                item_view.c_id = $course_id AND
3371
                                view.c_id = $course_id AND
3372
                                view.lp_id = $lp_id AND
3373
                                view.user_id = $student_id AND
3374
                                session_id = $session_id";
3375
3376
                    $rs = Database::query($sql);
3377
                    if (Database::num_rows($rs) > 0) {
3378
                        $total_time += Database::result($rs, 0, 0);
3379
                    }
3380
                }
3381
            }
3382
        }
3383
3384
        return $total_time;
3385
    }
3386
3387
    /**
3388
     * This function gets last connection time to one learning path.
3389
     *
3390
     * @param int|array $student_id  Student id(s)
3391
     * @param string    $course_code Course code
3392
     * @param int       $lp_id       Learning path id
3393
     * @param int       $session_id
3394
     *
3395
     * @return int Total time
3396
     */
3397
    public static function get_last_connection_time_in_lp(
3398
        $student_id,
3399
        $course_code,
3400
        $lp_id,
3401
        $session_id = 0
3402
    ) {
3403
        $course = api_get_course_info($course_code);
3404
        $student_id = (int) $student_id;
3405
        $lp_id = (int) $lp_id;
3406
        $session_id = (int) $session_id;
3407
        $lastTime = 0;
3408
3409
        if (!empty($course)) {
3410
            $course_id = $course['real_id'];
3411
            $lp_table = Database::get_course_table(TABLE_LP_MAIN);
3412
            $t_lpv = Database::get_course_table(TABLE_LP_VIEW);
3413
            $t_lpiv = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3414
3415
            // Check the real number of LPs corresponding to the filter in the
3416
            // database (and if no list was given, get them all)
3417
            $sql = "SELECT id FROM $lp_table 
3418
                    WHERE c_id = $course_id AND id = $lp_id ";
3419
            $row = Database::query($sql);
3420
            $count = Database::num_rows($row);
3421
3422
            // calculates last connection time
3423
            if ($count > 0) {
3424
                $sql = 'SELECT MAX(start_time)
3425
                        FROM '.$t_lpiv.' AS item_view
3426
                        INNER JOIN '.$t_lpv.' AS view
3427
                        ON (item_view.lp_view_id = view.id AND item_view.c_id = view.c_id)
3428
                        WHERE
3429
                            status != "not attempted" AND
3430
                            item_view.c_id = '.$course_id.' AND
3431
                            view.c_id = '.$course_id.' AND
3432
                            view.lp_id = '.$lp_id.' AND 
3433
                            view.user_id = '.$student_id.' AND 
3434
                            view.session_id = '.$session_id;
3435
                $rs = Database::query($sql);
3436
                if (Database::num_rows($rs) > 0) {
3437
                    $lastTime = Database::result($rs, 0, 0);
3438
                }
3439
            }
3440
        }
3441
3442
        return $lastTime;
3443
    }
3444
3445
    /**
3446
     * gets the list of students followed by coach.
3447
     *
3448
     * @param int $coach_id Coach id
3449
     *
3450
     * @return array List of students
3451
     */
3452
    public static function get_student_followed_by_coach($coach_id)
3453
    {
3454
        $coach_id = intval($coach_id);
3455
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3456
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3457
        $tbl_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
3458
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3459
3460
        $students = [];
3461
        // At first, courses where $coach_id is coach of the course //
3462
        $sql = 'SELECT session_id, c_id
3463
                FROM '.$tbl_session_course_user.'
3464
                WHERE user_id='.$coach_id.' AND status=2';
3465
3466
        if (api_is_multiple_url_enabled()) {
3467
            $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3468
            $access_url_id = api_get_current_access_url_id();
3469
            if ($access_url_id != -1) {
3470
                $sql = 'SELECT scu.session_id, scu.c_id
3471
                        FROM '.$tbl_session_course_user.' scu
3472
                        INNER JOIN '.$tbl_session_rel_access_url.'  sru
3473
                        ON (scu.session_id=sru.session_id)
3474
                        WHERE
3475
                            scu.user_id='.$coach_id.' AND
3476
                            scu.status=2 AND
3477
                            sru.access_url_id = '.$access_url_id;
3478
            }
3479
        }
3480
3481
        $result = Database::query($sql);
3482
3483
        while ($a_courses = Database::fetch_array($result)) {
3484
            $courseId = $a_courses['c_id'];
3485
            $id_session = $a_courses['session_id'];
3486
3487
            $sql = "SELECT DISTINCT srcru.user_id
3488
                    FROM $tbl_session_course_user AS srcru
3489
                    INNER JOIN $tbl_session_user sru
3490
                    ON (srcru.user_id = sru.user_id AND srcru.session_id = sru.session_id)
3491
                    WHERE
3492
                        sru.relation_type <> ".SESSION_RELATION_TYPE_RRHH." AND
3493
                        srcru.c_id = '$courseId' AND
3494
                        srcru.session_id = '$id_session'";
3495
3496
            $rs = Database::query($sql);
3497
            while ($row = Database::fetch_array($rs)) {
3498
                $students[$row['user_id']] = $row['user_id'];
3499
            }
3500
        }
3501
3502
        // Then, courses where $coach_id is coach of the session    //
3503
        $sql = 'SELECT session_course_user.user_id
3504
                FROM '.$tbl_session_course_user.' as session_course_user
3505
                INNER JOIN '.$tbl_session_user.' sru
3506
                ON session_course_user.user_id = sru.user_id AND session_course_user.session_id = sru.session_id
3507
                INNER JOIN '.$tbl_session_course.' as session_course
3508
                ON session_course.c_id = session_course_user.c_id
3509
                AND session_course_user.session_id = session_course.session_id
3510
                INNER JOIN '.$tbl_session.' as session
3511
                ON session.id = session_course.session_id
3512
                AND session.id_coach = '.$coach_id;
3513
        if (api_is_multiple_url_enabled()) {
3514
            $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3515
            $access_url_id = api_get_current_access_url_id();
3516
            if ($access_url_id != -1) {
3517
                $sql = 'SELECT session_course_user.user_id
3518
                        FROM '.$tbl_session_course_user.' as session_course_user
3519
                        INNER JOIN '.$tbl_session_user.' sru
3520
                        ON session_course_user.user_id = sru.user_id AND
3521
                           session_course_user.session_id = sru.session_id
3522
                        INNER JOIN '.$tbl_session_course.' as session_course
3523
                        ON session_course.c_id = session_course_user.c_id AND
3524
                        session_course_user.session_id = session_course.session_id
3525
                        INNER JOIN '.$tbl_session.' as session
3526
                        ON session.id = session_course.session_id AND
3527
                        session.id_coach = '.$coach_id.'
3528
                        INNER JOIN '.$tbl_session_rel_access_url.' session_rel_url
3529
                        ON session.id = session_rel_url.session_id 
3530
                        WHERE access_url_id = '.$access_url_id;
3531
            }
3532
        }
3533
3534
        $result = Database::query($sql);
3535
        while ($row = Database::fetch_array($result)) {
3536
            $students[$row['user_id']] = $row['user_id'];
3537
        }
3538
3539
        return $students;
3540
    }
3541
3542
    /**
3543
     * Get student followed by a coach inside a session.
3544
     *
3545
     * @param    int        Session id
3546
     * @param    int        Coach id
3547
     *
3548
     * @return array students list
3549
     */
3550
    public static function get_student_followed_by_coach_in_a_session(
3551
        $id_session,
3552
        $coach_id
3553
    ) {
3554
        $coach_id = intval($coach_id);
3555
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3556
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3557
3558
        $students = [];
3559
        // At first, courses where $coach_id is coach of the course //
3560
        $sql = 'SELECT c_id FROM '.$tbl_session_course_user.'
3561
                WHERE session_id="'.$id_session.'" AND user_id='.$coach_id.' AND status=2';
3562
        $result = Database::query($sql);
3563
3564
        while ($a_courses = Database::fetch_array($result)) {
3565
            $courseId = $a_courses['c_id'];
3566
            $sql = "SELECT DISTINCT srcru.user_id
3567
                    FROM $tbl_session_course_user AS srcru
3568
                    WHERE
3569
                        c_id = '$courseId' AND
3570
                        session_id = '".$id_session."'";
3571
            $rs = Database::query($sql);
3572
            while ($row = Database::fetch_array($rs)) {
3573
                $students[$row['user_id']] = $row['user_id'];
3574
            }
3575
        }
3576
3577
        // Then, courses where $coach_id is coach of the session
3578
        $sql = 'SELECT id_coach FROM '.$tbl_session.'
3579
                WHERE id="'.$id_session.'" AND id_coach="'.$coach_id.'"';
3580
        $result = Database::query($sql);
3581
3582
        //He is the session_coach so we select all the users in the session
3583
        if (Database::num_rows($result) > 0) {
3584
            $sql = 'SELECT DISTINCT srcru.user_id
3585
                    FROM '.$tbl_session_course_user.' AS srcru
3586
                    WHERE session_id="'.$id_session.'"';
3587
            $result = Database::query($sql);
3588
            while ($row = Database::fetch_array($result)) {
3589
                $students[$row['user_id']] = $row['user_id'];
3590
            }
3591
        }
3592
3593
        return $students;
3594
    }
3595
3596
    /**
3597
     * Check if a coach is allowed to follow a student.
3598
     *
3599
     * @param    int        Coach id
3600
     * @param    int        Student id
3601
     *
3602
     * @return bool
3603
     */
3604
    public static function is_allowed_to_coach_student($coach_id, $student_id)
3605
    {
3606
        $coach_id = intval($coach_id);
3607
        $student_id = intval($student_id);
3608
3609
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3610
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3611
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3612
3613
        // At first, courses where $coach_id is coach of the course //
3614
        $sql = 'SELECT 1 FROM '.$tbl_session_course_user.'
3615
                WHERE user_id='.$coach_id.' AND status=2';
3616
        $result = Database::query($sql);
3617
        if (Database::num_rows($result) > 0) {
3618
            return true;
3619
        }
3620
3621
        // Then, courses where $coach_id is coach of the session
3622
        $sql = 'SELECT session_course_user.user_id
3623
                FROM '.$tbl_session_course_user.' as session_course_user
3624
                INNER JOIN '.$tbl_session_course.' as session_course
3625
                ON session_course.c_id = session_course_user.c_id
3626
                INNER JOIN '.$tbl_session.' as session
3627
                ON session.id = session_course.session_id
3628
                AND session.id_coach = '.$coach_id.'
3629
                WHERE user_id = '.$student_id;
3630
        $result = Database::query($sql);
3631
        if (Database::num_rows($result) > 0) {
3632
            return true;
3633
        }
3634
3635
        return false;
3636
    }
3637
3638
    /**
3639
     * Get courses followed by coach.
3640
     *
3641
     * @param     int        Coach id
3642
     * @param    int        Session id (optional)
3643
     *
3644
     * @return array Courses list
3645
     */
3646
    public static function get_courses_followed_by_coach($coach_id, $id_session = 0)
3647
    {
3648
        $coach_id = intval($coach_id);
3649
        if (!empty($id_session)) {
3650
            $id_session = intval($id_session);
3651
        }
3652
3653
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3654
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3655
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3656
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3657
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3658
3659
        // At first, courses where $coach_id is coach of the course.
3660
        $sql = 'SELECT DISTINCT c.code
3661
                FROM '.$tbl_session_course_user.' sc
3662
                INNER JOIN '.$tbl_course.' c
3663
                ON (c.id = sc.c_id)
3664
                WHERE user_id = '.$coach_id.' AND status = 2';
3665
3666
        if (api_is_multiple_url_enabled()) {
3667
            $access_url_id = api_get_current_access_url_id();
3668
            if ($access_url_id != -1) {
3669
                $sql = 'SELECT DISTINCT c.code
3670
                        FROM '.$tbl_session_course_user.' scu
3671
                        INNER JOIN '.$tbl_course.' c
3672
                        ON (c.code = scu.c_id)
3673
                        INNER JOIN '.$tbl_course_rel_access_url.' cru
3674
                        ON (c.id = cru.c_id)
3675
                        WHERE
3676
                            scu.user_id='.$coach_id.' AND
3677
                            scu.status=2 AND
3678
                            cru.access_url_id = '.$access_url_id;
3679
            }
3680
        }
3681
3682
        if (!empty($id_session)) {
3683
            $sql .= ' AND session_id='.$id_session;
3684
        }
3685
3686
        $courseList = [];
3687
        $result = Database::query($sql);
3688
        while ($row = Database::fetch_array($result)) {
3689
            $courseList[$row['code']] = $row['code'];
3690
        }
3691
3692
        // Then, courses where $coach_id is coach of the session
3693
        $sql = 'SELECT DISTINCT course.code
3694
                FROM '.$tbl_session_course.' as session_course
3695
                INNER JOIN '.$tbl_session.' as session
3696
                    ON session.id = session_course.session_id
3697
                    AND session.id_coach = '.$coach_id.'
3698
                INNER JOIN '.$tbl_course.' as course
3699
                    ON course.id = session_course.c_id';
3700
3701
        if (api_is_multiple_url_enabled()) {
3702
            $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3703
            $access_url_id = api_get_current_access_url_id();
3704
            if ($access_url_id != -1) {
3705
                $sql = 'SELECT DISTINCT c.code
3706
                    FROM '.$tbl_session_course.' as session_course
3707
                    INNER JOIN '.$tbl_course.' c
3708
                    ON (c.id = session_course.c_id)
3709
                    INNER JOIN '.$tbl_session.' as session
3710
                    ON session.id = session_course.session_id
3711
                        AND session.id_coach = '.$coach_id.'
3712
                    INNER JOIN '.$tbl_course.' as course
3713
                        ON course.id = session_course.c_id
3714
                     INNER JOIN '.$tbl_course_rel_access_url.' course_rel_url
3715
                    ON (course_rel_url.c_id = c.id)';
3716
            }
3717
        }
3718
3719
        if (!empty($id_session)) {
3720
            $sql .= ' WHERE session_course.session_id='.$id_session;
3721
            if (api_is_multiple_url_enabled()) {
3722
                $sql .= ' AND access_url_id = '.$access_url_id;
3723
            }
3724
        } else {
3725
            if (api_is_multiple_url_enabled()) {
3726
                $sql .= ' WHERE access_url_id = '.$access_url_id;
3727
            }
3728
        }
3729
3730
        $result = Database::query($sql);
3731
        while ($row = Database::fetch_array($result)) {
3732
            $courseList[$row['code']] = $row['code'];
3733
        }
3734
3735
        return $courseList;
3736
    }
3737
3738
    /**
3739
     * Get sessions coached by user.
3740
     *
3741
     * @param $coach_id
3742
     * @param int    $start
3743
     * @param int    $limit
3744
     * @param bool   $getCount
3745
     * @param string $keyword
3746
     * @param string $description
3747
     * @param string $orderByName
3748
     * @param string $orderByDirection
3749
     *
3750
     * @return mixed
3751
     */
3752
    public static function get_sessions_coached_by_user(
3753
        $coach_id,
3754
        $start = 0,
3755
        $limit = 0,
3756
        $getCount = false,
3757
        $keyword = '',
3758
        $description = '',
3759
        $orderByName = '',
3760
        $orderByDirection = ''
3761
    ) {
3762
        // table definition
3763
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3764
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3765
        $coach_id = (int) $coach_id;
3766
3767
        $select = " SELECT * FROM ";
3768
        if ($getCount) {
3769
            $select = " SELECT count(DISTINCT id) as count FROM ";
3770
        }
3771
3772
        $limitCondition = null;
3773
        if (!empty($start) && !empty($limit)) {
3774
            $limitCondition = " LIMIT ".intval($start).", ".intval($limit);
3775
        }
3776
3777
        $keywordCondition = null;
3778
3779
        if (!empty($keyword)) {
3780
            $keyword = Database::escape_string($keyword);
3781
            $keywordCondition = " AND (name LIKE '%$keyword%' ) ";
3782
3783
            if (!empty($description)) {
3784
                $description = Database::escape_string($description);
3785
                $keywordCondition = " AND (name LIKE '%$keyword%' OR description LIKE '%$description%' ) ";
3786
            }
3787
        }
3788
3789
        $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3790
        $access_url_id = api_get_current_access_url_id();
3791
3792
        $orderBy = '';
3793
        if (!empty($orderByName)) {
3794
            if (in_array($orderByName, ['name', 'access_start_date'])) {
3795
                $orderByDirection = in_array(strtolower($orderByDirection), ['asc', 'desc']) ? $orderByDirection : 'asc';
3796
                $orderByName = Database::escape_string($orderByName);
3797
                $orderBy .= " ORDER BY $orderByName $orderByDirection";
3798
            }
3799
        }
3800
3801
        $sql = "
3802
            $select
3803
            (
3804
                SELECT DISTINCT
3805
                    session.id,
3806
                    name,
3807
                    access_start_date,
3808
                    access_end_date
3809
                FROM $tbl_session session
3810
                INNER JOIN $tbl_session_rel_access_url session_rel_url
3811
                ON (session.id = session_rel_url.session_id)
3812
                WHERE
3813
                    id_coach = $coach_id AND
3814
                    access_url_id = $access_url_id
3815
                    $keywordCondition
3816
            UNION
3817
                SELECT DISTINCT
3818
                    session.id,
3819
                    session.name,
3820
                    session.access_start_date,
3821
                    session.access_end_date
3822
                FROM $tbl_session as session
3823
                INNER JOIN $tbl_session_course_user as session_course_user
3824
                ON
3825
                    session.id = session_course_user.session_id AND
3826
                    session_course_user.user_id = $coach_id AND
3827
                    session_course_user.status = 2
3828
                INNER JOIN $tbl_session_rel_access_url session_rel_url
3829
                ON (session.id = session_rel_url.session_id)
3830
                WHERE
3831
                    access_url_id = $access_url_id
3832
                    $keywordCondition
3833
            ) as sessions $limitCondition $orderBy
3834
            ";
3835
3836
        $rs = Database::query($sql);
3837
        if ($getCount) {
3838
            $row = Database::fetch_array($rs);
3839
3840
            return $row['count'];
3841
        }
3842
3843
        $sessions = [];
3844
        while ($row = Database::fetch_array($rs)) {
3845
            if ($row['access_start_date'] == '0000-00-00 00:00:00') {
3846
                $row['access_start_date'] = null;
3847
            }
3848
3849
            $sessions[$row['id']] = $row;
3850
        }
3851
3852
        if (!empty($sessions)) {
3853
            foreach ($sessions as &$session) {
3854
                if (empty($session['access_start_date'])) {
3855
                    $session['status'] = get_lang('SessionActive');
3856
                } else {
3857
                    $time_start = api_strtotime($session['access_start_date'], 'UTC');
3858
                    $time_end = api_strtotime($session['access_end_date'], 'UTC');
3859
                    if ($time_start < time() && time() < $time_end) {
3860
                        $session['status'] = get_lang('SessionActive');
3861
                    } else {
3862
                        if (time() < $time_start) {
3863
                            $session['status'] = get_lang('SessionFuture');
3864
                        } else {
3865
                            if (time() > $time_end) {
3866
                                $session['status'] = get_lang('SessionPast');
3867
                            }
3868
                        }
3869
                    }
3870
                }
3871
            }
3872
        }
3873
3874
        return $sessions;
3875
    }
3876
3877
    /**
3878
     * Get courses list from a session.
3879
     *
3880
     * @param    int        Session id
3881
     *
3882
     * @return array Courses list
3883
     */
3884
    public static function get_courses_list_from_session($session_id)
3885
    {
3886
        $session_id = intval($session_id);
3887
3888
        // table definition
3889
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3890
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
3891
3892
        $sql = "SELECT DISTINCT code, c_id
3893
                FROM $tbl_session_course sc
3894
                INNER JOIN $courseTable c
3895
                ON sc.c_id = c.id
3896
                WHERE session_id= $session_id";
3897
3898
        $result = Database::query($sql);
3899
3900
        $courses = [];
3901
        while ($row = Database::fetch_array($result)) {
3902
            $courses[$row['code']] = $row;
3903
        }
3904
3905
        return $courses;
3906
    }
3907
3908
    /**
3909
     * Count the number of documents that an user has uploaded to a course.
3910
     *
3911
     * @param    int|array   Student id(s)
3912
     * @param    string      Course code
3913
     * @param    int         Session id (optional),
3914
     * if param $session_id is null(default)
3915
     * return count of assignments including sessions, 0 = session is not filtered
3916
     *
3917
     * @return int Number of documents
3918
     */
3919
    public static function count_student_uploaded_documents(
3920
        $student_id,
3921
        $course_code,
3922
        $session_id = null
3923
    ) {
3924
        // get the information of the course
3925
        $a_course = api_get_course_info($course_code);
3926
        if (!empty($a_course)) {
3927
            // table definition
3928
            $tbl_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
3929
            $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
3930
            $course_id = $a_course['real_id'];
3931
            if (is_array($student_id)) {
3932
                $studentList = array_map('intval', $student_id);
3933
                $condition_user = " AND ip.insert_user_id IN ('".implode(',', $studentList)."') ";
3934
            } else {
3935
                $student_id = intval($student_id);
3936
                $condition_user = " AND ip.insert_user_id = '$student_id' ";
3937
            }
3938
3939
            $condition_session = null;
3940
            if (isset($session_id)) {
3941
                $session_id = intval($session_id);
3942
                $condition_session = " AND pub.session_id = $session_id ";
3943
            }
3944
3945
            $sql = "SELECT count(ip.tool) AS count
3946
                    FROM $tbl_item_property ip
3947
                    INNER JOIN $tbl_document pub
3948
                    ON (ip.ref = pub.id AND ip.c_id = pub.c_id)
3949
                    WHERE
3950
                        ip.c_id  = $course_id AND
3951
                        pub.c_id  = $course_id AND
3952
                        pub.filetype ='file' AND
3953
                        ip.tool = 'document'
3954
                        $condition_user $condition_session ";
3955
            $rs = Database::query($sql);
3956
            $row = Database::fetch_array($rs, 'ASSOC');
3957
3958
            return $row['count'];
3959
        }
3960
3961
        return null;
3962
    }
3963
3964
    /**
3965
     * Count assignments per student.
3966
     *
3967
     * @param $student_id
3968
     * @param null $course_code
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $course_code is correct as it would always require null to be passed?
Loading history...
3969
     * @param null $session_id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $session_id is correct as it would always require null to be passed?
Loading history...
3970
     *
3971
     * @return int Count of assignments
3972
     *
3973
     * @internal param array|int $Student id(s)
3974
     * @internal param Course $string code
3975
     * @internal param Session $int id (optional),
3976
     * if param $session_id is null(default) return count of assignments
3977
     * including sessions, 0 = session is not filtered
3978
     */
3979
    public static function count_student_assignments(
3980
        $student_id,
3981
        $course_code = null,
3982
        $session_id = null
3983
    ) {
3984
        if (empty($student_id)) {
3985
            return 0;
3986
        }
3987
3988
        $conditions = [];
3989
3990
        // Get the information of the course
3991
        $a_course = api_get_course_info($course_code);
3992
        if (!empty($a_course)) {
3993
            $course_id = $a_course['real_id'];
3994
            $conditions[] = " ip.c_id  = $course_id AND pub.c_id  = $course_id ";
3995
        }
3996
3997
        // table definition
3998
        $tbl_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
3999
        $tbl_student_publication = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4000
4001
        if (is_array($student_id)) {
4002
            $studentList = array_map('intval', $student_id);
4003
            $conditions[] = " ip.insert_user_id IN ('".implode("','", $studentList)."') ";
4004
        } else {
4005
            $student_id = intval($student_id);
4006
            $conditions[] = " ip.insert_user_id = '$student_id' ";
4007
        }
4008
4009
        $conditions[] = ' pub.active <> 2 ';
4010
        $conditionToString = implode(' AND ', $conditions);
4011
        $sessionCondition = api_get_session_condition($session_id, true, false, 'pub.session_id');
4012
        $conditionToString .= $sessionCondition;
4013
4014
        $sql = "SELECT count(ip.tool) as count
4015
                FROM $tbl_item_property ip
4016
                INNER JOIN $tbl_student_publication pub
4017
                ON (ip.ref = pub.id AND ip.c_id = pub.c_id)
4018
                WHERE
4019
                    ip.tool='work' AND
4020
                    $conditionToString";
4021
        $rs = Database::query($sql);
4022
        $row = Database::fetch_array($rs, 'ASSOC');
4023
4024
        return $row['count'];
4025
    }
4026
4027
    /**
4028
     * Count messages per student inside forum tool.
4029
     *
4030
     * @param int|array  Student id
4031
     * @param string     Course code
4032
     * @param int        Session id if null(default) return count of messages including sessions, 0 = session is not filtered
4033
     *
4034
     * @return int Count of messages
4035
     */
4036
    public static function count_student_messages($student_id, $courseCode = null, $session_id = null)
4037
    {
4038
        if (empty($student_id)) {
4039
            return 0;
4040
        }
4041
4042
        // Table definition.
4043
        $tbl_forum_post = Database::get_course_table(TABLE_FORUM_POST);
4044
        $tbl_forum = Database::get_course_table(TABLE_FORUM);
4045
4046
        $conditions = [];
4047
        if (is_array($student_id)) {
4048
            $studentList = array_map('intval', $student_id);
4049
            $conditions[] = " post.poster_id IN ('".implode("','", $studentList)."') ";
4050
        } else {
4051
            $student_id = intval($student_id);
4052
            $conditions[] = " post.poster_id = '$student_id' ";
4053
        }
4054
4055
        $conditionsToString = implode('AND ', $conditions);
4056
4057
        if (empty($courseCode)) {
4058
            $sql = "SELECT count(poster_id) as count
4059
                    FROM $tbl_forum_post post
4060
                    INNER JOIN $tbl_forum forum
4061
                    ON (forum.forum_id = post.forum_id AND forum.c_id = post.c_id)
4062
                    WHERE $conditionsToString";
4063
4064
            $rs = Database::query($sql);
4065
            $row = Database::fetch_array($rs, 'ASSOC');
4066
4067
            return $row['count'];
4068
        }
4069
4070
        require_once api_get_path(SYS_CODE_PATH).'forum/forumconfig.inc.php';
4071
        require_once api_get_path(SYS_CODE_PATH).'forum/forumfunction.inc.php';
4072
4073
        $courseInfo = api_get_course_info($courseCode);
4074
4075
        $forums = [];
4076
        if (!empty($courseInfo)) {
4077
            $forums = get_forums('', $courseCode, true, $session_id);
4078
            $course_id = $courseInfo['real_id'];
4079
            $conditions[] = " post.c_id  = $course_id ";
4080
        }
4081
4082
        if (!empty($forums)) {
4083
            $idList = array_column($forums, 'forum_id');
4084
            $idListToString = implode("', '", $idList);
4085
            $conditions[] = " post.forum_id  IN ('$idListToString')";
4086
        }
4087
4088
        $conditionsToString = implode('AND ', $conditions);
4089
        $sql = "SELECT count(poster_id) as count
4090
                FROM $tbl_forum_post post
4091
                WHERE $conditionsToString";
4092
4093
        $rs = Database::query($sql);
4094
        $row = Database::fetch_array($rs, 'ASSOC');
4095
        $count = $row['count'];
4096
4097
        return $count;
4098
    }
4099
4100
    /**
4101
     * This function counts the number of post by course.
4102
     *
4103
     * @param string $course_code
4104
     * @param int    $session_id  (optional), if is null(default) it'll return results including sessions,
4105
     *                            0 = session is not filtered
4106
     * @param int    $groupId
4107
     *
4108
     * @return int The number of post by course
4109
     */
4110
    public static function count_number_of_posts_by_course($course_code, $session_id = null, $groupId = 0)
4111
    {
4112
        $courseInfo = api_get_course_info($course_code);
4113
        if (!empty($courseInfo)) {
4114
            $tbl_posts = Database::get_course_table(TABLE_FORUM_POST);
4115
            $tbl_forums = Database::get_course_table(TABLE_FORUM);
4116
4117
            $condition_session = '';
4118
            if (isset($session_id)) {
4119
                $session_id = intval($session_id);
4120
                $condition_session = api_get_session_condition(
4121
                    $session_id,
4122
                    true,
4123
                    false,
4124
                    'f.session_id'
4125
                );
4126
            }
4127
4128
            $course_id = $courseInfo['real_id'];
4129
            $groupId = intval($groupId);
4130
            if (!empty($groupId)) {
4131
                $groupCondition = " i.to_group_id = $groupId  ";
4132
            } else {
4133
                $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) ";
4134
            }
4135
4136
            $item = Database::get_course_table(TABLE_ITEM_PROPERTY);
4137
            $sql = "SELECT count(*) FROM $tbl_posts p
4138
                    INNER JOIN $tbl_forums f
4139
                    ON f.forum_id = p.forum_id AND p.c_id = f.c_id
4140
                    INNER JOIN $item i
4141
                    ON (tool = '".TOOL_FORUM."' AND f.c_id = i.c_id AND f.iid = i.ref)
4142
                    WHERE
4143
                        p.c_id = $course_id AND
4144
                        f.c_id = $course_id AND
4145
                        $groupCondition
4146
                        $condition_session
4147
                    ";
4148
            $result = Database::query($sql);
4149
            $row = Database::fetch_row($result);
4150
            $count = $row[0];
4151
4152
            return $count;
4153
        } else {
4154
            return null;
4155
        }
4156
    }
4157
4158
    /**
4159
     * This function counts the number of threads by course.
4160
     *
4161
     * @param      string     Course code
4162
     * @param    int        Session id (optional),
4163
     * if param $session_id is null(default) it'll return results including
4164
     * sessions, 0 = session is not filtered
4165
     * @param int $groupId
4166
     *
4167
     * @return int The number of threads by course
4168
     */
4169
    public static function count_number_of_threads_by_course(
4170
        $course_code,
4171
        $session_id = null,
4172
        $groupId = 0
4173
    ) {
4174
        $course_info = api_get_course_info($course_code);
4175
        if (empty($course_info)) {
4176
            return null;
4177
        }
4178
4179
        $course_id = $course_info['real_id'];
4180
        $tbl_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4181
        $tbl_forums = Database::get_course_table(TABLE_FORUM);
4182
4183
        $condition_session = '';
4184
        if (isset($session_id)) {
4185
            $session_id = intval($session_id);
4186
            $condition_session = ' AND f.session_id = '.$session_id;
4187
        }
4188
4189
        $groupId = intval($groupId);
4190
4191
        if (!empty($groupId)) {
4192
            $groupCondition = " i.to_group_id = $groupId ";
4193
        } else {
4194
            $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) ";
4195
        }
4196
4197
        $item = Database::get_course_table(TABLE_ITEM_PROPERTY);
4198
        $sql = "SELECT count(*)
4199
                FROM $tbl_threads t
4200
                INNER JOIN $tbl_forums f
4201
                ON f.iid = t.forum_id AND f.c_id = t.c_id
4202
                INNER JOIN $item i
4203
                ON (
4204
                    tool = '".TOOL_FORUM_THREAD."' AND
4205
                    f.c_id = i.c_id AND
4206
                    t.iid = i.ref
4207
                )
4208
                WHERE
4209
                    t.c_id = $course_id AND
4210
                    f.c_id = $course_id AND
4211
                    $groupCondition
4212
                    $condition_session
4213
                ";
4214
4215
        $result = Database::query($sql);
4216
        if (Database::num_rows($result)) {
4217
            $row = Database::fetch_row($result);
4218
            $count = $row[0];
4219
4220
            return $count;
4221
        } else {
4222
            return null;
4223
        }
4224
    }
4225
4226
    /**
4227
     * This function counts the number of forums by course.
4228
     *
4229
     * @param      string     Course code
4230
     * @param    int        Session id (optional),
4231
     * if param $session_id is null(default) it'll return results
4232
     * including sessions, 0 = session is not filtered
4233
     * @param int $groupId
4234
     *
4235
     * @return int The number of forums by course
4236
     */
4237
    public static function count_number_of_forums_by_course(
4238
        $course_code,
4239
        $session_id = null,
4240
        $groupId = 0
4241
    ) {
4242
        $course_info = api_get_course_info($course_code);
4243
        if (empty($course_info)) {
4244
            return null;
4245
        }
4246
        $course_id = $course_info['real_id'];
4247
4248
        $condition_session = '';
4249
        if (isset($session_id)) {
4250
            $session_id = intval($session_id);
4251
            $condition_session = ' AND f.session_id = '.$session_id;
4252
        }
4253
4254
        $groupId = intval($groupId);
4255
        if (!empty($groupId)) {
4256
            $groupCondition = " i.to_group_id = $groupId ";
4257
        } else {
4258
            $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) ";
4259
        }
4260
4261
        $tbl_forums = Database::get_course_table(TABLE_FORUM);
4262
        $item = Database::get_course_table(TABLE_ITEM_PROPERTY);
4263
4264
        $sql = "SELECT count(*)
4265
                FROM $tbl_forums f
4266
                INNER JOIN $item i
4267
                ON f.c_id = i.c_id AND f.iid = i.ref AND tool = '".TOOL_FORUM."'
4268
                WHERE
4269
                    f.c_id = $course_id AND
4270
                    $groupCondition
4271
                    $condition_session
4272
                ";
4273
        $result = Database::query($sql);
4274
        if (Database::num_rows($result)) {
4275
            $row = Database::fetch_row($result);
4276
            $count = $row[0];
4277
4278
            return $count;
4279
        } else {
4280
            return null;
4281
        }
4282
    }
4283
4284
    /**
4285
     * This function counts the chat last connections by course in x days.
4286
     *
4287
     * @param      string     Course code
4288
     * @param      int     Last x days
4289
     * @param    int        Session id (optional)
4290
     *
4291
     * @return int Chat last connections by course in x days
4292
     */
4293
    public static function chat_connections_during_last_x_days_by_course(
4294
        $course_code,
4295
        $last_days,
4296
        $session_id = 0
4297
    ) {
4298
        $course_info = api_get_course_info($course_code);
4299
        if (empty($course_info)) {
4300
            return null;
4301
        }
4302
        $course_id = $course_info['real_id'];
4303
4304
        // Protect data
4305
        $last_days = intval($last_days);
4306
        $session_id = intval($session_id);
4307
        $tbl_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
4308
        $now = api_get_utc_datetime();
4309
4310
        $sql = "SELECT count(*) FROM $tbl_stats_access
4311
                WHERE
4312
                    DATE_SUB('$now',INTERVAL $last_days DAY) <= access_date AND
4313
                    c_id = '$course_id' AND
4314
                    access_tool='".TOOL_CHAT."' AND
4315
                    access_session_id='$session_id' ";
4316
        $result = Database::query($sql);
4317
        if (Database::num_rows($result)) {
4318
            $row = Database::fetch_row($result);
4319
            $count = $row[0];
4320
4321
            return $count;
4322
        } else {
4323
            return null;
4324
        }
4325
    }
4326
4327
    /**
4328
     * This function gets the last student's connection in chat.
4329
     *
4330
     * @param      int     Student id
4331
     * @param      string     Course code
4332
     * @param    int        Session id (optional)
4333
     *
4334
     * @return string datetime formatted without day (e.g: February 23, 2010 10:20:50 )
4335
     */
4336
    public static function chat_last_connection(
4337
        $student_id,
4338
        $courseId,
4339
        $session_id = 0
4340
    ) {
4341
        $student_id = intval($student_id);
4342
        $courseId = intval($courseId);
4343
        $session_id = intval($session_id);
4344
        $date_time = '';
4345
4346
        // table definition
4347
        $tbl_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4348
        $sql = "SELECT access_date
4349
                FROM $tbl_stats_access
4350
                WHERE
4351
                     access_tool='".TOOL_CHAT."' AND
4352
                     access_user_id='$student_id' AND
4353
                     c_id = $courseId AND
4354
                     access_session_id = '$session_id'
4355
                ORDER BY access_date DESC limit 1";
4356
        $rs = Database::query($sql);
4357
        if (Database::num_rows($rs) > 0) {
4358
            $row = Database::fetch_array($rs);
4359
            $date_time = api_convert_and_format_date(
4360
                $row['access_date'],
4361
                null,
4362
                date_default_timezone_get()
4363
            );
4364
        }
4365
4366
        return $date_time;
4367
    }
4368
4369
    /**
4370
     * Get count student's visited links.
4371
     *
4372
     * @param int $student_id Student id
4373
     * @param int $courseId
4374
     * @param int $session_id Session id (optional)
4375
     *
4376
     * @return int count of visited links
4377
     */
4378
    public static function count_student_visited_links($student_id, $courseId, $session_id = 0)
4379
    {
4380
        $student_id = intval($student_id);
4381
        $courseId = intval($courseId);
4382
        $session_id = intval($session_id);
4383
4384
        // table definition
4385
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
4386
4387
        $sql = 'SELECT 1
4388
                FROM '.$table.'
4389
                WHERE
4390
                    links_user_id= '.$student_id.' AND
4391
                    c_id = "'.$courseId.'" AND
4392
                    links_session_id = '.$session_id.' ';
4393
4394
        $rs = Database::query($sql);
4395
4396
        return Database::num_rows($rs);
4397
    }
4398
4399
    /**
4400
     * Get count student downloaded documents.
4401
     *
4402
     * @param    int        Student id
4403
     * @param int $courseId
4404
     * @param    int        Session id (optional)
4405
     *
4406
     * @return int Count downloaded documents
4407
     */
4408
    public static function count_student_downloaded_documents($student_id, $courseId, $session_id = 0)
4409
    {
4410
        $student_id = intval($student_id);
4411
        $courseId = intval($courseId);
4412
        $session_id = intval($session_id);
4413
4414
        // table definition
4415
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
4416
4417
        $sql = 'SELECT 1
4418
                FROM '.$table.'
4419
                WHERE down_user_id = '.$student_id.'
4420
                AND c_id  = "'.$courseId.'"
4421
                AND down_session_id = '.$session_id.' ';
4422
        $rs = Database::query($sql);
4423
4424
        return Database::num_rows($rs);
4425
    }
4426
4427
    /**
4428
     * Get course list inside a session from a student.
4429
     *
4430
     * @param int $user_id    Student id
4431
     * @param int $id_session Session id (optional)
4432
     *
4433
     * @return array Courses list
4434
     */
4435
    public static function get_course_list_in_session_from_student($user_id, $id_session = 0)
4436
    {
4437
        $user_id = intval($user_id);
4438
        $id_session = intval($id_session);
4439
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4440
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
4441
4442
        $sql = "SELECT c.code
4443
                FROM $tbl_session_course_user sc
4444
                INNER JOIN $courseTable c
4445
                WHERE
4446
                    user_id= $user_id  AND
4447
                    session_id = $id_session";
4448
        $result = Database::query($sql);
4449
        $courses = [];
4450
        while ($row = Database::fetch_array($result)) {
4451
            $courses[$row['code']] = $row['code'];
4452
        }
4453
4454
        return $courses;
4455
    }
4456
4457
    /**
4458
     * Get inactive students in course.
4459
     *
4460
     * @param int        $courseId
4461
     * @param string|int $since      Since login course date (optional, default = 'never')
4462
     * @param int        $session_id (optional)
4463
     *
4464
     * @return array Inactive users
4465
     */
4466
    public static function getInactiveStudentsInCourse(
4467
        $courseId,
4468
        $since = 'never',
4469
        $session_id = 0
4470
    ) {
4471
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
4472
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4473
        $table_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4474
        $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
4475
        $now = api_get_utc_datetime();
4476
        $courseId = (int) $courseId;
4477
        $session_id = (int) $session_id;
4478
4479
        if (empty($courseId)) {
4480
            return false;
4481
        }
4482
4483
        if ($since === 'never') {
4484
            if (empty($session_id)) {
4485
                $sql = 'SELECT course_user.user_id
4486
                        FROM '.$table_course_rel_user.' course_user
4487
                        LEFT JOIN '.$tbl_track_login.' stats_login
4488
                        ON course_user.user_id = stats_login.user_id AND
4489
                        relation_type<>'.COURSE_RELATION_TYPE_RRHH.'
4490
                        INNER JOIN '.$tableCourse.' c
4491
                        ON (c.id = course_user.c_id)
4492
                        WHERE
4493
                            course_user.c_id = '.$courseId.' AND
4494
                            stats_login.login_course_date IS NULL
4495
                        GROUP BY course_user.user_id';
4496
            } else {
4497
                $sql = 'SELECT session_course_user.user_id
4498
                        FROM '.$tbl_session_course_user.' session_course_user
4499
                        LEFT JOIN '.$tbl_track_login.' stats_login
4500
                        ON session_course_user.user_id = stats_login.user_id
4501
                        INNER JOIN '.$tableCourse.' c
4502
                        ON (c.id = session_course_user.c_id)
4503
                        WHERE
4504
                            session_course_user.c_id = '.$courseId.' AND
4505
                            stats_login.login_course_date IS NULL
4506
                        GROUP BY session_course_user.user_id';
4507
            }
4508
        } else {
4509
            $since = (int) $since;
4510
            if (empty($session_id)) {
4511
                $inner = 'INNER JOIN '.$table_course_rel_user.' course_user
4512
                          ON course_user.user_id = stats_login.user_id AND course_user.c_id = c.id ';
4513
            } else {
4514
                $inner = 'INNER JOIN '.$tbl_session_course_user.' session_course_user
4515
                          ON
4516
                            c.id = session_course_user.c_id AND
4517
                            session_course_user.session_id = '.$session_id.' AND
4518
                            session_course_user.user_id = stats_login.user_id ';
4519
            }
4520
4521
            $sql = 'SELECT 
4522
                    stats_login.user_id, 
4523
                    MAX(login_course_date) max_date
4524
                FROM '.$tbl_track_login.' stats_login
4525
                INNER JOIN '.$tableCourse.' c
4526
                ON (c.id = stats_login.c_id)
4527
                '.$inner.'
4528
                WHERE c.id = '.$courseId.'
4529
                GROUP BY stats_login.user_id
4530
                HAVING DATE_SUB("'.$now.'", INTERVAL '.$since.' DAY) > max_date ';
4531
        }
4532
4533
        $rs = Database::query($sql);
4534
        $users = [];
4535
        while ($user = Database::fetch_array($rs)) {
4536
            $users[] = $user['user_id'];
4537
        }
4538
4539
        return $users;
4540
    }
4541
4542
    /**
4543
     * Get count login per student.
4544
     *
4545
     * @param int $student_id Student id
4546
     * @param int $courseId
4547
     * @param int $session_id Session id (optional)
4548
     *
4549
     * @return int count login
4550
     */
4551
    public static function count_login_per_student($student_id, $courseId, $session_id = 0)
4552
    {
4553
        $student_id = intval($student_id);
4554
        $courseId = intval($courseId);
4555
        $session_id = intval($session_id);
4556
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
4557
4558
        $sql = 'SELECT '.$student_id.'
4559
                FROM '.$table.'
4560
                WHERE
4561
                    access_user_id='.$student_id.' AND
4562
                    c_id="'.$courseId.'" AND
4563
                    access_session_id = "'.$session_id.'" ';
4564
4565
        $rs = Database::query($sql);
4566
        $nb_login = Database::num_rows($rs);
4567
4568
        return $nb_login;
4569
    }
4570
4571
    /**
4572
     * Get students followed by a human resources manager.
4573
     *
4574
     * @param    int        Drh id
4575
     *
4576
     * @return array Student list
4577
     */
4578
    public static function get_student_followed_by_drh($hr_dept_id)
4579
    {
4580
        $hr_dept_id = intval($hr_dept_id);
4581
        $a_students = [];
4582
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
4583
4584
        $sql = 'SELECT DISTINCT user_id FROM '.$tbl_user.' as user
4585
                WHERE hr_dept_id='.$hr_dept_id;
4586
        $rs = Database::query($sql);
4587
4588
        while ($user = Database::fetch_array($rs)) {
4589
            $a_students[$user['user_id']] = $user['user_id'];
4590
        }
4591
4592
        return $a_students;
4593
    }
4594
4595
    /**
4596
     * get count clicks about tools most used by course.
4597
     *
4598
     * @param int $courseId
4599
     * @param    int        Session id (optional),
4600
     * if param $session_id is null(default) it'll return results
4601
     * including sessions, 0 = session is not filtered
4602
     *
4603
     * @return array tools data
4604
     */
4605
    public static function get_tools_most_used_by_course($courseId, $session_id = null)
4606
    {
4607
        $courseId = intval($courseId);
4608
        $data = [];
4609
        $TABLETRACK_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4610
        $condition_session = '';
4611
        if (isset($session_id)) {
4612
            $session_id = intval($session_id);
4613
            $condition_session = ' AND access_session_id = '.$session_id;
4614
        }
4615
        $sql = "SELECT
4616
                    access_tool,
4617
                    COUNT(DISTINCT access_user_id),
4618
                    count(access_tool) as count_access_tool
4619
                FROM $TABLETRACK_ACCESS
4620
                WHERE
4621
                    access_tool IS NOT NULL AND
4622
                    access_tool != '' AND
4623
                    c_id = '$courseId'
4624
                    $condition_session
4625
                GROUP BY access_tool
4626
                ORDER BY count_access_tool DESC
4627
                LIMIT 0, 3";
4628
        $rs = Database::query($sql);
4629
        if (Database::num_rows($rs) > 0) {
4630
            while ($row = Database::fetch_array($rs)) {
4631
                $data[] = $row;
4632
            }
4633
        }
4634
4635
        return $data;
4636
    }
4637
4638
    /**
4639
     * get documents most downloaded by course.
4640
     *
4641
     * @param      string     Course code
4642
     * @param    int        Session id (optional),
4643
     * if param $session_id is null(default) it'll return results including
4644
     * sessions, 0 = session is not filtered
4645
     * @param    int        Limit (optional, default = 0, 0 = without limit)
4646
     *
4647
     * @return array documents downloaded
4648
     */
4649
    public static function get_documents_most_downloaded_by_course(
4650
        $course_code,
4651
        $session_id = 0,
4652
        $limit = 0
4653
    ) {
4654
        $courseId = api_get_course_int_id($course_code);
4655
        $data = [];
4656
4657
        $TABLETRACK_DOWNLOADS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
4658
        $condition_session = '';
4659
        $session_id = intval($session_id);
4660
        if (!empty($session_id)) {
4661
            $condition_session = ' AND down_session_id = '.$session_id;
4662
        }
4663
        $sql = "SELECT
4664
                    down_doc_path,
4665
                    COUNT(DISTINCT down_user_id),
4666
                    COUNT(down_doc_path) as count_down
4667
                FROM $TABLETRACK_DOWNLOADS
4668
                WHERE c_id = $courseId
4669
                    $condition_session
4670
                GROUP BY down_doc_path
4671
                ORDER BY count_down DESC
4672
                LIMIT 0,  $limit";
4673
        $rs = Database::query($sql);
4674
4675
        if (Database::num_rows($rs) > 0) {
4676
            while ($row = Database::fetch_array($rs)) {
4677
                $data[] = $row;
4678
            }
4679
        }
4680
4681
        return $data;
4682
    }
4683
4684
    /**
4685
     * get links most visited by course.
4686
     *
4687
     * @param      string     Course code
4688
     * @param    int        Session id (optional),
4689
     * if param $session_id is null(default) it'll
4690
     * return results including sessions, 0 = session is not filtered
4691
     *
4692
     * @return array links most visited
4693
     */
4694
    public static function get_links_most_visited_by_course($course_code, $session_id = null)
4695
    {
4696
        $course_code = Database::escape_string($course_code);
4697
        $course_info = api_get_course_info($course_code);
4698
        $course_id = $course_info['real_id'];
4699
        $data = [];
4700
4701
        $TABLETRACK_LINKS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
4702
        $TABLECOURSE_LINKS = Database::get_course_table(TABLE_LINK);
4703
4704
        $condition_session = '';
4705
        if (isset($session_id)) {
4706
            $session_id = intval($session_id);
4707
            $condition_session = ' AND cl.session_id = '.$session_id;
4708
        }
4709
4710
        $sql = "SELECT cl.title, cl.url,count(DISTINCT sl.links_user_id), count(cl.title) as count_visits
4711
                FROM $TABLETRACK_LINKS AS sl, $TABLECOURSE_LINKS AS cl
4712
                WHERE
4713
                    cl.c_id = $course_id AND
4714
                    sl.links_link_id = cl.id AND
4715
                    sl.c_id = $course_id
4716
                    $condition_session
4717
                GROUP BY cl.title, cl.url
4718
                ORDER BY count_visits DESC
4719
                LIMIT 0, 3";
4720
        $rs = Database::query($sql);
4721
        if (Database::num_rows($rs) > 0) {
4722
            while ($row = Database::fetch_array($rs)) {
4723
                $data[] = $row;
4724
            }
4725
        }
4726
4727
        return $data;
4728
    }
4729
4730
    /**
4731
     * Shows the user progress (when clicking in the Progress tab).
4732
     *
4733
     * @param int    $user_id
4734
     * @param int    $session_id
4735
     * @param string $extra_params
4736
     * @param bool   $show_courses
4737
     * @param bool   $showAllSessions
4738
     * @param bool   $returnArray
4739
     *
4740
     * @return string|array
4741
     */
4742
    public static function show_user_progress(
4743
        $user_id,
4744
        $session_id = 0,
4745
        $extra_params = '',
4746
        $show_courses = true,
4747
        $showAllSessions = true,
4748
        $returnArray = false
4749
    ) {
4750
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
4751
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
4752
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4753
        $tbl_access_rel_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4754
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4755
        $tbl_access_rel_session = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
4756
4757
        $trackingColumns = [
4758
            'course_session' => [
4759
                'course_title' => true,
4760
                'published_exercises' => true,
4761
                'new_exercises' => true,
4762
                'my_average' => true,
4763
                'average_exercise_result' => true,
4764
                'time_spent' => true,
4765
                'lp_progress' => true,
4766
                'score' => true,
4767
                'best_score' => true,
4768
                'last_connection' => true,
4769
                'details' => true,
4770
            ],
4771
        ];
4772
4773
        $trackingColumnsConfig = api_get_configuration_value('tracking_columns');
4774
        if (!empty($trackingColumnsConfig)) {
4775
            $trackingColumns = $trackingColumnsConfig;
4776
        }
4777
4778
        $user_id = (int) $user_id;
4779
        $session_id = (int) $session_id;
4780
        $urlId = api_get_current_access_url_id();
4781
4782
        if (api_is_multiple_url_enabled()) {
4783
            $sql = "SELECT c.id, c.code, title
4784
                    FROM $tbl_course_user cu
4785
                    INNER JOIN $tbl_course c
4786
                    ON (cu.c_id = c.id)
4787
                    INNER JOIN $tbl_access_rel_course a
4788
                    ON (a.c_id = c.id)
4789
                    WHERE
4790
                        cu.user_id = $user_id AND
4791
                        relation_type<> ".COURSE_RELATION_TYPE_RRHH." AND
4792
                        access_url_id = $urlId
4793
                    ORDER BY title";
4794
        } else {
4795
            $sql = "SELECT c.id, c.code, title
4796
                    FROM $tbl_course_user u
4797
                    INNER JOIN $tbl_course c ON (c_id = c.id)
4798
                    WHERE
4799
                        u.user_id= $user_id AND
4800
                        relation_type <> ".COURSE_RELATION_TYPE_RRHH."
4801
                    ORDER BY title";
4802
        }
4803
4804
        $rs = Database::query($sql);
4805
        $courses = $course_in_session = $temp_course_in_session = [];
4806
        $courseIdList = [];
4807
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4808
            $courses[$row['code']] = $row['title'];
4809
            $courseIdList[] = $row['id'];
4810
        }
4811
4812
        $orderBy = ' ORDER BY name ';
4813
        $extraInnerJoin = null;
4814
4815
        if (SessionManager::orderCourseIsEnabled() && !empty($session_id)) {
4816
            $orderBy = ' ORDER BY s.id, position ';
4817
            $tableSessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
4818
            $extraInnerJoin = " INNER JOIN $tableSessionRelCourse src
4819
                                ON (cu.c_id = src.c_id AND src.session_id = $session_id) ";
4820
        }
4821
4822
        $sessionCondition = '';
4823
        if (!empty($session_id)) {
4824
            $sessionCondition = " AND s.id = $session_id";
4825
        }
4826
4827
        // Get the list of sessions where the user is subscribed as student
4828
        if (api_is_multiple_url_enabled()) {
4829
            $sql = "SELECT DISTINCT c.code, s.id as session_id, name
4830
                    FROM $tbl_session_course_user cu
4831
                    INNER JOIN $tbl_access_rel_session a
4832
                    ON (a.session_id = cu.session_id)
4833
                    INNER JOIN $tbl_session s
4834
                    ON (s.id = a.session_id)
4835
                    INNER JOIN $tbl_course c
4836
                    ON (c.id = cu.c_id)
4837
                    $extraInnerJoin
4838
                    WHERE
4839
                        cu.user_id = $user_id AND
4840
                        access_url_id = ".$urlId."
4841
                        $sessionCondition
4842
                    $orderBy ";
4843
        } else {
4844
            $sql = "SELECT DISTINCT c.code, s.id as session_id, name
4845
                    FROM $tbl_session_course_user cu
4846
                    INNER JOIN $tbl_session s
4847
                    ON (s.id = cu.session_id)
4848
                    INNER JOIN $tbl_course c
4849
                    ON (c.id = cu.c_id)
4850
                    $extraInnerJoin
4851
                    WHERE
4852
                        cu.user_id = $user_id
4853
                        $sessionCondition
4854
                    $orderBy ";
4855
        }
4856
4857
        $rs = Database::query($sql);
4858
        $simple_session_array = [];
4859
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4860
            $course_info = api_get_course_info($row['code']);
4861
            $temp_course_in_session[$row['session_id']]['course_list'][$course_info['real_id']] = $course_info;
4862
            $temp_course_in_session[$row['session_id']]['name'] = $row['name'];
4863
            $simple_session_array[$row['session_id']] = $row['name'];
4864
        }
4865
4866
        foreach ($simple_session_array as $my_session_id => $session_name) {
4867
            $course_list = $temp_course_in_session[$my_session_id]['course_list'];
4868
            $my_course_data = [];
4869
            foreach ($course_list as $courseId => $course_data) {
4870
                $my_course_data[$courseId] = $course_data['title'];
4871
            }
4872
4873
            if (empty($session_id)) {
4874
                $my_course_data = utf8_sort($my_course_data);
4875
            }
4876
4877
            $final_course_data = [];
4878
            foreach ($my_course_data as $course_id => $value) {
4879
                if (isset($course_list[$course_id])) {
4880
                    $final_course_data[$course_id] = $course_list[$course_id];
4881
                }
4882
            }
4883
            $course_in_session[$my_session_id]['course_list'] = $final_course_data;
4884
            $course_in_session[$my_session_id]['name'] = $session_name;
4885
        }
4886
4887
        if ($returnArray) {
4888
            $course_in_session[0] = $courseIdList;
4889
4890
            return $course_in_session;
4891
        }
4892
4893
        $html = '';
4894
        // Course list
4895
        if ($show_courses) {
4896
            if (!empty($courses)) {
4897
                $html .= Display::page_subheader(
4898
                    Display::return_icon(
4899
                        'course.png',
4900
                        get_lang('MyCourses'),
4901
                        [],
4902
                        ICON_SIZE_SMALL
4903
                    ).' '.get_lang('MyCourses')
4904
                );
4905
4906
                $columns = [
4907
                    'course_title' => get_lang('Course'),
4908
                    'time_spent' => get_lang('TimeSpentInTheCourse'),
4909
                    'progress' => get_lang('Progress'),
4910
                    'best_score_in_lp' => get_lang('BestScoreInLearningPath'),
4911
                    'best_score_not_in_lp' => get_lang('BestScoreNotInLearningPath'),
4912
                    'latest_login' => get_lang('LastConnexion'),
4913
                    'details' => get_lang('Details'),
4914
                ];
4915
                $availableColumns = [];
4916
                if (isset($trackingColumns['my_progress_courses'])) {
4917
                    $availableColumns = $trackingColumns['my_progress_courses'];
4918
                }
4919
                $html .= '<div class="table-responsive">';
4920
                $html .= '<table class="table table-striped table-hover">';
4921
                $html .= '<thead><tr>';
4922
                foreach ($columns as $columnKey => $name) {
4923
                    if (!empty($availableColumns)) {
4924
                        if (isset($availableColumns[$columnKey]) && $availableColumns[$columnKey] == false) {
4925
                            continue;
4926
                        }
4927
                    }
4928
                    $html .= Display::tag('th', $name);
4929
                }
4930
                $html .= '</tr></thead><tbody>';
4931
4932
                foreach ($courses as $course_code => $course_title) {
4933
                    $courseInfo = api_get_course_info($course_code);
4934
                    $courseId = $courseInfo['real_id'];
4935
4936
                    $total_time_login = self::get_time_spent_on_the_course(
4937
                        $user_id,
4938
                        $courseId
4939
                    );
4940
                    $time = api_time_to_hms($total_time_login);
4941
                    $progress = self::get_avg_student_progress(
4942
                        $user_id,
4943
                        $course_code
4944
                    );
4945
                    $bestScore = self::get_avg_student_score(
4946
                        $user_id,
4947
                        $course_code,
4948
                        [],
4949
                        null,
4950
                        false,
4951
                        false,
4952
                        true
4953
                    );
4954
4955
                    $exerciseList = ExerciseLib::get_all_exercises(
4956
                        $courseInfo,
4957
                        0,
4958
                        false,
4959
                        null,
4960
                        false,
4961
                        1
4962
                    );
4963
4964
                    $bestScoreAverageNotInLP = 0;
4965
                    if (!empty($exerciseList)) {
4966
                        foreach ($exerciseList as $exerciseData) {
4967
                            $results = Event::get_best_exercise_results_by_user(
4968
                                $exerciseData['id'],
4969
                                $courseInfo['real_id'],
4970
                                0,
4971
                                $user_id
4972
                            );
4973
                            $best = 0;
4974
                            if (!empty($results)) {
4975
                                foreach ($results as $result) {
4976
                                    if (!empty($result['max_score'])) {
4977
                                        $score = $result['score'] / $result['max_score'];
4978
                                        if ($score > $best) {
4979
                                            $best = $score;
4980
                                        }
4981
                                    }
4982
                                }
4983
                            }
4984
                            $bestScoreAverageNotInLP += $best;
4985
                        }
4986
                        $bestScoreAverageNotInLP = round($bestScoreAverageNotInLP / count($exerciseList) * 100, 2);
4987
                    }
4988
4989
                    $last_connection = self::get_last_connection_date_on_the_course(
4990
                        $user_id,
4991
                        $courseInfo
4992
                    );
4993
4994
                    if (is_null($progress) || empty($progress)) {
4995
                        $progress = '0%';
4996
                    } else {
4997
                        $progress = $progress.'%';
4998
                    }
4999
5000
                    if (isset($_GET['course']) &&
5001
                        $course_code == $_GET['course'] &&
5002
                        empty($_GET['session_id'])
5003
                    ) {
5004
                        $html .= '<tr class="row_odd" style="background-color:#FBF09D">';
5005
                    } else {
5006
                        $html .= '<tr class="row_even">';
5007
                    }
5008
                    $url = api_get_course_url($course_code, $session_id);
5009
                    $course_url = Display::url($course_title, $url, ['target' => SESSION_LINK_TARGET]);
5010
                    $bestScoreResult = '';
5011
                    if (empty($bestScore)) {
5012
                        $bestScoreResult = '-';
5013
                    } else {
5014
                        $bestScoreResult = $bestScore.'%';
5015
                    }
5016
                    $bestScoreNotInLP = '';
5017
                    if (empty($bestScoreAverageNotInLP)) {
5018
                        $bestScoreNotInLP = '-';
5019
                    } else {
5020
                        $bestScoreNotInLP = $bestScoreAverageNotInLP.'%';
5021
                    }
5022
5023
                    $detailsLink = '';
5024
                    if (isset($_GET['course']) &&
5025
                        $course_code == $_GET['course'] &&
5026
                        empty($_GET['session_id'])
5027
                    ) {
5028
                        $detailsLink .= '<a href="#course_session_header">';
5029
                        $detailsLink .= Display::return_icon('2rightarrow_na.png', get_lang('Details'));
5030
                        $detailsLink .= '</a>';
5031
                    } else {
5032
                        $detailsLink .= '<a href="'.api_get_self().'?course='.$course_code.$extra_params.'#course_session_header">';
5033
                        $detailsLink .= Display::return_icon('2rightarrow.png', get_lang('Details'));
5034
                        $detailsLink .= '</a>';
5035
                    }
5036
5037
                    $result = [
5038
                        'course_title' => $course_url,
5039
                        'time_spent' => $time,
5040
                        'progress' => $progress,
5041
                        'best_score_in_lp' => $bestScoreResult,
5042
                        'best_score_not_in_lp' => $bestScoreNotInLP,
5043
                        'latest_login' => $last_connection,
5044
                        'details' => $detailsLink,
5045
                    ];
5046
5047
                    foreach ($result as $columnKey => $data) {
5048
                        if (!empty($availableColumns)) {
5049
                            if (isset($availableColumns[$columnKey]) && $availableColumns[$columnKey] == false) {
5050
                                continue;
5051
                            }
5052
                        }
5053
                        $html .= '<td>'.$data.'</td>';
5054
                    }
5055
5056
                    $html .= '</tr>';
5057
                }
5058
                $html .= '</tbody></table>';
5059
                $html .= '</div>';
5060
            }
5061
        }
5062
5063
        // Session list
5064
        if (!empty($course_in_session)) {
5065
            $main_session_graph = '';
5066
            // Load graphics only when calling to an specific session
5067
            $all_exercise_graph_name_list = [];
5068
            $my_results = [];
5069
            $all_exercise_graph_list = [];
5070
            $all_exercise_start_time = [];
5071
            foreach ($course_in_session as $my_session_id => $session_data) {
5072
                $course_list = $session_data['course_list'];
5073
                $user_count = count(SessionManager::get_users_by_session($my_session_id));
5074
                $exercise_graph_name_list = [];
5075
                $exercise_graph_list = [];
5076
5077
                foreach ($course_list as $course_data) {
5078
                    $exercise_list = ExerciseLib::get_all_exercises(
5079
                        $course_data,
5080
                        $my_session_id,
5081
                        false,
5082
                        null,
5083
                        false,
5084
                        1
5085
                    );
5086
5087
                    foreach ($exercise_list as $exercise_data) {
5088
                        $exercise_obj = new Exercise($course_data['real_id']);
5089
                        $exercise_obj->read($exercise_data['id']);
5090
                        // Exercise is not necessary to be visible to show results check the result_disable configuration instead
5091
                        //$visible_return = $exercise_obj->is_visible();
5092
                        if ($exercise_data['results_disabled'] == 0 || $exercise_data['results_disabled'] == 2) {
5093
                            $best_average = (int)
5094
                                ExerciseLib::get_best_average_score_by_exercise(
5095
                                    $exercise_data['id'],
5096
                                    $course_data['real_id'],
5097
                                    $my_session_id,
5098
                                    $user_count
5099
                                )
5100
                            ;
5101
5102
                            $exercise_graph_list[] = $best_average;
5103
                            $all_exercise_graph_list[] = $best_average;
5104
5105
                            $user_result_data = ExerciseLib::get_best_attempt_by_user(
5106
                                api_get_user_id(),
5107
                                $exercise_data['id'],
5108
                                $course_data['real_id'],
5109
                                $my_session_id
5110
                            );
5111
5112
                            $score = 0;
5113
                            if (!empty($user_result_data['max_score']) && intval($user_result_data['max_score']) != 0) {
5114
                                $score = intval($user_result_data['score'] / $user_result_data['max_score'] * 100);
5115
                            }
5116
                            $time = api_strtotime($exercise_data['start_time']) ? api_strtotime($exercise_data['start_time'], 'UTC') : 0;
5117
                            $all_exercise_start_time[] = $time;
5118
                            $my_results[] = $score;
5119
                            if (count($exercise_list) <= 10) {
5120
                                $title = cut($course_data['title'], 30)." \n ".cut($exercise_data['title'], 30);
5121
                                $exercise_graph_name_list[] = $title;
5122
                                $all_exercise_graph_name_list[] = $title;
5123
                            } else {
5124
                                // if there are more than 10 results, space becomes difficult to find,
5125
                                // so only show the title of the exercise, not the tool
5126
                                $title = cut($exercise_data['title'], 30);
5127
                                $exercise_graph_name_list[] = $title;
5128
                                $all_exercise_graph_name_list[] = $title;
5129
                            }
5130
                        }
5131
                    }
5132
                }
5133
            }
5134
5135
            // Complete graph
5136
            if (!empty($my_results) && !empty($all_exercise_graph_list)) {
5137
                asort($all_exercise_start_time);
5138
5139
                //Fix exams order
5140
                $final_all_exercise_graph_name_list = [];
5141
                $my_results_final = [];
5142
                $final_all_exercise_graph_list = [];
5143
5144
                foreach ($all_exercise_start_time as $key => $time) {
5145
                    $label_time = '';
5146
                    if (!empty($time)) {
5147
                        $label_time = date('d-m-y', $time);
5148
                    }
5149
                    $final_all_exercise_graph_name_list[] = $all_exercise_graph_name_list[$key].' '.$label_time;
5150
                    $my_results_final[] = $my_results[$key];
5151
                    $final_all_exercise_graph_list[] = $all_exercise_graph_list[$key];
5152
                }
5153
                $main_session_graph = self::generate_session_exercise_graph(
5154
                    $final_all_exercise_graph_name_list,
5155
                    $my_results_final,
5156
                    $final_all_exercise_graph_list
5157
                );
5158
            }
5159
5160
            $sessionIcon = Display::return_icon(
5161
                'session.png',
5162
                get_lang('Sessions'),
5163
                [],
5164
                ICON_SIZE_SMALL
5165
            );
5166
5167
            $anchor = Display::url('', '', ['name' => 'course_session_header']);
5168
            $html .= $anchor.Display::page_subheader(
5169
                $sessionIcon.' '.get_lang('Sessions')
5170
            );
5171
5172
            $html .= '<div class="table-responsive">';
5173
            $html .= '<table class="table table-striped table-hover">';
5174
            $html .= '<thead>';
5175
            $html .= '<tr>
5176
                  '.Display::tag('th', get_lang('Session'), ['width' => '300px']).'
5177
                  '.Display::tag('th', get_lang('PublishedExercises'), ['width' => '300px']).'
5178
                  '.Display::tag('th', get_lang('NewExercises')).'
5179
                  '.Display::tag('th', get_lang('AverageExerciseResult')).'
5180
                  '.Display::tag('th', get_lang('Details')).'
5181
                  </tr>';
5182
            $html .= '</thead>';
5183
            $html .= '<tbody>';
5184
5185
            foreach ($course_in_session as $my_session_id => $session_data) {
5186
                $course_list = $session_data['course_list'];
5187
                $session_name = $session_data['name'];
5188
                if ($showAllSessions == false) {
5189
                    if (isset($session_id) && !empty($session_id)) {
5190
                        if ($session_id != $my_session_id) {
5191
                            continue;
5192
                        }
5193
                    }
5194
                }
5195
5196
                $all_exercises = 0;
5197
                $all_unanswered_exercises_by_user = 0;
5198
                $all_average = 0;
5199
                $stats_array = [];
5200
5201
                foreach ($course_list as $course_data) {
5202
                    // All exercises in the course @todo change for a real count
5203
                    $exercises = ExerciseLib::get_all_exercises($course_data, $my_session_id);
5204
                    $count_exercises = 0;
5205
                    if (is_array($exercises) && !empty($exercises)) {
5206
                        $count_exercises = count($exercises);
5207
                    }
5208
5209
                    // Count of user results
5210
                    $done_exercises = null;
5211
                    $courseInfo = api_get_course_info($course_data['code']);
5212
5213
                    $answered_exercises = 0;
5214
                    if (!empty($exercises)) {
5215
                        foreach ($exercises as $exercise_item) {
5216
                            $attempts = Event::count_exercise_attempts_by_user(
5217
                                api_get_user_id(),
5218
                                $exercise_item['id'],
5219
                                $courseInfo['real_id'],
5220
                                $my_session_id
5221
                            );
5222
                            if ($attempts > 1) {
5223
                                $answered_exercises++;
5224
                            }
5225
                        }
5226
                    }
5227
5228
                    // Average
5229
                    $average = ExerciseLib::get_average_score_by_course(
5230
                        $courseInfo['real_id'],
5231
                        $my_session_id
5232
                    );
5233
                    $all_exercises += $count_exercises;
5234
                    $all_unanswered_exercises_by_user += $count_exercises - $answered_exercises;
5235
                    $all_average += $average;
5236
                }
5237
5238
                if (!empty($course_list)) {
5239
                    $all_average = $all_average / count($course_list);
5240
                }
5241
5242
                if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) {
5243
                    $html .= '<tr style="background-color:#FBF09D">';
5244
                } else {
5245
                    $html .= '<tr>';
5246
                }
5247
                $url = api_get_path(WEB_CODE_PATH)."session/index.php?session_id={$my_session_id}";
5248
5249
                $html .= Display::tag('td', Display::url($session_name, $url, ['target' => SESSION_LINK_TARGET]));
5250
                $html .= Display::tag('td', $all_exercises);
5251
                $html .= Display::tag('td', $all_unanswered_exercises_by_user);
5252
                $html .= Display::tag('td', ExerciseLib::convert_to_percentage($all_average));
5253
5254
                if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) {
5255
                    $icon = Display::url(
5256
                        Display::return_icon(
5257
                            '2rightarrow_na.png',
5258
                            get_lang('Details')
5259
                        ),
5260
                        api_get_self().'?session_id='.$my_session_id.'#course_session_list'
5261
                    );
5262
                } else {
5263
                    $icon = Display::url(
5264
                        Display::return_icon(
5265
                            '2rightarrow.png',
5266
                            get_lang('Details')
5267
                        ),
5268
                        api_get_self().'?session_id='.$my_session_id.'#course_session_list'
5269
                    );
5270
                }
5271
                $html .= Display::tag('td', $icon);
5272
                $html .= '</tr>';
5273
            }
5274
            $html .= '</tbody>';
5275
            $html .= '</table></div><br />';
5276
            $html .= Display::div(
5277
                $main_session_graph,
5278
                [
5279
                    'id' => 'session_graph',
5280
                    'class' => 'chart-session',
5281
                    'style' => 'position:relative; text-align: center;',
5282
                ]
5283
            );
5284
5285
            // Checking selected session.
5286
            if (isset($_GET['session_id'])) {
5287
                $session_id_from_get = (int) $_GET['session_id'];
5288
                $session_data = $course_in_session[$session_id_from_get];
5289
                $course_list = $session_data['course_list'];
5290
5291
                $html .= '<a name= "course_session_list"></a>';
5292
                $html .= Display::tag('h3', $session_data['name'].' - '.get_lang('CourseList'));
5293
5294
                $html .= '<div class="table-responsive">';
5295
                $html .= '<table class="table table-hover table-striped">';
5296
5297
                $columnHeaders = [
5298
                    'course_title' => [
5299
                        get_lang('Course'),
5300
                        ['width' => '300px'],
5301
                    ],
5302
                    'published_exercises' => [
5303
                        get_lang('PublishedExercises'),
5304
                    ],
5305
                    'new_exercises' => [
5306
                        get_lang('NewExercises'),
5307
                    ],
5308
                    'my_average' => [
5309
                        get_lang('MyAverage'),
5310
                    ],
5311
                    'average_exercise_result' => [
5312
                        get_lang('AverageExerciseResult'),
5313
                    ],
5314
                    'time_spent' => [
5315
                        get_lang('TimeSpentInTheCourse'),
5316
                    ],
5317
                    'lp_progress' => [
5318
                        get_lang('LPProgress'),
5319
                    ],
5320
                    'score' => [
5321
                        get_lang('Score').
5322
                        Display::return_icon(
5323
                            'info3.gif',
5324
                            get_lang('ScormAndLPTestTotalAverage'),
5325
                            ['align' => 'absmiddle', 'hspace' => '3px']
5326
                        ),
5327
                    ],
5328
                    'best_score' => [
5329
                        get_lang('BestScore'),
5330
                    ],
5331
                    'last_connection' => [
5332
                        get_lang('LastConnexion'),
5333
                    ],
5334
                    'details' => [
5335
                        get_lang('Details'),
5336
                    ],
5337
                ];
5338
5339
                $html .= '<thead><tr>';
5340
                foreach ($columnHeaders as $key => $columnSetting) {
5341
                    if (isset($trackingColumns['course_session']) &&
5342
                        in_array($key, $trackingColumns['course_session']) &&
5343
                        $trackingColumns['course_session'][$key]
5344
                    ) {
5345
                        $settings = isset($columnSetting[1]) ? $columnSetting[1] : [];
5346
                        $html .= Display::tag(
5347
                             'th',
5348
                             $columnSetting[0],
5349
                             $settings
5350
                         );
5351
                    }
5352
                }
5353
5354
                $html .= '</tr>
5355
                    </thead>
5356
                    <tbody>';
5357
5358
                foreach ($course_list as $course_data) {
5359
                    $course_code = $course_data['code'];
5360
                    $course_title = $course_data['title'];
5361
                    $courseId = $course_data['real_id'];
5362
5363
                    // All exercises in the course @todo change for a real count
5364
                    $exercises = ExerciseLib::get_all_exercises(
5365
                        $course_data,
5366
                        $session_id_from_get
5367
                    );
5368
                    $count_exercises = 0;
5369
                    if (!empty($exercises)) {
5370
                        $count_exercises = count($exercises);
5371
                    }
5372
                    $answered_exercises = 0;
5373
                    foreach ($exercises as $exercise_item) {
5374
                        $attempts = Event::count_exercise_attempts_by_user(
5375
                            api_get_user_id(),
5376
                            $exercise_item['id'],
5377
                            $courseId,
5378
                            $session_id_from_get
5379
                        );
5380
                        if ($attempts > 1) {
5381
                            $answered_exercises++;
5382
                        }
5383
                    }
5384
5385
                    $unanswered_exercises = $count_exercises - $answered_exercises;
5386
5387
                    // Average
5388
                    $average = ExerciseLib::get_average_score_by_course(
5389
                        $courseId,
5390
                        $session_id_from_get
5391
                    );
5392
                    $my_average = ExerciseLib::get_average_score_by_course_by_user(
5393
                        api_get_user_id(),
5394
                        $courseId,
5395
                        $session_id_from_get
5396
                    );
5397
5398
                    $bestScore = self::get_avg_student_score(
5399
                        $user_id,
5400
                        $course_code,
5401
                        [],
5402
                        $session_id_from_get,
5403
                        false,
5404
                        false,
5405
                        true
5406
                    );
5407
5408
                    $stats_array[$course_code] = [
5409
                        'exercises' => $count_exercises,
5410
                        'unanswered_exercises_by_user' => $unanswered_exercises,
5411
                        'done_exercises' => $done_exercises,
5412
                        'average' => $average,
5413
                        'my_average' => $my_average,
5414
                        'best_score' => $bestScore,
5415
                    ];
5416
5417
                    $last_connection = self::get_last_connection_date_on_the_course(
5418
                        $user_id,
5419
                        $course_data,
5420
                        $session_id_from_get
5421
                    );
5422
5423
                    $progress = self::get_avg_student_progress(
5424
                        $user_id,
5425
                        $course_code,
5426
                        [],
5427
                        $session_id_from_get
5428
                    );
5429
5430
                    $total_time_login = self::get_time_spent_on_the_course(
5431
                        $user_id,
5432
                        $courseId,
5433
                        $session_id_from_get
5434
                    );
5435
                    $time = api_time_to_hms($total_time_login);
5436
5437
                    $percentage_score = self::get_avg_student_score(
5438
                        $user_id,
5439
                        $course_code,
5440
                        [],
5441
                        $session_id_from_get
5442
                    );
5443
                    $courseCodeFromGet = isset($_GET['course']) ? $_GET['course'] : null;
5444
5445
                    if ($course_code == $courseCodeFromGet && $_GET['session_id'] == $session_id_from_get) {
5446
                        $html .= '<tr class="row_odd" style="background-color:#FBF09D" >';
5447
                    } else {
5448
                        $html .= '<tr class="row_even">';
5449
                    }
5450
5451
                    $url = api_get_course_url($course_code, $session_id_from_get);
5452
                    $course_url = Display::url(
5453
                        $course_title,
5454
                        $url,
5455
                        ['target' => SESSION_LINK_TARGET]
5456
                    );
5457
5458
                    if (is_numeric($progress)) {
5459
                        $progress = $progress.'%';
5460
                    } else {
5461
                        $progress = '0%';
5462
                    }
5463
                    if (is_numeric($percentage_score)) {
5464
                        $percentage_score = $percentage_score.'%';
5465
                    } else {
5466
                        $percentage_score = '0%';
5467
                    }
5468
5469
                    if (is_numeric($stats_array[$course_code]['best_score'])) {
5470
                        $bestScore = $stats_array[$course_code]['best_score'].'%';
5471
                    } else {
5472
                        $bestScore = '-';
5473
                    }
5474
5475
                    if (empty($last_connection) || is_bool($last_connection)) {
5476
                        $last_connection = '';
5477
                    }
5478
5479
                    if ($course_code == $courseCodeFromGet &&
5480
                        $_GET['session_id'] == $session_id_from_get
5481
                    ) {
5482
                        $details = Display::url(
5483
                            Display::return_icon('2rightarrow_na.png', get_lang('Details')),
5484
                        '#course_session_data'
5485
                        );
5486
                    } else {
5487
                        $url = api_get_self().'?course='.$course_code.'&session_id='.$session_id_from_get.$extra_params.'#course_session_data';
5488
                        $details = Display::url(
5489
                            Display::return_icon(
5490
                                '2rightarrow.png',
5491
                                get_lang('Details')
5492
                            ),
5493
                            $url
5494
                        );
5495
                    }
5496
                    $details .= '</a>';
5497
5498
                    $data = [
5499
                        'course_title' => $course_url,
5500
                        'published_exercises' => $stats_array[$course_code]['exercises'], // exercise available
5501
                        'new_exercises' => $stats_array[$course_code]['unanswered_exercises_by_user'],
5502
                        'my_average' => ExerciseLib::convert_to_percentage($stats_array[$course_code]['my_average']),
5503
                        'average_exercise_result' => $stats_array[$course_code]['average'] == 0 ? '-' : '('.ExerciseLib::convert_to_percentage($stats_array[$course_code]['average']).')',
5504
                        'time_spent' => $time,
5505
                        'lp_progress' => $progress,
5506
                        'score' => $percentage_score,
5507
                        'best_score' => $bestScore,
5508
                        'last_connection' => $last_connection,
5509
                        'details' => $details,
5510
                    ];
5511
5512
                    foreach ($data as $key => $value) {
5513
                        if (in_array($key, $trackingColumns['course_session'])
5514
                            && $trackingColumns['course_session'][$key]
5515
                        ) {
5516
                            $html .= Display::tag('td', $value);
5517
                        }
5518
                    }
5519
                    $html .= '</tr>';
5520
                }
5521
                $html .= '</tbody></table></div>';
5522
            }
5523
        }
5524
5525
        $pluginCalendar = api_get_plugin_setting('learning_calendar', 'enabled') === 'true';
5526
        if ($pluginCalendar) {
5527
            $course_in_session[0] = $courseIdList;
5528
            $plugin = LearningCalendarPlugin::create();
5529
            $html .= $plugin->getUserStatsPanel($user_id, $course_in_session);
5530
        }
5531
5532
        return $html;
5533
    }
5534
5535
    /**
5536
     * Shows the user detail progress (when clicking in the details link).
5537
     *
5538
     * @param int    $user_id
5539
     * @param string $course_code
5540
     * @param int    $session_id
5541
     *
5542
     * @return string html code
5543
     */
5544
    public static function show_course_detail($user_id, $course_code, $session_id)
5545
    {
5546
        $html = '';
5547
        if (isset($course_code)) {
5548
            $user_id = intval($user_id);
5549
            $session_id = intval($session_id);
5550
            $course = Database::escape_string($course_code);
5551
            $course_info = api_get_course_info($course);
5552
            if (empty($course_info)) {
5553
                return '';
5554
            }
5555
5556
            $html .= '<a name="course_session_data"></a>';
5557
            $html .= Display::page_subheader($course_info['title']);
5558
            $html .= '<div class="table-responsive">';
5559
            $html .= '<table class="table table-striped table-hover">';
5560
5561
            //Course details
5562
            $html .= '
5563
                <thead>
5564
                <tr>
5565
                <th>'.get_lang('Exercises').'</th>
5566
                <th>'.get_lang('Attempts').'</th>
5567
                <th>'.get_lang('BestAttempt').'</th>
5568
                <th>'.get_lang('Ranking').'</th>
5569
                <th>'.get_lang('BestResultInCourse').'</th>
5570
                <th>'.get_lang('Statistics').' '.Display::return_icon('info3.gif', get_lang('OnlyBestResultsPerStudent'), ['align' => 'absmiddle', 'hspace' => '3px']).'</th>
5571
                </tr>
5572
                </thead>
5573
                <tbody>';
5574
5575
            if (empty($session_id)) {
5576
                $user_list = CourseManager::get_user_list_from_course_code(
5577
                    $course,
5578
                    $session_id,
5579
                    null,
5580
                    null,
5581
                    STUDENT
5582
                );
5583
            } else {
5584
                $user_list = CourseManager::get_user_list_from_course_code(
5585
                    $course,
5586
                    $session_id,
5587
                    null,
5588
                    null,
5589
                    0
5590
                );
5591
            }
5592
5593
            // Show exercise results of invisible exercises? see BT#4091
5594
            $exercise_list = ExerciseLib::get_all_exercises(
5595
                $course_info,
5596
                $session_id,
5597
                false,
5598
                null,
5599
                false,
5600
                2
5601
            );
5602
5603
            $to_graph_exercise_result = [];
5604
            if (!empty($exercise_list)) {
5605
                $score = $weighting = $exe_id = 0;
5606
                foreach ($exercise_list as $exercices) {
5607
                    $exercise_obj = new Exercise($course_info['real_id']);
5608
                    $exercise_obj->read($exercices['id']);
5609
                    $visible_return = $exercise_obj->is_visible();
5610
                    $score = $weighting = $attempts = 0;
5611
5612
                    // Getting count of attempts by user
5613
                    $attempts = Event::count_exercise_attempts_by_user(
5614
                        api_get_user_id(),
5615
                        $exercices['id'],
5616
                        $course_info['real_id'],
5617
                        $session_id
5618
                    );
5619
5620
                    $html .= '<tr class="row_even">';
5621
                    $url = api_get_path(WEB_CODE_PATH)."exercise/overview.php?cidReq={$course_info['code']}&id_session=$session_id&exerciseId={$exercices['id']}";
5622
5623
                    if ($visible_return['value'] == true) {
5624
                        $exercices['title'] = Display::url(
5625
                            $exercices['title'],
5626
                            $url,
5627
                            ['target' => SESSION_LINK_TARGET]
5628
                        );
5629
                    } elseif ($exercices['active'] == -1) {
5630
                        $exercices['title'] = sprintf(get_lang('XParenthesisDeleted'), $exercices['title']);
5631
                    }
5632
5633
                    $html .= Display::tag('td', $exercices['title']);
5634
5635
                    // Exercise configuration show results or show only score
5636
                    if ($exercices['results_disabled'] == 0 || $exercices['results_disabled'] == 2) {
5637
                        //For graphics
5638
                        $best_exercise_stats = Event::get_best_exercise_results_by_user(
5639
                            $exercices['id'],
5640
                            $course_info['real_id'],
5641
                            $session_id
5642
                        );
5643
5644
                        $to_graph_exercise_result[$exercices['id']] = [
5645
                            'title' => $exercices['title'],
5646
                            'data' => $best_exercise_stats,
5647
                        ];
5648
5649
                        $latest_attempt_url = '';
5650
                        $best_score = $position = $percentage_score_result = '-';
5651
                        $graph = $normal_graph = null;
5652
5653
                        // Getting best results
5654
                        $best_score_data = ExerciseLib::get_best_attempt_in_course(
5655
                            $exercices['id'],
5656
                            $course_info['real_id'],
5657
                            $session_id
5658
                        );
5659
5660
                        $best_score = '';
5661
                        if (!empty($best_score_data)) {
5662
                            $best_score = ExerciseLib::show_score(
5663
                                $best_score_data['score'],
5664
                                $best_score_data['max_score']
5665
                            );
5666
                        }
5667
5668
                        if ($attempts > 0) {
5669
                            $exercise_stat = ExerciseLib::get_best_attempt_by_user(
5670
                                api_get_user_id(),
5671
                                $exercices['id'],
5672
                                $course_info['real_id'],
5673
                                $session_id
5674
                            );
5675
                            if (!empty($exercise_stat)) {
5676
                                // Always getting the BEST attempt
5677
                                $score = $exercise_stat['score'];
5678
                                $weighting = $exercise_stat['max_score'];
5679
                                $exe_id = $exercise_stat['exe_id'];
5680
5681
                                $latest_attempt_url .= api_get_path(WEB_CODE_PATH).'exercise/result.php?id='.$exe_id.'&cidReq='.$course_info['code'].'&show_headers=1&id_session='.$session_id;
5682
                                $percentage_score_result = Display::url(
5683
                                    ExerciseLib::show_score($score, $weighting),
5684
                                    $latest_attempt_url
5685
                                );
5686
                                $my_score = 0;
5687
                                if (!empty($weighting) && intval($weighting) != 0) {
5688
                                    $my_score = $score / $weighting;
5689
                                }
5690
                                //@todo this function slows the page
5691
                                if (is_int($user_list)) {
5692
                                    $user_list = [$user_list];
5693
                                }
5694
                                $position = ExerciseLib::get_exercise_result_ranking(
5695
                                    $my_score,
5696
                                    $exe_id,
5697
                                    $exercices['id'],
5698
                                    $course_info['code'],
5699
                                    $session_id,
5700
                                    $user_list
5701
                                );
5702
5703
                                $graph = self::generate_exercise_result_thumbnail_graph(
5704
                                    $to_graph_exercise_result[$exercices['id']]
5705
                                );
5706
                                $normal_graph = self::generate_exercise_result_graph(
5707
                                    $to_graph_exercise_result[$exercices['id']]
5708
                                );
5709
                            }
5710
                        }
5711
                        $html .= Display::div(
5712
                            $normal_graph,
5713
                            [
5714
                                'id' => 'main_graph_'.$exercices['id'],
5715
                                'class' => 'dialog',
5716
                                'style' => 'display:none',
5717
                            ]
5718
                        );
5719
5720
                        if (empty($graph)) {
5721
                            $graph = '-';
5722
                        } else {
5723
                            $graph = Display::url(
5724
                                '<img src="'.$graph.'" >',
5725
                                $normal_graph,
5726
                                [
5727
                                    'id' => $exercices['id'],
5728
                                    'class' => 'expand-image',
5729
                                ]
5730
                            );
5731
                        }
5732
5733
                        $html .= Display::tag('td', $attempts);
5734
                        $html .= Display::tag('td', $percentage_score_result);
5735
                        $html .= Display::tag('td', $position);
5736
                        $html .= Display::tag('td', $best_score);
5737
                        $html .= Display::tag('td', $graph);
5738
                    } else {
5739
                        // Exercise configuration NO results
5740
                        $html .= Display::tag('td', $attempts);
5741
                        $html .= Display::tag('td', '-');
5742
                        $html .= Display::tag('td', '-');
5743
                        $html .= Display::tag('td', '-');
5744
                        $html .= Display::tag('td', '-');
5745
                    }
5746
                    $html .= '</tr>';
5747
                }
5748
            } else {
5749
                $html .= '<tr><td colspan="5">'.get_lang('NoEx').'</td></tr>';
5750
            }
5751
            $html .= '</tbody></table></div>';
5752
5753
            $columnHeaders = [
5754
                'lp' => get_lang('LearningPath'),
5755
                'time' => get_lang('LatencyTimeSpent'),
5756
                'progress' => get_lang('Progress'),
5757
                'score' => get_lang('Score'),
5758
                'best_score' => get_lang('BestScore'),
5759
                'last_connection' => get_lang('LastConnexion'),
5760
            ];
5761
5762
            $headers = '';
5763
            $trackingColumns = api_get_configuration_value('tracking_columns');
5764
            if (isset($trackingColumns['my_progress_lp'])) {
5765
                foreach ($columnHeaders as $key => $value) {
5766
                    if (!isset($trackingColumns['my_progress_lp'][$key]) ||
5767
                        $trackingColumns['my_progress_lp'][$key] == false
5768
                    ) {
5769
                        unset($columnHeaders[$key]);
5770
                    }
5771
                }
5772
            }
5773
5774
            $columnHeadersKeys = array_keys($columnHeaders);
5775
            foreach ($columnHeaders as $key => $columnName) {
5776
                $headers .= Display::tag(
5777
                    'th',
5778
                    $columnName
5779
                );
5780
            }
5781
5782
            // LP table results
5783
            $html .= '<div class="table-responsive">';
5784
            $html .= '<table class="table table-striped table-hover">';
5785
            $html .= '<thead><tr>';
5786
            $html .= $headers;
5787
            $html .= '</tr></thead><tbody>';
5788
5789
            $list = new LearnpathList(
5790
                api_get_user_id(),
5791
                $course_info['code'],
5792
                $session_id,
5793
                'lp.publicatedOn ASC',
5794
                true,
5795
                null,
5796
                true
5797
            );
5798
5799
            $lp_list = $list->get_flat_list();
5800
5801
            if (!empty($lp_list) > 0) {
5802
                foreach ($lp_list as $lp_id => $learnpath) {
5803
                    $progress = self::get_avg_student_progress(
5804
                        $user_id,
5805
                        $course,
5806
                        [$lp_id],
5807
                        $session_id
5808
                    );
5809
                    $last_connection_in_lp = self::get_last_connection_time_in_lp(
5810
                        $user_id,
5811
                        $course,
5812
                        $lp_id,
5813
                        $session_id
5814
                    );
5815
5816
                    $time_spent_in_lp = self::get_time_spent_in_lp(
5817
                        $user_id,
5818
                        $course,
5819
                        [$lp_id],
5820
                        $session_id
5821
                    );
5822
                    $percentage_score = self::get_avg_student_score(
5823
                        $user_id,
5824
                        $course,
5825
                        [$lp_id],
5826
                        $session_id
5827
                    );
5828
5829
                    $bestScore = self::get_avg_student_score(
5830
                        $user_id,
5831
                        $course,
5832
                        [$lp_id],
5833
                        $session_id,
5834
                        false,
5835
                        false,
5836
                        true
5837
                    );
5838
5839
                    if (is_numeric($progress)) {
5840
                        $progress = $progress.'%';
5841
                    }
5842
                    if (is_numeric($percentage_score)) {
5843
                        $percentage_score = $percentage_score.'%';
5844
                    } else {
5845
                        $percentage_score = '0%';
5846
                    }
5847
5848
                    if (is_numeric($bestScore)) {
5849
                        $bestScore = $bestScore.'%';
5850
                    } else {
5851
                        $bestScore = '-';
5852
                    }
5853
5854
                    $time_spent_in_lp = api_time_to_hms($time_spent_in_lp);
5855
                    $last_connection = '-';
5856
                    if (!empty($last_connection_in_lp)) {
5857
                        $last_connection = api_convert_and_format_date(
5858
                            $last_connection_in_lp,
5859
                            DATE_TIME_FORMAT_LONG
5860
                        );
5861
                    }
5862
5863
                    $url = api_get_path(WEB_CODE_PATH)."lp/lp_controller.php?cidReq={$course_code}&id_session=$session_id&lp_id=$lp_id&action=view";
5864
                    $html .= '<tr class="row_even">';
5865
5866
                    if (in_array('lp', $columnHeadersKeys)) {
5867
                        if ($learnpath['lp_visibility'] == 0) {
5868
                            $html .= Display::tag('td', $learnpath['lp_name']);
5869
                        } else {
5870
                            $html .= Display::tag(
5871
                                'td',
5872
                                Display::url(
5873
                                    $learnpath['lp_name'],
5874
                                    $url,
5875
                                    ['target' => SESSION_LINK_TARGET]
5876
                                )
5877
                            );
5878
                        }
5879
                    }
5880
5881
                    if (in_array('time', $columnHeadersKeys)) {
5882
                        $html .= Display::tag(
5883
                            'td',
5884
                            $time_spent_in_lp
5885
                        );
5886
                    }
5887
5888
                    if (in_array('progress', $columnHeadersKeys)) {
5889
                        $html .= Display::tag(
5890
                            'td',
5891
                            $progress
5892
                        );
5893
                    }
5894
5895
                    if (in_array('score', $columnHeadersKeys)) {
5896
                        $html .= Display::tag('td', $percentage_score);
5897
                    }
5898
                    if (in_array('best_score', $columnHeadersKeys)) {
5899
                        $html .= Display::tag('td', $bestScore);
5900
                    }
5901
5902
                    if (in_array('last_connection', $columnHeadersKeys)) {
5903
                        $html .= Display::tag('td', $last_connection, ['width' => '180px']);
5904
                    }
5905
                    $html .= '</tr>';
5906
                }
5907
            } else {
5908
                $html .= '<tr>
5909
                        <td colspan="4" align="center">
5910
                            '.get_lang('NoLearnpath').'
5911
                        </td>
5912
                      </tr>';
5913
            }
5914
            $html .= '</tbody></table></div>';
5915
5916
            $html .= self::displayUserSkills($user_id, $course_info['id'], $session_id);
5917
        }
5918
5919
        return $html;
5920
    }
5921
5922
    /**
5923
     * Generates an histogram.
5924
     *
5925
     * @param array $names      list of exercise names
5926
     * @param array $my_results my results 0 to 100
5927
     * @param array $average    average scores 0-100
5928
     *
5929
     * @return string
5930
     */
5931
    public static function generate_session_exercise_graph($names, $my_results, $average)
5932
    {
5933
        /* Create and populate the pData object */
5934
        $myData = new pData();
5935
        $myData->addPoints($names, 'Labels');
5936
        $myData->addPoints($my_results, 'Serie1');
5937
        $myData->addPoints($average, 'Serie2');
5938
        $myData->setSerieWeight('Serie1', 1);
5939
        $myData->setSerieTicks('Serie2', 4);
5940
        $myData->setSerieDescription('Labels', 'Months');
5941
        $myData->setAbscissa('Labels');
5942
        $myData->setSerieDescription('Serie1', get_lang('MyResults'));
5943
        $myData->setSerieDescription('Serie2', get_lang('AverageScore'));
5944
        $myData->setAxisUnit(0, '%');
5945
        $myData->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
5946
        // Cache definition
5947
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
5948
        $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]);
5949
        $chartHash = $myCache->getHash($myData);
5950
5951
        if ($myCache->isInCache($chartHash)) {
5952
            //if we already created the img
5953
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
5954
            $myCache->saveFromCache($chartHash, $imgPath);
5955
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
5956
        } else {
5957
            /* Define width, height and angle */
5958
            $mainWidth = 860;
5959
            $mainHeight = 500;
5960
            $angle = 50;
5961
5962
            /* Create the pChart object */
5963
            $myPicture = new pImage($mainWidth, $mainHeight, $myData);
5964
5965
            /* Turn of Antialiasing */
5966
            $myPicture->Antialias = false;
5967
5968
            /* Draw the background */
5969
            $settings = ['R' => 255, 'G' => 255, 'B' => 255];
5970
            $myPicture->drawFilledRectangle(0, 0, $mainWidth, $mainHeight, $settings);
5971
5972
            /* Add a border to the picture */
5973
            $myPicture->drawRectangle(
5974
                0,
5975
                0,
5976
                $mainWidth - 1,
5977
                $mainHeight - 1,
5978
                ['R' => 0, 'G' => 0, 'B' => 0]
5979
            );
5980
5981
            /* Set the default font */
5982
            $myPicture->setFontProperties(
5983
                [
5984
                    'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
5985
                    'FontSize' => 10, ]
5986
            );
5987
            /* Write the chart title */
5988
            $myPicture->drawText(
5989
                $mainWidth / 2,
5990
                30,
5991
                get_lang('ExercisesInTimeProgressChart'),
5992
                [
5993
                    'FontSize' => 12,
5994
                    'Align' => TEXT_ALIGN_BOTTOMMIDDLE,
5995
                ]
5996
            );
5997
5998
            /* Set the default font */
5999
            $myPicture->setFontProperties(
6000
                [
6001
                    'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
6002
                    'FontSize' => 6,
6003
                ]
6004
            );
6005
6006
            /* Define the chart area */
6007
            $myPicture->setGraphArea(60, 60, $mainWidth - 60, $mainHeight - 150);
6008
6009
            /* Draw the scale */
6010
            $scaleSettings = [
6011
                'XMargin' => 10,
6012
                'YMargin' => 10,
6013
                'Floating' => true,
6014
                'GridR' => 200,
6015
                'GridG' => 200,
6016
                'GridB' => 200,
6017
                'DrawSubTicks' => true,
6018
                'CycleBackground' => true,
6019
                'LabelRotation' => $angle,
6020
                'Mode' => SCALE_MODE_ADDALL_START0,
6021
            ];
6022
            $myPicture->drawScale($scaleSettings);
6023
6024
            /* Turn on Antialiasing */
6025
            $myPicture->Antialias = true;
6026
6027
            /* Enable shadow computing */
6028
            $myPicture->setShadow(
6029
                true,
6030
                [
6031
                    'X' => 1,
6032
                    'Y' => 1,
6033
                    'R' => 0,
6034
                    'G' => 0,
6035
                    'B' => 0,
6036
                    'Alpha' => 10,
6037
                ]
6038
            );
6039
6040
            /* Draw the line chart */
6041
            $myPicture->setFontProperties(
6042
                [
6043
                    'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
6044
                    'FontSize' => 10,
6045
                ]
6046
            );
6047
            $myPicture->drawSplineChart();
6048
            $myPicture->drawPlotChart(
6049
                [
6050
                    'DisplayValues' => true,
6051
                    'PlotBorder' => true,
6052
                    'BorderSize' => 1,
6053
                    'Surrounding' => -60,
6054
                    'BorderAlpha' => 80,
6055
                ]
6056
            );
6057
6058
            /* Write the chart legend */
6059
            $myPicture->drawLegend(
6060
                $mainWidth / 2 + 50,
6061
                50,
6062
                [
6063
                    'Style' => LEGEND_BOX,
6064
                    'Mode' => LEGEND_HORIZONTAL,
6065
                    'FontR' => 0,
6066
                    'FontG' => 0,
6067
                    'FontB' => 0,
6068
                    'R' => 220,
6069
                    'G' => 220,
6070
                    'B' => 220,
6071
                    'Alpha' => 100,
6072
                ]
6073
            );
6074
6075
            $myCache->writeToCache($chartHash, $myPicture);
6076
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
6077
            $myCache->saveFromCache($chartHash, $imgPath);
6078
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
6079
        }
6080
6081
        $html = '<img src="'.$imgPath.'">';
6082
6083
        return $html;
6084
    }
6085
6086
    /**
6087
     * Returns a thumbnail of the function generate_exercise_result_graph.
6088
     *
6089
     * @param array $attempts
6090
     */
6091
    public static function generate_exercise_result_thumbnail_graph($attempts)
6092
    {
6093
        //$exercise_title = $attempts['title'];
6094
        $attempts = $attempts['data'];
6095
        $my_exercise_result_array = $exercise_result = [];
6096
        if (empty($attempts)) {
6097
            return null;
6098
        }
6099
6100
        foreach ($attempts as $attempt) {
6101
            if (api_get_user_id() == $attempt['exe_user_id']) {
6102
                if ($attempt['max_score'] != 0) {
6103
                    $my_exercise_result_array[] = $attempt['score'] / $attempt['max_score'];
6104
                }
6105
            } else {
6106
                if ($attempt['max_score'] != 0) {
6107
                    $exercise_result[] = $attempt['score'] / $attempt['max_score'];
6108
                }
6109
            }
6110
        }
6111
6112
        //Getting best result
6113
        rsort($my_exercise_result_array);
6114
        $my_exercise_result = 0;
6115
        if (isset($my_exercise_result_array[0])) {
6116
            $my_exercise_result = $my_exercise_result_array[0] * 100;
6117
        }
6118
6119
        $max = 100;
6120
        $pieces = 5;
6121
        $part = round($max / $pieces);
6122
        $x_axis = [];
6123
        $final_array = [];
6124
        $my_final_array = [];
6125
6126
        for ($i = 1; $i <= $pieces; $i++) {
6127
            $sum = 1;
6128
            if ($i == 1) {
6129
                $sum = 0;
6130
            }
6131
            $min = ($i - 1) * $part + $sum;
6132
            $max = ($i) * $part;
6133
            $x_axis[] = $min." - ".$max;
6134
            $count = 0;
6135
            foreach ($exercise_result as $result) {
6136
                $percentage = $result * 100;
6137
                //echo $percentage.' - '.$min.' - '.$max."<br />";
6138
                if ($percentage >= $min && $percentage <= $max) {
6139
                    //echo ' is > ';
6140
                    $count++;
6141
                }
6142
            }
6143
            //echo '<br />';
6144
            $final_array[] = $count;
6145
6146
            if ($my_exercise_result >= $min && $my_exercise_result <= $max) {
6147
                $my_final_array[] = 1;
6148
            } else {
6149
                $my_final_array[] = 0;
6150
            }
6151
        }
6152
6153
        //Fix to remove the data of the user with my data
6154
        for ($i = 0; $i <= count($my_final_array); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
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
}
Loading history...
6155
            if (!empty($my_final_array[$i])) {
6156
                $my_final_array[$i] = $final_array[$i] + 1; //Add my result
6157
                $final_array[$i] = 0;
6158
            }
6159
        }
6160
6161
        // Dataset definition
6162
        $dataSet = new pData();
6163
        $dataSet->addPoints($final_array, 'Serie1');
6164
        $dataSet->addPoints($my_final_array, 'Serie2');
6165
        $dataSet->normalize(100, "%");
6166
        $dataSet->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
6167
6168
        // Cache definition
6169
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
6170
        $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]);
6171
        $chartHash = $myCache->getHash($dataSet);
6172
        if ($myCache->isInCache($chartHash)) {
6173
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
6174
            $myCache->saveFromCache($chartHash, $imgPath);
6175
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
6176
        } else {
6177
            /* Create the pChart object */
6178
            $widthSize = 80;
6179
            $heightSize = 35;
6180
            $fontSize = 2;
6181
6182
            $myPicture = new pImage($widthSize, $heightSize, $dataSet);
6183
6184
            /* Turn of Antialiasing */
6185
            $myPicture->Antialias = false;
6186
6187
            /* Add a border to the picture */
6188
            $myPicture->drawRectangle(
6189
                0,
6190
                0,
6191
                $widthSize - 1,
6192
                $heightSize - 1,
6193
                ['R' => 0, 'G' => 0, 'B' => 0]
6194
            );
6195
6196
            /* Set the default font */
6197
            $myPicture->setFontProperties(
6198
                [
6199
                    'FontName' => api_get_path(
6200
                            SYS_FONTS_PATH
6201
                        ).'opensans/OpenSans-Regular.ttf',
6202
                    'FontSize' => $fontSize,
6203
                ]
6204
            );
6205
6206
            /* Do not write the chart title */
6207
            /* Define the chart area */
6208
            $myPicture->setGraphArea(5, 5, $widthSize - 5, $heightSize - 5);
6209
6210
            /* Draw the scale */
6211
            $scaleSettings = [
6212
                'GridR' => 200,
6213
                'GridG' => 200,
6214
                'GridB' => 200,
6215
                'DrawSubTicks' => true,
6216
                'CycleBackground' => true,
6217
                'Mode' => SCALE_MODE_MANUAL,
6218
                'ManualScale' => [
6219
                    '0' => [
6220
                        'Min' => 0,
6221
                        'Max' => 100,
6222
                    ],
6223
                ],
6224
            ];
6225
            $myPicture->drawScale($scaleSettings);
6226
6227
            /* Turn on shadow computing */
6228
            $myPicture->setShadow(
6229
                true,
6230
                [
6231
                    'X' => 1,
6232
                    'Y' => 1,
6233
                    'R' => 0,
6234
                    'G' => 0,
6235
                    'B' => 0,
6236
                    'Alpha' => 10,
6237
                ]
6238
            );
6239
6240
            /* Draw the chart */
6241
            $myPicture->setShadow(
6242
                true,
6243
                [
6244
                    'X' => 1,
6245
                    'Y' => 1,
6246
                    'R' => 0,
6247
                    'G' => 0,
6248
                    'B' => 0,
6249
                    'Alpha' => 10,
6250
                ]
6251
            );
6252
            $settings = [
6253
                'DisplayValues' => true,
6254
                'DisplaySize' => $fontSize,
6255
                'DisplayR' => 0,
6256
                'DisplayG' => 0,
6257
                'DisplayB' => 0,
6258
                'DisplayOrientation' => ORIENTATION_HORIZONTAL,
6259
                'Gradient' => false,
6260
                'Surrounding' => 5,
6261
                'InnerSurrounding' => 5,
6262
            ];
6263
            $myPicture->drawStackedBarChart($settings);
6264
6265
            /* Save and write in cache */
6266
            $myCache->writeToCache($chartHash, $myPicture);
6267
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
6268
            $myCache->saveFromCache($chartHash, $imgPath);
6269
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
6270
        }
6271
6272
        return $imgPath;
6273
    }
6274
6275
    /**
6276
     * Generates a big graph with the number of best results.
6277
     *
6278
     * @param	array
6279
     */
6280
    public static function generate_exercise_result_graph($attempts)
6281
    {
6282
        $exercise_title = strip_tags($attempts['title']);
6283
        $attempts = $attempts['data'];
6284
        $my_exercise_result_array = $exercise_result = [];
6285
        if (empty($attempts)) {
6286
            return null;
6287
        }
6288
        foreach ($attempts as $attempt) {
6289
            if (api_get_user_id() == $attempt['exe_user_id']) {
6290
                if ($attempt['max_score'] != 0) {
6291
                    $my_exercise_result_array[] = $attempt['score'] / $attempt['max_score'];
6292
                }
6293
            } else {
6294
                if ($attempt['max_score'] != 0) {
6295
                    $exercise_result[] = $attempt['score'] / $attempt['max_score'];
6296
                }
6297
            }
6298
        }
6299
6300
        //Getting best result
6301
        rsort($my_exercise_result_array);
6302
        $my_exercise_result = 0;
6303
        if (isset($my_exercise_result_array[0])) {
6304
            $my_exercise_result = $my_exercise_result_array[0] * 100;
6305
        }
6306
6307
        $max = 100;
6308
        $pieces = 5;
6309
        $part = round($max / $pieces);
6310
        $x_axis = [];
6311
        $final_array = [];
6312
        $my_final_array = [];
6313
6314
        for ($i = 1; $i <= $pieces; $i++) {
6315
            $sum = 1;
6316
            if ($i == 1) {
6317
                $sum = 0;
6318
            }
6319
            $min = ($i - 1) * $part + $sum;
6320
            $max = ($i) * $part;
6321
            $x_axis[] = $min." - ".$max;
6322
            $count = 0;
6323
            foreach ($exercise_result as $result) {
6324
                $percentage = $result * 100;
6325
                if ($percentage >= $min && $percentage <= $max) {
6326
                    $count++;
6327
                }
6328
            }
6329
            $final_array[] = $count;
6330
6331
            if ($my_exercise_result >= $min && $my_exercise_result <= $max) {
6332
                $my_final_array[] = 1;
6333
            } else {
6334
                $my_final_array[] = 0;
6335
            }
6336
        }
6337
6338
        //Fix to remove the data of the user with my data
6339
6340
        for ($i = 0; $i <= count($my_final_array); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
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
}
Loading history...
6341
            if (!empty($my_final_array[$i])) {
6342
                $my_final_array[$i] = $final_array[$i] + 1; //Add my result
6343
                $final_array[$i] = 0;
6344
            }
6345
        }
6346
6347
        // Dataset definition
6348
        $dataSet = new pData();
6349
        $dataSet->addPoints($final_array, 'Serie1');
6350
        $dataSet->addPoints($my_final_array, 'Serie2');
6351
        $dataSet->addPoints($x_axis, 'Serie3');
6352
6353
        $dataSet->setSerieDescription('Serie1', get_lang('Score'));
6354
        $dataSet->setSerieDescription('Serie2', get_lang('MyResults'));
6355
        $dataSet->setAbscissa('Serie3');
6356
6357
        $dataSet->setXAxisName(get_lang('Score'));
6358
        $dataSet->normalize(100, "%");
6359
6360
        $dataSet->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
6361
6362
        // Cache definition
6363
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
6364
        $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]);
6365
        $chartHash = $myCache->getHash($dataSet);
6366
6367
        if ($myCache->isInCache($chartHash)) {
6368
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
6369
            $myCache->saveFromCache($chartHash, $imgPath);
6370
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
6371
        } else {
6372
            /* Create the pChart object */
6373
            $widthSize = 480;
6374
            $heightSize = 250;
6375
            $fontSize = 8;
6376
            $myPicture = new pImage($widthSize, $heightSize, $dataSet);
6377
6378
            /* Turn of Antialiasing */
6379
            $myPicture->Antialias = false;
6380
6381
            /* Add a border to the picture */
6382
            $myPicture->drawRectangle(0, 0, $widthSize - 1, $heightSize - 1, ['R' => 0, 'G' => 0, 'B' => 0]);
6383
6384
            /* Set the default font */
6385
            $myPicture->setFontProperties(
6386
                [
6387
                    'FontName' => api_get_path(
6388
                            SYS_FONTS_PATH
6389
                        ).'opensans/OpenSans-Regular.ttf',
6390
                    'FontSize' => 10,
6391
                ]
6392
            );
6393
6394
            /* Write the chart title */
6395
            $myPicture->drawText(
6396
                250,
6397
                20,
6398
                $exercise_title,
6399
                [
6400
                    'FontSize' => 12,
6401
                    'Align' => TEXT_ALIGN_BOTTOMMIDDLE,
6402
                ]
6403
            );
6404
6405
            /* Define the chart area */
6406
            $myPicture->setGraphArea(50, 50, $widthSize - 20, $heightSize - 30);
6407
6408
            /* Draw the scale */
6409
            $scaleSettings = [
6410
                'GridR' => 200,
6411
                'GridG' => 200,
6412
                'GridB' => 200,
6413
                'DrawSubTicks' => true,
6414
                'CycleBackground' => true,
6415
                'Mode' => SCALE_MODE_MANUAL,
6416
                'ManualScale' => [
6417
                    '0' => [
6418
                        'Min' => 0,
6419
                        'Max' => 100,
6420
                    ],
6421
                ],
6422
            ];
6423
            $myPicture->drawScale($scaleSettings);
6424
6425
            /* Turn on shadow computing */
6426
            $myPicture->setShadow(true, ['X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10]);
6427
6428
            /* Draw the chart */
6429
            $myPicture->setShadow(true, ['X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10]);
6430
            $settings = [
6431
                'DisplayValues' => true,
6432
                'DisplaySize' => $fontSize,
6433
                'DisplayR' => 0,
6434
                'DisplayG' => 0,
6435
                'DisplayB' => 0,
6436
                'DisplayOrientation' => ORIENTATION_HORIZONTAL,
6437
                'Gradient' => false,
6438
                'Surrounding' => 30,
6439
                'InnerSurrounding' => 25,
6440
            ];
6441
            $myPicture->drawStackedBarChart($settings);
6442
6443
            $legendSettings = [
6444
                'Mode' => LEGEND_HORIZONTAL,
6445
                'Style' => LEGEND_NOBORDER,
6446
            ];
6447
            $myPicture->drawLegend($widthSize / 2, 30, $legendSettings);
6448
6449
            /* Write and save into cache */
6450
            $myCache->writeToCache($chartHash, $myPicture);
6451
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
6452
            $myCache->saveFromCache($chartHash, $imgPath);
6453
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
6454
        }
6455
6456
        return $imgPath;
6457
    }
6458
6459
    /**
6460
     * @param FormValidator $form
6461
     *
6462
     * @return mixed
6463
     */
6464
    public static function setUserSearchForm($form)
6465
    {
6466
        global $_configuration;
6467
        $form->addElement('text', 'keyword', get_lang('Keyword'));
6468
        $form->addElement(
6469
            'select',
6470
            'active',
6471
            get_lang('Status'),
6472
            [1 => get_lang('Active'), 0 => get_lang('Inactive')]
6473
        );
6474
6475
        $form->addElement(
6476
            'select',
6477
            'sleeping_days',
6478
            get_lang('InactiveDays'),
6479
            [
6480
                '',
6481
                1 => 1,
6482
                5 => 5,
6483
                15 => 15,
6484
                30 => 30,
6485
                60 => 60,
6486
                90 => 90,
6487
                120 => 120,
6488
            ]
6489
        );
6490
6491
        $form->addButtonSearch(get_lang('Search'));
6492
6493
        return $form;
6494
    }
6495
6496
    /**
6497
     * Get the progress of a exercise.
6498
     *
6499
     * @param int    $sessionId  The session ID (session.id)
6500
     * @param int    $courseId   The course ID (course.id)
6501
     * @param int    $exerciseId The quiz ID (c_quiz.id)
6502
     * @param string $date_from
6503
     * @param string $date_to
6504
     * @param array  $options    An array of options you can pass to the query (limit, where and order)
6505
     *
6506
     * @return array An array with the data of exercise(s) progress
6507
     */
6508
    public static function get_exercise_progress(
6509
        $sessionId = 0,
6510
        $courseId = 0,
6511
        $exerciseId = 0,
6512
        $date_from = null,
6513
        $date_to = null,
6514
        $options = []
6515
    ) {
6516
        $sessionId = intval($sessionId);
6517
        $courseId = intval($courseId);
6518
        $exerciseId = intval($exerciseId);
6519
        $date_from = Database::escape_string($date_from);
6520
        $date_to = Database::escape_string($date_to);
6521
        /*
6522
         * This method gets the data by blocks, as previous attempts at one single
6523
         * query made it take ages. The logic of query division is described below
6524
         */
6525
        // Get tables names
6526
        $tuser = Database::get_main_table(TABLE_MAIN_USER);
6527
        $tquiz = Database::get_course_table(TABLE_QUIZ_TEST);
6528
        $tquiz_answer = Database::get_course_table(TABLE_QUIZ_ANSWER);
6529
        $tquiz_question = Database::get_course_table(TABLE_QUIZ_QUESTION);
6530
        $tquiz_rel_question = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
6531
        $ttrack_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
6532
        $ttrack_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
6533
6534
        $sessions = [];
6535
        $courses = [];
6536
        // if session ID is defined but course ID is empty, get all the courses
6537
        // from that session
6538
        if (!empty($sessionId) && empty($courseId)) {
6539
            // $courses is an array of course int id as index and course details hash as value
6540
            $courses = SessionManager::get_course_list_by_session_id($sessionId);
6541
            $sessions[$sessionId] = api_get_session_info($sessionId);
6542
        } elseif (empty($sessionId) && !empty($courseId)) {
6543
            // if, to the contrary, course is defined but not sessions, get the sessions that include this course
6544
            // $sessions is an array like: [0] => ('id' => 3, 'name' => 'Session 35'), [1] => () etc;
6545
            $course = api_get_course_info_by_id($courseId);
6546
            $sessionsTemp = SessionManager::get_session_by_course($courseId);
6547
            $courses[$courseId] = $course;
6548
            foreach ($sessionsTemp as $sessionItem) {
6549
                $sessions[$sessionItem['id']] = $sessionItem;
6550
            }
6551
        } elseif (!empty($courseId) && !empty($sessionId)) {
6552
            //none is empty
6553
            $course = api_get_course_info_by_id($courseId);
6554
            $courses[$courseId] = [$course['code']];
6555
            $courses[$courseId]['code'] = $course['code'];
6556
            $sessions[$sessionId] = api_get_session_info($sessionId);
6557
        } else {
6558
            //both are empty, not enough data, return an empty array
6559
            return [];
6560
        }
6561
        // Now we have two arrays of courses and sessions with enough data to proceed
6562
        // If no course could be found, we shouldn't return anything.
6563
        // Sessions can be empty (then we only return the pure-course-context results)
6564
        if (count($courses) < 1) {
6565
            return [];
6566
        }
6567
6568
        $data = [];
6569
        // The following loop is less expensive than what it seems:
6570
        // - if a course was defined, then we only loop through sessions
6571
        // - if a session was defined, then we only loop through courses
6572
        // - if a session and a course were defined, then we only loop once
6573
        foreach ($courses as $courseIdx => $courseData) {
6574
            $where = '';
6575
            $whereParams = [];
6576
            $whereSessionParams = '';
6577
            if (count($sessions > 0)) {
6578
                foreach ($sessions as $sessionIdx => $sessionData) {
6579
                    if (!empty($sessionIdx)) {
6580
                        $whereSessionParams .= $sessionIdx.',';
6581
                    }
6582
                }
6583
                $whereSessionParams = substr($whereSessionParams, 0, -1);
6584
            }
6585
6586
            if (!empty($exerciseId)) {
6587
                $exerciseId = intval($exerciseId);
6588
                $where .= ' AND q.id = %d ';
6589
                $whereParams[] = $exerciseId;
6590
            }
6591
6592
            /*
6593
             * This feature has been disabled for now, to avoid having to
6594
             * join two very large tables
6595
            //2 = show all questions (wrong and correct answered)
6596
            if ($answer != 2) {
6597
                $answer = intval($answer);
6598
                //$where .= ' AND qa.correct = %d';
6599
                //$whereParams[] = $answer;
6600
            }
6601
            */
6602
6603
            $limit = '';
6604
            if (!empty($options['limit'])) {
6605
                $limit = " LIMIT ".$options['limit'];
6606
            }
6607
6608
            if (!empty($options['where'])) {
6609
                $where .= ' AND '.Database::escape_string($options['where']);
6610
            }
6611
6612
            $order = '';
6613
            if (!empty($options['order'])) {
6614
                $order = " ORDER BY ".$options['order'];
6615
            }
6616
6617
            if (!empty($date_to) && !empty($date_from)) {
6618
                $where .= sprintf(" AND (te.start_date BETWEEN '%s 00:00:00' AND '%s 23:59:59')", $date_from, $date_to);
6619
            }
6620
6621
            $sql = "SELECT
6622
                te.session_id,
6623
                ta.id as attempt_id,
6624
                te.exe_user_id as user_id,
6625
                te.exe_id as exercise_attempt_id,
6626
                ta.question_id,
6627
                ta.answer as answer_id,
6628
                ta.tms as time,
6629
                te.exe_exo_id as quiz_id,
6630
                CONCAT ('c', q.c_id, '_e', q.id) as exercise_id,
6631
                q.title as quiz_title,
6632
                qq.description as description
6633
                FROM $ttrack_exercises te
6634
                INNER JOIN $ttrack_attempt ta 
6635
                ON ta.exe_id = te.exe_id
6636
                INNER JOIN $tquiz q 
6637
                ON q.id = te.exe_exo_id
6638
                INNER JOIN $tquiz_rel_question rq 
6639
                ON rq.exercice_id = q.id AND rq.c_id = q.c_id
6640
                INNER JOIN $tquiz_question qq
6641
                ON
6642
                    qq.id = rq.question_id AND
6643
                    qq.c_id = rq.c_id AND
6644
                    qq.position = rq.question_order AND
6645
                    ta.question_id = rq.question_id
6646
                WHERE
6647
                    te.c_id = $courseIdx ".(empty($whereSessionParams) ? '' : "AND te.session_id IN ($whereSessionParams)")."
6648
                    AND q.c_id = $courseIdx
6649
                    $where $order $limit";
6650
            $sql_query = vsprintf($sql, $whereParams);
6651
6652
            // Now browse through the results and get the data
6653
            $rs = Database::query($sql_query);
6654
            $userIds = [];
6655
            $questionIds = [];
6656
            $answerIds = [];
6657
            while ($row = Database::fetch_array($rs)) {
6658
                //only show if exercise is visible
6659
                if (api_get_item_visibility($courseData, 'quiz', $row['exercise_id'])) {
6660
                    $userIds[$row['user_id']] = $row['user_id'];
6661
                    $questionIds[$row['question_id']] = $row['question_id'];
6662
                    $answerIds[$row['question_id']][$row['answer_id']] = $row['answer_id'];
6663
                    $row['session'] = $sessions[$row['session_id']];
6664
                    $data[] = $row;
6665
                }
6666
            }
6667
            // Now fill questions data. Query all questions and answers for this test to avoid
6668
            $sqlQuestions = "SELECT tq.c_id, tq.id as question_id, tq.question, tqa.id_auto,
6669
                            tqa.answer, tqa.correct, tq.position, tqa.id_auto as answer_id
6670
                            FROM $tquiz_question tq, $tquiz_answer tqa
6671
                            WHERE
6672
                                tqa.question_id = tq.id AND
6673
                                tqa.c_id = tq.c_id AND
6674
                                tq.c_id = $courseIdx AND
6675
                                tq.id IN (".implode(',', $questionIds).")";
6676
6677
            $resQuestions = Database::query($sqlQuestions);
6678
            $answer = [];
6679
            $question = [];
6680
            while ($rowQuestion = Database::fetch_assoc($resQuestions)) {
6681
                $questionId = $rowQuestion['question_id'];
6682
                $answerId = $rowQuestion['answer_id'];
6683
                $answer[$questionId][$answerId] = [
6684
                    'position' => $rowQuestion['position'],
6685
                    'question' => $rowQuestion['question'],
6686
                    'answer' => $rowQuestion['answer'],
6687
                    'correct' => $rowQuestion['correct'],
6688
                ];
6689
                $question[$questionId]['question'] = $rowQuestion['question'];
6690
            }
6691
6692
            // Now fill users data
6693
            $sqlUsers = "SELECT user_id, username, lastname, firstname
6694
                         FROM $tuser
6695
                         WHERE user_id IN (".implode(',', $userIds).")";
6696
            $resUsers = Database::query($sqlUsers);
6697
            while ($rowUser = Database::fetch_assoc($resUsers)) {
6698
                $users[$rowUser['user_id']] = $rowUser;
6699
            }
6700
6701
            foreach ($data as $id => $row) {
6702
                $rowQuestId = $row['question_id'];
6703
                $rowAnsId = $row['answer_id'];
6704
                $data[$id]['session'] = $sessions[$row['session_id']]['name'];
6705
                $data[$id]['firstname'] = $users[$row['user_id']]['firstname'];
6706
                $data[$id]['lastname'] = $users[$row['user_id']]['lastname'];
6707
                $data[$id]['username'] = $users[$row['user_id']]['username'];
6708
                $data[$id]['answer'] = $answer[$rowQuestId][$rowAnsId]['answer'];
6709
                $data[$id]['correct'] = ($answer[$rowQuestId][$rowAnsId]['correct'] == 0 ? get_lang('No') : get_lang('Yes'));
6710
                $data[$id]['question'] = $question[$rowQuestId]['question'];
6711
                $data[$id]['question_id'] = $rowQuestId;
6712
                $data[$id]['description'] = $row['description'];
6713
            }
6714
6715
            /*
6716
            The minimum expected array structure at the end is:
6717
            attempt_id,
6718
            session name,
6719
            exercise_id,
6720
            quiz_title,
6721
            username,
6722
            lastname,
6723
            firstname,
6724
            time,
6725
            question_id,
6726
            question,
6727
            answer,
6728
            */
6729
        }
6730
6731
        return $data;
6732
    }
6733
6734
    /**
6735
     * @param User                $user
6736
     * @param string              $tool
6737
     * @param Course              $course
6738
     * @param sessionEntity |null $session Optional
6739
     *
6740
     * @throws \Doctrine\ORM\NonUniqueResultException
6741
     *
6742
     * @return \Chamilo\CourseBundle\Entity\CStudentPublication|null
6743
     */
6744
    public static function getLastStudentPublication(
6745
        User $user,
6746
        $tool,
6747
        Course $course,
6748
        SessionEntity $session = null
6749
    ) {
6750
        return Database::getManager()
6751
            ->createQuery("
6752
                SELECT csp
6753
                FROM ChamiloCourseBundle:CStudentPublication csp
6754
                INNER JOIN ChamiloCourseBundle:CItemProperty cip
6755
                    WITH (
6756
                        csp.iid = cip.ref AND
6757
                        csp.session = cip.session AND
6758
                        csp.cId = cip.course AND
6759
                        csp.userId = cip.lasteditUserId
6760
                    )
6761
                WHERE
6762
                    cip.session = :session AND cip.course = :course AND cip.lasteditUserId = :user AND cip.tool = :tool
6763
                ORDER BY csp.iid DESC
6764
            ")
6765
            ->setMaxResults(1)
6766
            ->setParameters([
6767
                'tool' => $tool,
6768
                'session' => $session,
6769
                'course' => $course,
6770
                'user' => $user,
6771
            ])
6772
            ->getOneOrNullResult();
6773
    }
6774
6775
    /**
6776
     * Get the HTML code for show a block with the achieved user skill on course/session.
6777
     *
6778
     * @param int  $userId
6779
     * @param int  $courseId
6780
     * @param int  $sessionId
6781
     * @param bool $forceView forces the view of the skills, not checking for deeper access
6782
     *
6783
     * @return string
6784
     */
6785
    public static function displayUserSkills($userId, $courseId = 0, $sessionId = 0, $forceView = false)
6786
    {
6787
        if (Skill::isAllowed($userId, false) === false && $forceView == false) {
6788
            return '';
6789
        }
6790
        $skillManager = new Skill();
6791
        $html = $skillManager->getUserSkillsTable($userId, $courseId, $sessionId)['table'];
6792
6793
        return $html;
6794
    }
6795
6796
    /**
6797
     * @param int $userId
6798
     * @param int $courseId
6799
     * @param int $sessionId
6800
     *
6801
     * @return array
6802
     */
6803
    public static function getCalculateTime($userId, $courseId, $sessionId)
6804
    {
6805
        $userId = (int) $userId;
6806
        $courseId = (int) $courseId;
6807
        $sessionId = (int) $sessionId;
6808
6809
        if (empty($userId) || empty($courseId)) {
6810
            return [];
6811
        }
6812
6813
        $lpTime = [];
6814
        $sql = "SELECT MIN(date_reg) min, MAX(date_reg) max
6815
                FROM track_e_access_complete
6816
                WHERE
6817
                    user_id = $userId AND
6818
                    c_id = $courseId AND
6819
                    session_id = $sessionId AND                    
6820
                    login_as = 0
6821
                ORDER BY date_reg ASC
6822
                LIMIT 1";
6823
        $rs = Database::query($sql);
6824
6825
        $firstConnection = '';
6826
        $lastConnection = '';
6827
        if (Database::num_rows($rs) > 0) {
6828
            $value = Database::fetch_array($rs);
6829
            $firstConnection = $value['min'];
6830
            $lastConnection = $value['max'];
6831
        }
6832
6833
        $sql = "SELECT * FROM track_e_access_complete 
6834
                WHERE
6835
                    user_id = $userId AND
6836
                    c_id = $courseId AND                      
6837
                    session_id = $sessionId AND      
6838
                    login_as = 0";
6839
        $res = Database::query($sql);
6840
        $reg = [];
6841
        while ($row = Database::fetch_assoc($res)) {
6842
            $reg[$row['id']] = $row;
6843
            $reg[$row['id']]['date_reg'] = strtotime($row['date_reg']);
6844
        }
6845
6846
        $sessions = [];
6847
        foreach ($reg as $key => $value) {
6848
            $sessions[$value['current_id']][$value['tool']][] = $value;
6849
        }
6850
6851
        $quizTime = 0;
6852
        $result = [];
6853
        $totalTime = 0;
6854
6855
        foreach ($sessions as $listPerTool) {
6856
            $min = 0;
6857
            $max = 0;
6858
            $sessionDiff = 0;
6859
            foreach ($listPerTool as $tool => $results) {
6860
                $beforeItem = [];
6861
                foreach ($results as $item) {
6862
                    if (empty($beforeItem)) {
6863
                        $beforeItem = $item;
6864
                        continue;
6865
                    }
6866
6867
                    $partialTime = $item['date_reg'] - $beforeItem['date_reg'];
6868
6869
                    if ($item['date_reg'] > $max) {
6870
                        $max = $item['date_reg'];
6871
                    }
6872
6873
                    if (empty($min)) {
6874
                        $min = $item['date_reg'];
6875
                    }
6876
6877
                    if ($item['date_reg'] < $min) {
6878
                        $min = $item['date_reg'];
6879
                    }
6880
6881
                    switch ($tool) {
6882
                        case TOOL_AGENDA:
6883
                        case TOOL_FORUM:
6884
                        case TOOL_ANNOUNCEMENT:
6885
                        case TOOL_COURSE_DESCRIPTION:
6886
                        case TOOL_SURVEY:
6887
                        case TOOL_NOTEBOOK:
6888
                        case TOOL_GRADEBOOK:
6889
                        case TOOL_DROPBOX:
6890
                        case 'Reports':
6891
                        case 'Videoconference':
6892
                        case TOOL_LINK:
6893
                        case TOOL_CHAT:
6894
                        case 'course-main':
6895
                            if (!isset($result[$tool])) {
6896
                                $result[$tool] = 0;
6897
                            }
6898
                            $result[$tool] += $partialTime;
6899
                            break;
6900
                        case TOOL_LEARNPATH:
6901
                            if ($item['tool_id'] != $beforeItem['tool_id']) {
6902
                                continue;
6903
                            }
6904
                            if (!isset($lpTime[$item['tool_id']])) {
6905
                                $lpTime[$item['tool_id']] = 0;
6906
                            }
6907
                            $lpTime[$item['tool_id']] += $partialTime;
6908
                            if ($item['tool_id'] == 51) {
6909
                                //$counter++;
6910
                                //var_dump($beforeItem, $item);
6911
                                /*var_dump(
6912
                                    api_get_utc_datetime($item['date_reg']),
6913
                                    api_get_utc_datetime($beforeItem['date_reg'])
6914
                                );*/
6915
                                /*var_dump(
6916
                                    $counter.'-'.$beforeItem['id'].'-'.$item['id'].'-'.$partialTime.'-'.api_time_to_hms($lpTime[$item['tool_id']])
6917
                                );*/
6918
                            }
6919
                            break;
6920
                        case TOOL_QUIZ:
6921
                            if (!isset($lpTime[$item['action_details']])) {
6922
                                $lpTime[$item['action_details']] = 0;
6923
                            }
6924
                            if ($beforeItem['action'] == 'learnpath_id') {
6925
                                $lpTime[$item['action_details']] += $partialTime;
6926
                            } else {
6927
                                $quizTime += $partialTime;
6928
                            }
6929
                            break;
6930
                    }
6931
                    $beforeItem = $item;
6932
                }
6933
            }
6934
6935
            $sessionDiff += $max - $min;
6936
            if ($sessionDiff > 0) {
6937
                $totalTime += $sessionDiff;
6938
            }
6939
        }
6940
6941
        $totalLp = 0;
6942
        foreach ($lpTime as $value) {
6943
            $totalLp += $value;
6944
        }
6945
6946
        $result[TOOL_LEARNPATH] = $lpTime;
6947
        $result[TOOL_QUIZ] = $quizTime;
6948
        $result['total_learnpath'] = $totalLp;
6949
        $result['total_time'] = $totalTime;
6950
        $result['number_connections'] = count($sessions);
6951
        $result['first'] = $firstConnection;
6952
        $result['last'] = $lastConnection;
6953
6954
        return $result;
6955
    }
6956
6957
    /**
6958
     * Gets the IP of a given user, using the last login before the given date.
6959
     *
6960
     * @param int User ID
6961
     * @param string Datetime
6962
     * @param bool Whether to return the IP as a link or just as an IP
6963
     * @param string If defined and return_as_link if true, will be used as the text to be shown as the link
6964
     *
6965
     * @return string IP address (or false on error)
6966
     * @assert (0,0) === false
6967
     */
6968
    public static function get_ip_from_user_event(
6969
        $user_id,
6970
        $event_date,
6971
        $return_as_link = false,
6972
        $body_replace = null
6973
    ) {
6974
        if (empty($user_id) || empty($event_date)) {
6975
            return false;
6976
        }
6977
        $user_id = intval($user_id);
6978
        $event_date = Database::escape_string($event_date);
6979
        $table_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
6980
        $sql_ip = "SELECT login_date, user_ip 
6981
                   FROM $table_login
6982
                   WHERE login_user_id = $user_id AND login_date < '$event_date'
6983
                   ORDER BY login_date DESC LIMIT 1";
6984
        $ip = '';
6985
        $res_ip = Database::query($sql_ip);
6986
        if ($res_ip !== false && Database::num_rows($res_ip) > 0) {
6987
            $row_ip = Database::fetch_row($res_ip);
6988
            if ($return_as_link) {
6989
                $ip = Display::url(
6990
                    (empty($body_replace) ? $row_ip[1] : $body_replace),
6991
                    'http://www.whatsmyip.org/ip-geo-location/?ip='.$row_ip[1],
6992
                    ['title' => get_lang('TraceIP'), 'target' => '_blank']
6993
                );
6994
            } else {
6995
                $ip = $row_ip[1];
6996
            }
6997
        }
6998
6999
        return $ip;
7000
    }
7001
7002
    /**
7003
     * @param int   $userId
7004
     * @param array $courseInfo
7005
     * @param int   $sessionId
7006
     *
7007
     * @return array
7008
     */
7009
    public static function getToolInformation(
7010
        $userId,
7011
        $courseInfo,
7012
        $sessionId = 0
7013
    ) {
7014
        $csvContent = [];
7015
        $courseToolInformation = '';
7016
        $headerTool = [
7017
            [get_lang('Title')],
7018
            [get_lang('CreatedAt')],
7019
            [get_lang('UpdatedAt')],
7020
        ];
7021
7022
        $headerListForCSV = [];
7023
        foreach ($headerTool as $item) {
7024
            $headerListForCSV[] = $item[0];
7025
        }
7026
7027
        $courseForumInformationArray = getForumCreatedByUser(
7028
            $userId,
7029
            $courseInfo['real_id'],
7030
            $sessionId
7031
        );
7032
7033
        if (!empty($courseForumInformationArray)) {
7034
            $csvContent[] = [];
7035
            $csvContent[] = [get_lang('Forums')];
7036
            $csvContent[] = $headerListForCSV;
7037
            foreach ($courseForumInformationArray as $row) {
7038
                $csvContent[] = $row;
7039
            }
7040
7041
            $courseToolInformation .= Display::page_subheader2(
7042
                get_lang('Forums')
7043
            );
7044
            $courseToolInformation .= Display::return_sortable_table(
7045
                $headerTool,
7046
                $courseForumInformationArray
7047
            );
7048
        }
7049
7050
        $courseWorkInformationArray = getWorkCreatedByUser(
7051
            $userId,
7052
            $courseInfo['real_id'],
7053
            $sessionId
7054
        );
7055
7056
        if (!empty($courseWorkInformationArray)) {
7057
            $csvContent[] = null;
7058
            $csvContent[] = [get_lang('Works')];
7059
            $csvContent[] = $headerListForCSV;
7060
7061
            foreach ($courseWorkInformationArray as $row) {
7062
                $csvContent[] = $row;
7063
            }
7064
            $csvContent[] = null;
7065
7066
            $courseToolInformation .= Display::page_subheader2(
7067
                get_lang('Works')
7068
            );
7069
            $courseToolInformation .= Display::return_sortable_table(
7070
                $headerTool,
7071
                $courseWorkInformationArray
7072
            );
7073
        }
7074
7075
        $courseToolInformationTotal = null;
7076
        if (!empty($courseToolInformation)) {
7077
            $sessionTitle = null;
7078
            if (!empty($sessionId)) {
7079
                $sessionTitle = ' ('.api_get_session_name($sessionId).')';
7080
            }
7081
7082
            $courseToolInformationTotal .= Display::page_subheader(
7083
                $courseInfo['title'].$sessionTitle
7084
            );
7085
            $courseToolInformationTotal .= $courseToolInformation;
7086
        }
7087
7088
        return [
7089
            'array' => $csvContent,
7090
            'html' => $courseToolInformationTotal,
7091
        ];
7092
    }
7093
7094
    /**
7095
     * @param int $sessionId
7096
     *
7097
     * @return bool
7098
     */
7099
    public static function isAllowToTrack($sessionId)
7100
    {
7101
        $allow =
7102
            api_is_platform_admin(true, true) ||
7103
            SessionManager::user_is_general_coach(api_get_user_id(), $sessionId) ||
7104
            api_is_allowed_to_create_course() ||
7105
            api_is_course_tutor() ||
7106
            api_is_course_admin();
7107
7108
        return $allow;
7109
    }
7110
7111
    public function getCoursesAndSessions($userId)
7112
    {
7113
        $userId = (int) $userId;
7114
7115
        // Get the list of sessions where the user is subscribed as student
7116
        $sql = 'SELECT session_id, c_id
7117
        FROM '.Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER).'
7118
        WHERE user_id='.$userId;
7119
        $rs = Database::query($sql);
7120
        $tmp_sessions = [];
7121
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
7122
            $tmp_sessions[] = $row['session_id'];
7123
            if ($drh_can_access_all_courses) {
7124
                if (in_array($row['session_id'], $tmp_sessions)) {
7125
                    $courses_in_session[$row['session_id']][] = $row['c_id'];
7126
                }
7127
            } else {
7128
                if (isset($courses_in_session_by_coach[$row['session_id']])) {
7129
                    if (in_array($row['session_id'], $tmp_sessions)) {
7130
                        $courses_in_session[$row['session_id']][] = $row['c_id'];
7131
                    }
7132
                }
7133
            }
7134
        }
7135
    }
7136
}
7137
7138
/**
7139
 * @todo move into a proper file
7140
 *
7141
 * @package chamilo.tracking
7142
 */
7143
class TrackingCourseLog
7144
{
7145
    /**
7146
     * @return mixed
7147
     */
7148
    public static function count_item_resources()
7149
    {
7150
        $session_id = api_get_session_id();
7151
        $course_id = api_get_course_int_id();
7152
7153
        $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
7154
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
7155
7156
        $sql = "SELECT count(tool) AS total_number_of_items
7157
                FROM $table_item_property track_resource, $table_user user
7158
                WHERE
7159
                    track_resource.c_id = $course_id AND
7160
                    track_resource.insert_user_id = user.user_id AND
7161
                    session_id ".(empty($session_id) ? ' IS NULL ' : " = $session_id ");
7162
7163
        if (isset($_GET['keyword'])) {
7164
            $keyword = Database::escape_string(trim($_GET['keyword']));
7165
            $sql .= " AND (
7166
                        user.username LIKE '%".$keyword."%' OR
7167
                        lastedit_type LIKE '%".$keyword."%' OR
7168
                        tool LIKE '%".$keyword."%'
7169
                    )";
7170
        }
7171
7172
        $sql .= " AND tool IN (
7173
                    'document',
7174
                    'learnpath',
7175
                    'quiz',
7176
                    'glossary',
7177
                    'link',
7178
                    'course_description',
7179
                    'announcement',
7180
                    'thematic',
7181
                    'thematic_advance',
7182
                    'thematic_plan'
7183
                )";
7184
        $res = Database::query($sql);
7185
        $obj = Database::fetch_object($res);
7186
7187
        return $obj->total_number_of_items;
7188
    }
7189
7190
    /**
7191
     * @param $from
7192
     * @param $number_of_items
7193
     * @param $column
7194
     * @param $direction
7195
     *
7196
     * @return array
7197
     */
7198
    public static function get_item_resources_data($from, $number_of_items, $column, $direction)
7199
    {
7200
        $session_id = api_get_session_id();
7201
        $course_id = api_get_course_int_id();
7202
7203
        $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
7204
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
7205
        $table_session = Database::get_main_table(TABLE_MAIN_SESSION);
7206
        $session_id = intval($session_id);
7207
7208
        $sql = "SELECT
7209
                    tool as col0,
7210
                    lastedit_type as col1,
7211
                    ref as ref,
7212
                    user.username as col3,
7213
                    insert_date as col6,
7214
                    visibility as col7,
7215
                    user.user_id as user_id
7216
                FROM $table_item_property track_resource, $table_user user
7217
                WHERE
7218
                  track_resource.c_id = $course_id AND
7219
                  track_resource.insert_user_id = user.user_id AND
7220
                  session_id ".(empty($session_id) ? ' IS NULL ' : " = $session_id ");
7221
7222
        if (isset($_GET['keyword'])) {
7223
            $keyword = Database::escape_string(trim($_GET['keyword']));
7224
            $sql .= " AND (
7225
                        user.username LIKE '%".$keyword."%' OR
7226
                        lastedit_type LIKE '%".$keyword."%' OR
7227
                        tool LIKE '%".$keyword."%'
7228
                     ) ";
7229
        }
7230
7231
        $sql .= " AND tool IN (
7232
                    'document',
7233
                    'learnpath',
7234
                    'quiz',
7235
                    'glossary',
7236
                    'link',
7237
                    'course_description',
7238
                    'announcement',
7239
                    'thematic',
7240
                    'thematic_advance',
7241
                    'thematic_plan'
7242
                )";
7243
7244
        if ($column == 0) {
7245
            $column = '0';
7246
        }
7247
        if ($column != '' && $direction != '') {
7248
            if ($column != 2 && $column != 4) {
7249
                $sql .= " ORDER BY col$column $direction";
7250
            }
7251
        } else {
7252
            $sql .= " ORDER BY col6 DESC ";
7253
        }
7254
7255
        $from = intval($from);
7256
        if ($from) {
7257
            $number_of_items = intval($number_of_items);
7258
            $sql .= " LIMIT $from, $number_of_items ";
7259
        }
7260
7261
        $res = Database::query($sql);
7262
        $resources = [];
7263
        $thematic_tools = ['thematic', 'thematic_advance', 'thematic_plan'];
7264
        while ($row = Database::fetch_array($res)) {
7265
            $ref = $row['ref'];
7266
            $table_name = self::get_tool_name_table($row['col0']);
7267
            $table_tool = Database::get_course_table($table_name['table_name']);
7268
7269
            $id = $table_name['id_tool'];
7270
            $recorset = false;
7271
7272
            if (in_array($row['col0'], ['thematic_plan', 'thematic_advance'])) {
7273
                $tbl_thematic = Database::get_course_table(TABLE_THEMATIC);
7274
                $sql = "SELECT thematic_id FROM $table_tool
7275
                        WHERE c_id = $course_id AND id = $ref";
7276
                $rs_thematic = Database::query($sql);
7277
                if (Database::num_rows($rs_thematic)) {
7278
                    $row_thematic = Database::fetch_array($rs_thematic);
7279
                    $thematic_id = $row_thematic['thematic_id'];
7280
7281
                    $sql = "SELECT session.id, session.name, user.username
7282
                            FROM $tbl_thematic t, $table_session session, $table_user user
7283
                            WHERE
7284
                              t.c_id = $course_id AND
7285
                              t.session_id = session.id AND
7286
                              session.id_coach = user.user_id AND
7287
                              t.id = $thematic_id";
7288
                    $recorset = Database::query($sql);
7289
                }
7290
            } else {
7291
                $sql = "SELECT session.id, session.name, user.username
7292
                          FROM $table_tool tool, $table_session session, $table_user user
7293
                          WHERE
7294
                              tool.c_id = $course_id AND
7295
                              tool.session_id = session.id AND
7296
                              session.id_coach = user.user_id AND
7297
                              tool.$id = $ref";
7298
                $recorset = Database::query($sql);
7299
            }
7300
7301
            if (!empty($recorset)) {
7302
                $obj = Database::fetch_object($recorset);
7303
7304
                $name_session = '';
7305
                $coach_name = '';
7306
                if (!empty($obj)) {
7307
                    $name_session = $obj->name;
7308
                    $coach_name = $obj->username;
7309
                }
7310
7311
                $url_tool = api_get_path(WEB_CODE_PATH).$table_name['link_tool'];
7312
                $row[0] = '';
7313
                if ($row['col6'] != 2) {
7314
                    if (in_array($row['col0'], $thematic_tools)) {
7315
                        $exp_thematic_tool = explode('_', $row['col0']);
7316
                        $thematic_tool_title = '';
7317
                        if (is_array($exp_thematic_tool)) {
7318
                            foreach ($exp_thematic_tool as $exp) {
7319
                                $thematic_tool_title .= api_ucfirst($exp);
7320
                            }
7321
                        } else {
7322
                            $thematic_tool_title = api_ucfirst($row['col0']);
7323
                        }
7324
7325
                        $row[0] = '<a href="'.$url_tool.'?'.api_get_cidreq().'&action=thematic_details">'.get_lang($thematic_tool_title).'</a>';
7326
                    } else {
7327
                        $row[0] = '<a href="'.$url_tool.'?'.api_get_cidreq().'">'.get_lang('Tool'.api_ucfirst($row['col0'])).'</a>';
7328
                    }
7329
                } else {
7330
                    $row[0] = api_ucfirst($row['col0']);
7331
                }
7332
                $row[1] = get_lang($row[1]);
7333
                $row[6] = api_convert_and_format_date($row['col6'], null, date_default_timezone_get());
7334
                $row[5] = '';
7335
                //@todo Improve this code please
7336
                switch ($table_name['table_name']) {
7337
                    case 'document':
7338
                        $sql = "SELECT tool.title as title FROM $table_tool tool
7339
                                WHERE c_id = $course_id AND id = $ref";
7340
                        $rs_document = Database::query($sql);
7341
                        $obj_document = Database::fetch_object($rs_document);
7342
                        if ($obj_document) {
7343
                            $row[5] = $obj_document->title;
7344
                        }
7345
                        break;
7346
                    case 'announcement':
7347
                        $sql = "SELECT title FROM $table_tool
7348
                                WHERE c_id = $course_id AND id = $ref";
7349
                        $rs_document = Database::query($sql);
7350
                        $obj_document = Database::fetch_object($rs_document);
7351
                        if ($obj_document) {
7352
                            $row[5] = $obj_document->title;
7353
                        }
7354
                        break;
7355
                    case 'glossary':
7356
                        $sql = "SELECT name FROM $table_tool
7357
                                WHERE c_id = $course_id AND glossary_id = $ref";
7358
                        $rs_document = Database::query($sql);
7359
                        $obj_document = Database::fetch_object($rs_document);
7360
                        if ($obj_document) {
7361
                            $row[5] = $obj_document->name;
7362
                        }
7363
                        break;
7364
                    case 'lp':
7365
                        $sql = "SELECT name
7366
                                FROM $table_tool WHERE c_id = $course_id AND id = $ref";
7367
                        $rs_document = Database::query($sql);
7368
                        $obj_document = Database::fetch_object($rs_document);
7369
                        $row[5] = $obj_document->name;
7370
                        break;
7371
                    case 'quiz':
7372
                        $sql = "SELECT title FROM $table_tool
7373
                                WHERE c_id = $course_id AND id = $ref";
7374
                        $rs_document = Database::query($sql);
7375
                        $obj_document = Database::fetch_object($rs_document);
7376
                        if ($obj_document) {
7377
                            $row[5] = $obj_document->title;
7378
                        }
7379
                        break;
7380
                    case 'course_description':
7381
                        $sql = "SELECT title FROM $table_tool
7382
                                WHERE c_id = $course_id AND id = $ref";
7383
                        $rs_document = Database::query($sql);
7384
                        $obj_document = Database::fetch_object($rs_document);
7385
                        if ($obj_document) {
7386
                            $row[5] = $obj_document->title;
7387
                        }
7388
                        break;
7389
                    case 'thematic':
7390
                        $rs = Database::query("SELECT title FROM $table_tool WHERE c_id = $course_id AND id = $ref");
7391
                        if (Database::num_rows($rs) > 0) {
7392
                            $obj = Database::fetch_object($rs);
7393
                            if ($obj) {
7394
                                $row[5] = $obj->title;
7395
                            }
7396
                        }
7397
                        break;
7398
                    case 'thematic_advance':
7399
                        $rs = Database::query("SELECT content FROM $table_tool WHERE c_id = $course_id AND id = $ref");
7400
                        if (Database::num_rows($rs) > 0) {
7401
                            $obj = Database::fetch_object($rs);
7402
                            if ($obj) {
7403
                                $row[5] = $obj->content;
7404
                            }
7405
                        }
7406
                        break;
7407
                    case 'thematic_plan':
7408
                        $rs = Database::query("SELECT title FROM $table_tool WHERE c_id = $course_id AND id = $ref");
7409
                        if (Database::num_rows($rs) > 0) {
7410
                            $obj = Database::fetch_object($rs);
7411
                            if ($obj) {
7412
                                $row[5] = $obj->title;
7413
                            }
7414
                        }
7415
                        break;
7416
                    default:
7417
                        break;
7418
                }
7419
7420
                $row2 = $name_session;
7421
                if (!empty($coach_name)) {
7422
                    $row2 .= '<br />'.get_lang('Coach').': '.$coach_name;
7423
                }
7424
                $row[2] = $row2;
7425
                if (!empty($row['col3'])) {
7426
                    $userInfo = api_get_user_info($row['user_id']);
7427
                    $row['col3'] = Display::url(
7428
                        $row['col3'],
7429
                        $userInfo['profile_url']
7430
                    );
7431
                    $row[3] = $row['col3'];
7432
7433
                    $ip = Tracking::get_ip_from_user_event(
7434
                        $row['user_id'],
7435
                        $row['col6'],
7436
                        true
7437
                    );
7438
                    if (empty($ip)) {
7439
                        $ip = get_lang('Unknown');
7440
                    }
7441
                    $row[4] = $ip;
7442
                }
7443
7444
                $resources[] = $row;
7445
            }
7446
        }
7447
7448
        return $resources;
7449
    }
7450
7451
    /**
7452
     * @param string $tool
7453
     *
7454
     * @return array
7455
     */
7456
    public static function get_tool_name_table($tool)
7457
    {
7458
        switch ($tool) {
7459
            case 'document':
7460
                $table_name = TABLE_DOCUMENT;
7461
                $link_tool = 'document/document.php';
7462
                $id_tool = 'id';
7463
                break;
7464
            case 'learnpath':
7465
                $table_name = TABLE_LP_MAIN;
7466
                $link_tool = 'lp/lp_controller.php';
7467
                $id_tool = 'id';
7468
                break;
7469
            case 'quiz':
7470
                $table_name = TABLE_QUIZ_TEST;
7471
                $link_tool = 'exercise/exercise.php';
7472
                $id_tool = 'id';
7473
                break;
7474
            case 'glossary':
7475
                $table_name = TABLE_GLOSSARY;
7476
                $link_tool = 'glossary/index.php';
7477
                $id_tool = 'glossary_id';
7478
                break;
7479
            case 'link':
7480
                $table_name = TABLE_LINK;
7481
                $link_tool = 'link/link.php';
7482
                $id_tool = 'id';
7483
                break;
7484
            case 'course_description':
7485
                $table_name = TABLE_COURSE_DESCRIPTION;
7486
                $link_tool = 'course_description/';
7487
                $id_tool = 'id';
7488
                break;
7489
            case 'announcement':
7490
                $table_name = TABLE_ANNOUNCEMENT;
7491
                $link_tool = 'announcements/announcements.php';
7492
                $id_tool = 'id';
7493
                break;
7494
            case 'thematic':
7495
                $table_name = TABLE_THEMATIC;
7496
                $link_tool = 'course_progress/index.php';
7497
                $id_tool = 'id';
7498
                break;
7499
            case 'thematic_advance':
7500
                $table_name = TABLE_THEMATIC_ADVANCE;
7501
                $link_tool = 'course_progress/index.php';
7502
                $id_tool = 'id';
7503
                break;
7504
            case 'thematic_plan':
7505
                $table_name = TABLE_THEMATIC_PLAN;
7506
                $link_tool = 'course_progress/index.php';
7507
                $id_tool = 'id';
7508
                break;
7509
            default:
7510
                $table_name = $tool;
7511
            break;
7512
        }
7513
7514
        return [
7515
            'table_name' => $table_name,
7516
            'link_tool' => $link_tool,
7517
            'id_tool' => $id_tool,
7518
        ];
7519
    }
7520
7521
    /**
7522
     * @return string
7523
     */
7524
    public static function display_additional_profile_fields()
7525
    {
7526
        // getting all the extra profile fields that are defined by the platform administrator
7527
        $extra_fields = UserManager::get_extra_fields(0, 50, 5, 'ASC');
7528
7529
        // creating the form
7530
        $return = '<form action="courseLog.php" method="get" name="additional_profile_field_form" id="additional_profile_field_form">';
7531
7532
        // the select field with the additional user profile fields (= this is where we select the field of which we want to see
7533
        // the information the users have entered or selected.
7534
        $return .= '<select class="chzn-select" name="additional_profile_field[]" multiple>';
7535
        $return .= '<option value="-">'.get_lang('SelectFieldToAdd').'</option>';
7536
        $extra_fields_to_show = 0;
7537
        foreach ($extra_fields as $key => $field) {
7538
            // show only extra fields that are visible + and can be filtered, added by J.Montoya
7539
            if ($field[6] == 1 && $field[8] == 1) {
7540
                if (isset($_GET['additional_profile_field']) && $field[0] == $_GET['additional_profile_field']) {
7541
                    $selected = 'selected="selected"';
7542
                } else {
7543
                    $selected = '';
7544
                }
7545
                $extra_fields_to_show++;
7546
                $return .= '<option value="'.$field[0].'" '.$selected.'>'.$field[3].'</option>';
7547
            }
7548
        }
7549
        $return .= '</select>';
7550
7551
        // the form elements for the $_GET parameters (because the form is passed through GET
7552
        foreach ($_GET as $key => $value) {
7553
            if ($key != 'additional_profile_field') {
7554
                $return .= '<input type="hidden" name="'.Security::remove_XSS($key).'" value="'.Security::remove_XSS($value).'" />';
7555
            }
7556
        }
7557
        // the submit button
7558
        $return .= '<button class="save" type="submit">'.get_lang('AddAdditionalProfileField').'</button>';
7559
        $return .= '</form>';
7560
        if ($extra_fields_to_show > 0) {
7561
            return $return;
7562
        } else {
7563
            return '';
7564
        }
7565
    }
7566
7567
    /**
7568
     * This function gets all the information of a certrain ($field_id)
7569
     * additional profile field for a specific list of users is more efficent
7570
     * than get_addtional_profile_information_of_field() function
7571
     * It gets the information of all the users so that it can be displayed
7572
     * in the sortable table or in the csv or xls export.
7573
     *
7574
     * @author    Julio Montoya <[email protected]>
7575
     *
7576
     * @param    int field id
7577
     * @param    array list of user ids
7578
     *
7579
     * @return array
7580
     *
7581
     * @since    Nov 2009
7582
     *
7583
     * @version    1.8.6.2
7584
     */
7585
    public static function getAdditionalProfileInformationOfFieldByUser($field_id, $users)
7586
    {
7587
        // Database table definition
7588
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
7589
        $table_user_field_values = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
7590
        $extraField = Database::get_main_table(TABLE_EXTRA_FIELD);
7591
        $result_extra_field = UserManager::get_extra_field_information($field_id);
7592
        $return = [];
7593
        if (!empty($users)) {
7594
            if ($result_extra_field['field_type'] == UserManager::USER_FIELD_TYPE_TAG) {
7595
                foreach ($users as $user_id) {
7596
                    $user_result = UserManager::get_user_tags($user_id, $field_id);
7597
                    $tag_list = [];
7598
                    foreach ($user_result as $item) {
7599
                        $tag_list[] = $item['tag'];
7600
                    }
7601
                    $return[$user_id][] = implode(', ', $tag_list);
7602
                }
7603
            } else {
7604
                $new_user_array = [];
7605
                foreach ($users as $user_id) {
7606
                    $new_user_array[] = "'".$user_id."'";
7607
                }
7608
                $users = implode(',', $new_user_array);
7609
                $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
7610
                // Selecting only the necessary information NOT ALL the user list
7611
                $sql = "SELECT user.user_id, v.value
7612
                        FROM $table_user user
7613
                        INNER JOIN $table_user_field_values v
7614
                        ON (user.user_id = v.item_id)
7615
                        INNER JOIN $extraField f
7616
                        ON (f.id = v.field_id)
7617
                        WHERE
7618
                            f.extra_field_type = $extraFieldType AND
7619
                            v.field_id=".intval($field_id)." AND
7620
                            user.user_id IN ($users)";
7621
7622
                $result = Database::query($sql);
7623
                while ($row = Database::fetch_array($result)) {
7624
                    // get option value for field type double select by id
7625
                    if (!empty($row['value'])) {
7626
                        if ($result_extra_field['field_type'] ==
7627
                            ExtraField::FIELD_TYPE_DOUBLE_SELECT
7628
                        ) {
7629
                            $id_double_select = explode(';', $row['value']);
7630
                            if (is_array($id_double_select)) {
7631
                                $value1 = $result_extra_field['options'][$id_double_select[0]]['option_value'];
7632
                                $value2 = $result_extra_field['options'][$id_double_select[1]]['option_value'];
7633
                                $row['value'] = ($value1.';'.$value2);
7634
                            }
7635
                        }
7636
7637
                        if ($result_extra_field['field_type'] == ExtraField::FIELD_TYPE_SELECT_WITH_TEXT_FIELD) {
7638
                            $parsedValue = explode('::', $row['value']);
7639
7640
                            if ($parsedValue) {
7641
                                $value1 = $result_extra_field['options'][$parsedValue[0]]['display_text'];
7642
                                $value2 = $parsedValue[1];
7643
7644
                                $row['value'] = "$value1: $value2";
7645
                            }
7646
                        }
7647
7648
                        if ($result_extra_field['field_type'] == ExtraField::FIELD_TYPE_TRIPLE_SELECT) {
7649
                            list($level1, $level2, $level3) = explode(';', $row['value']);
7650
7651
                            $row['value'] = $result_extra_field['options'][$level1]['display_text'].' / ';
7652
                            $row['value'] .= $result_extra_field['options'][$level2]['display_text'].' / ';
7653
                            $row['value'] .= $result_extra_field['options'][$level3]['display_text'];
7654
                        }
7655
                    }
7656
                    // get other value from extra field
7657
                    $return[$row['user_id']][] = $row['value'];
7658
                }
7659
            }
7660
        }
7661
7662
        return $return;
7663
    }
7664
7665
    /**
7666
     * count the number of students in this course (used for SortableTable)
7667
     * Deprecated.
7668
     */
7669
    public function count_student_in_course()
7670
    {
7671
        global $nbStudents;
7672
7673
        return $nbStudents;
7674
    }
7675
7676
    public function sort_users($a, $b)
7677
    {
7678
        $tracking = Session::read('tracking_column');
7679
7680
        return strcmp(
7681
            trim(api_strtolower($a[$tracking])),
7682
            trim(api_strtolower($b[$tracking]))
7683
        );
7684
    }
7685
7686
    public function sort_users_desc($a, $b)
7687
    {
7688
        $tracking = Session::read('tracking_column');
7689
7690
        return strcmp(
7691
            trim(api_strtolower($b[$tracking])),
7692
            trim(api_strtolower($a[$tracking]))
7693
        );
7694
    }
7695
7696
    /**
7697
     * Get number of users for sortable with pagination.
7698
     *
7699
     * @return int
7700
     */
7701
    public static function get_number_of_users()
7702
    {
7703
        global $user_ids;
7704
7705
        return count($user_ids);
7706
    }
7707
7708
    /**
7709
     * Get data for users list in sortable with pagination.
7710
     *
7711
     * @param $from
7712
     * @param $number_of_items
7713
     * @param $column
7714
     * @param $direction
7715
     * @param $includeInvitedUsers boolean Whether include the invited users
7716
     *
7717
     * @return array
7718
     */
7719
    public static function get_user_data(
7720
        $from,
7721
        $number_of_items,
7722
        $column,
7723
        $direction,
7724
        $includeInvitedUsers = false
7725
    ) {
7726
        global $user_ids, $course_code, $export_csv, $session_id;
7727
7728
        $csv_content = [];
7729
        $course_code = Database::escape_string($course_code);
7730
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
7731
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
7732
        $access_url_id = api_get_current_access_url_id();
7733
7734
        // get all users data from a course for sortable with limit
7735
        if (is_array($user_ids)) {
7736
            $user_ids = array_map('intval', $user_ids);
7737
            $condition_user = " WHERE user.user_id IN (".implode(',', $user_ids).") ";
7738
        } else {
7739
            $user_ids = intval($user_ids);
7740
            $condition_user = " WHERE user.user_id = $user_ids ";
7741
        }
7742
7743
        if (!empty($_GET['user_keyword'])) {
7744
            $keyword = trim(Database::escape_string($_GET['user_keyword']));
7745
            $condition_user .= " AND (
7746
                user.firstname LIKE '%".$keyword."%' OR
7747
                user.lastname LIKE '%".$keyword."%'  OR
7748
                user.username LIKE '%".$keyword."%'  OR
7749
                user.email LIKE '%".$keyword."%'
7750
             ) ";
7751
        }
7752
7753
        $url_table = null;
7754
        $url_condition = null;
7755
        if (api_is_multiple_url_enabled()) {
7756
            $url_table = ", ".$tbl_url_rel_user." as url_users";
7757
            $url_condition = " AND user.user_id = url_users.user_id AND access_url_id='$access_url_id'";
7758
        }
7759
7760
        $invitedUsersCondition = '';
7761
        if (!$includeInvitedUsers) {
7762
            $invitedUsersCondition = " AND user.status != ".INVITEE;
7763
        }
7764
7765
        $sql = "SELECT  user.user_id as user_id,
7766
                    user.official_code  as col0,
7767
                    user.lastname       as col1,
7768
                    user.firstname      as col2,
7769
                    user.username       as col3
7770
                FROM $tbl_user as user $url_table
7771
                $condition_user $url_condition $invitedUsersCondition";
7772
7773
        if (!in_array($direction, ['ASC', 'DESC'])) {
7774
            $direction = 'ASC';
7775
        }
7776
7777
        $column = intval($column);
7778
        $from = intval($from);
7779
        $number_of_items = intval($number_of_items);
7780
7781
        $sql .= " ORDER BY col$column $direction ";
7782
        $sql .= " LIMIT $from,$number_of_items";
7783
7784
        $res = Database::query($sql);
7785
        $users = [];
7786
7787
        $course_info = api_get_course_info($course_code);
7788
        $total_surveys = 0;
7789
        $total_exercises = ExerciseLib::get_all_exercises(
7790
            $course_info,
7791
            $session_id,
7792
            false,
7793
            null,
7794
            false,
7795
            3
7796
        );
7797
7798
        if (empty($session_id)) {
7799
            $survey_user_list = [];
7800
            $survey_list = SurveyManager::get_surveys($course_code, $session_id);
7801
7802
            $total_surveys = count($survey_list);
7803
            foreach ($survey_list as $survey) {
7804
                $user_list = SurveyManager::get_people_who_filled_survey(
7805
                    $survey['survey_id'],
7806
                    false,
7807
                    $course_info['real_id']
7808
                );
7809
7810
                foreach ($user_list as $user_id) {
7811
                    isset($survey_user_list[$user_id]) ? $survey_user_list[$user_id]++ : $survey_user_list[$user_id] = 1;
7812
                }
7813
            }
7814
        }
7815
7816
        $courseInfo = api_get_course_info($course_code);
7817
        $courseId = $courseInfo['real_id'];
7818
7819
        $urlBase = api_get_path(WEB_CODE_PATH).'mySpace/myStudents.php?details=true&cidReq='.$course_code.
7820
            '&course='.$course_code.'&origin=tracking_course&id_session='.$session_id;
7821
7822
        $sortByFirstName = api_sort_by_first_name();
7823
        while ($user = Database::fetch_array($res, 'ASSOC')) {
7824
            $user['official_code'] = $user['col0'];
7825
            $user['username'] = $user['col3'];
7826
7827
            $user['time'] = api_time_to_hms(
7828
                Tracking::get_time_spent_on_the_course(
7829
                    $user['user_id'],
7830
                    $courseId,
7831
                    $session_id
7832
                )
7833
            );
7834
7835
            $avg_student_score = Tracking::get_avg_student_score(
7836
                $user['user_id'],
7837
                $course_code,
7838
                [],
7839
                $session_id
7840
            );
7841
7842
            $avg_student_progress = Tracking::get_avg_student_progress(
7843
                $user['user_id'],
7844
                $course_code,
7845
                [],
7846
                $session_id
7847
            );
7848
7849
            if (empty($avg_student_progress)) {
7850
                $avg_student_progress = 0;
7851
            }
7852
            $user['average_progress'] = $avg_student_progress.'%';
7853
7854
            $total_user_exercise = Tracking::get_exercise_student_progress(
7855
                $total_exercises,
7856
                $user['user_id'],
7857
                $courseId,
7858
                $session_id
7859
            );
7860
7861
            $user['exercise_progress'] = $total_user_exercise;
7862
7863
            $total_user_exercise = Tracking::get_exercise_student_average_best_attempt(
7864
                $total_exercises,
7865
                $user['user_id'],
7866
                $courseId,
7867
                $session_id
7868
            );
7869
7870
            $user['exercise_average_best_attempt'] = $total_user_exercise;
7871
7872
            if (is_numeric($avg_student_score)) {
7873
                $user['student_score'] = $avg_student_score.'%';
7874
            } else {
7875
                $user['student_score'] = $avg_student_score;
7876
            }
7877
7878
            $user['count_assignments'] = Tracking::count_student_assignments(
7879
                $user['user_id'],
7880
                $course_code,
7881
                $session_id
7882
            );
7883
            $user['count_messages'] = Tracking::count_student_messages(
7884
                $user['user_id'],
7885
                $course_code,
7886
                $session_id
7887
            );
7888
            $user['first_connection'] = Tracking::get_first_connection_date_on_the_course(
7889
                $user['user_id'],
7890
                $courseId,
7891
                $session_id
7892
            );
7893
            $user['last_connection'] = Tracking::get_last_connection_date_on_the_course(
7894
                $user['user_id'],
7895
                $courseInfo,
7896
                $session_id,
7897
                $export_csv === false
7898
            );
7899
7900
            if (empty($session_id)) {
7901
                $user['survey'] = (isset($survey_user_list[$user['user_id']]) ? $survey_user_list[$user['user_id']] : 0).' / '.$total_surveys;
7902
            }
7903
7904
            $url = $urlBase.'&student='.$user['user_id'];
7905
7906
            $user['link'] = '<center><a href="'.$url.'">
7907
                            '.Display::return_icon('2rightarrow.png', get_lang('Details')).'
7908
                             </a></center>';
7909
7910
            // store columns in array $users
7911
            $user_row = [];
7912
            $user_row['official_code'] = $user['official_code']; //0
7913
            if ($sortByFirstName) {
7914
                $user_row['firstname'] = $user['col2'];
7915
                $user_row['lastname'] = $user['col1'];
7916
            } else {
7917
                $user_row['lastname'] = $user['col1'];
7918
                $user_row['firstname'] = $user['col2'];
7919
            }
7920
            $user_row['username'] = $user['username'];
7921
            $user_row['time'] = $user['time'];
7922
            $user_row['average_progress'] = $user['average_progress'];
7923
            $user_row['exercise_progress'] = $user['exercise_progress'];
7924
            $user_row['exercise_average_best_attempt'] = $user['exercise_average_best_attempt'];
7925
            $user_row['student_score'] = $user['student_score'];
7926
            $user_row['count_assignments'] = $user['count_assignments'];
7927
            $user_row['count_messages'] = $user['count_messages'];
7928
7929
            $userGroupManager = new UserGroup();
7930
            $user_row['classes'] = $userGroupManager->getLabelsFromNameList($user['user_id'], UserGroup::NORMAL_CLASS);
7931
7932
            if (empty($session_id)) {
7933
                $user_row['survey'] = $user['survey'];
7934
            }
7935
7936
            $user_row['first_connection'] = $user['first_connection'];
7937
            $user_row['last_connection'] = $user['last_connection'];
7938
7939
            // we need to display an additional profile field
7940
            if (isset($_GET['additional_profile_field'])) {
7941
                $data = Session::read('additional_user_profile_info');
7942
                $extraFieldInfo = Session::read('extra_field_info');
7943
                foreach ($_GET['additional_profile_field'] as $fieldId) {
7944
                    if (isset($data[$fieldId]) && isset($data[$fieldId][$user['user_id']])) {
7945
                        if (is_array($data[$fieldId][$user['user_id']])) {
7946
                            $user_row[$extraFieldInfo[$fieldId]['variable']] = implode(
7947
                                ', ',
7948
                                $data[$fieldId][$user['user_id']]
7949
                            );
7950
                        } else {
7951
                            $user_row[$extraFieldInfo[$fieldId]['variable']] = $data[$fieldId][$user['user_id']];
7952
                        }
7953
                    } else {
7954
                        $user_row[$extraFieldInfo[$fieldId]['variable']] = '';
7955
                    }
7956
                }
7957
            }
7958
7959
            $user_row['link'] = $user['link'];
7960
7961
            if ($export_csv) {
7962
                if (empty($session_id)) {
7963
                    unset($user_row['classes']);
7964
                    unset($user_row['link']);
7965
                } else {
7966
                    unset($user_row['classes']);
7967
                    unset($user_row['link']);
7968
                }
7969
7970
                $csv_content[] = $user_row;
7971
            }
7972
            $users[] = array_values($user_row);
7973
        }
7974
7975
        if ($export_csv) {
7976
            Session::write('csv_content', $csv_content);
7977
        }
7978
7979
        Session::erase('additional_user_profile_info');
7980
        Session::erase('extra_field_info');
7981
7982
        return $users;
7983
    }
7984
7985
    /**
7986
     * Get data for users list in sortable with pagination.
7987
     *
7988
     * @param $from
7989
     * @param $number_of_items
7990
     * @param $column
7991
     * @param $direction
7992
     * @param $includeInvitedUsers boolean Whether include the invited users
7993
     *
7994
     * @return array
7995
     */
7996
    public static function getTotalTimeReport(
7997
        $from,
7998
        $number_of_items,
7999
        $column,
8000
        $direction,
8001
        $includeInvitedUsers = false
8002
    ) {
8003
        global $user_ids, $course_code, $export_csv, $csv_content, $session_id;
8004
8005
        $course_code = Database::escape_string($course_code);
8006
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
8007
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
8008
        $access_url_id = api_get_current_access_url_id();
8009
8010
        // get all users data from a course for sortable with limit
8011
        if (is_array($user_ids)) {
8012
            $user_ids = array_map('intval', $user_ids);
8013
            $condition_user = " WHERE user.user_id IN (".implode(',', $user_ids).") ";
8014
        } else {
8015
            $user_ids = intval($user_ids);
8016
            $condition_user = " WHERE user.user_id = $user_ids ";
8017
        }
8018
8019
        $url_table = null;
8020
        $url_condition = null;
8021
        if (api_is_multiple_url_enabled()) {
8022
            $url_table = ", ".$tbl_url_rel_user." as url_users";
8023
            $url_condition = " AND user.user_id = url_users.user_id AND access_url_id='$access_url_id'";
8024
        }
8025
8026
        $invitedUsersCondition = '';
8027
        if (!$includeInvitedUsers) {
8028
            $invitedUsersCondition = " AND user.status != ".INVITEE;
8029
        }
8030
8031
        $sql = "SELECT  user.user_id as user_id,
8032
                    user.official_code  as col0,
8033
                    user.lastname       as col1,
8034
                    user.firstname      as col2,
8035
                    user.username       as col3
8036
                FROM $tbl_user as user $url_table
8037
                $condition_user $url_condition $invitedUsersCondition";
8038
8039
        if (!in_array($direction, ['ASC', 'DESC'])) {
8040
            $direction = 'ASC';
8041
        }
8042
8043
        $column = intval($column);
8044
        $from = intval($from);
8045
        $number_of_items = intval($number_of_items);
8046
8047
        $sql .= " ORDER BY col$column $direction ";
8048
        $sql .= " LIMIT $from,$number_of_items";
8049
8050
        $res = Database::query($sql);
8051
        $users = [];
8052
8053
        $course_info = api_get_course_info($course_code);
8054
        $sortByFirstName = api_sort_by_first_name();
8055
        while ($user = Database::fetch_array($res, 'ASSOC')) {
8056
            $courseInfo = api_get_course_info($course_code);
8057
            $courseId = $courseInfo['real_id'];
8058
8059
            $user['official_code'] = $user['col0'];
8060
            $user['lastname'] = $user['col1'];
8061
            $user['firstname'] = $user['col2'];
8062
            $user['username'] = $user['col3'];
8063
8064
            $totalCourseTime = Tracking::get_time_spent_on_the_course(
8065
                $user['user_id'],
8066
                $courseId,
8067
                $session_id
8068
            );
8069
8070
            $user['time'] = api_time_to_hms($totalCourseTime);
8071
            $totalLpTime = Tracking::get_time_spent_in_lp(
8072
                $user['user_id'],
8073
                $course_code,
8074
                [],
8075
                $session_id
8076
            );
8077
8078
            $user['total_lp_time'] = $totalLpTime;
8079
            $warning = '';
8080
            if ($totalLpTime > $totalCourseTime) {
8081
                $warning = '&nbsp;'.Display::label(get_lang('TimeDifference'), 'danger');
8082
            }
8083
8084
            $user['total_lp_time'] = api_time_to_hms($totalLpTime).$warning;
8085
8086
            $user['first_connection'] = Tracking::get_first_connection_date_on_the_course(
8087
                $user['user_id'],
8088
                $courseId,
8089
                $session_id
8090
            );
8091
            $user['last_connection'] = Tracking::get_last_connection_date_on_the_course(
8092
                $user['user_id'],
8093
                $courseInfo,
8094
                $session_id,
8095
                $export_csv === false
8096
            );
8097
8098
            $user['link'] = '<center>
8099
                             <a href="../mySpace/myStudents.php?student='.$user['user_id'].'&details=true&course='.$course_code.'&origin=tracking_course&id_session='.$session_id.'">
8100
                             '.Display::return_icon('2rightarrow.png', get_lang('Details')).'
8101
                             </a>
8102
                         </center>';
8103
8104
            // store columns in array $users
8105
            $user_row = [];
8106
            $user_row['official_code'] = $user['official_code']; //0
8107
            if ($sortByFirstName) {
8108
                $user_row['firstname'] = $user['firstname'];
8109
                $user_row['lastname'] = $user['lastname'];
8110
            } else {
8111
                $user_row['lastname'] = $user['lastname'];
8112
                $user_row['firstname'] = $user['firstname'];
8113
            }
8114
            $user_row['username'] = $user['username'];
8115
            $user_row['time'] = $user['time'];
8116
            $user_row['total_lp_time'] = $user['total_lp_time'];
8117
            $user_row['first_connection'] = $user['first_connection'];
8118
            $user_row['last_connection'] = $user['last_connection'];
8119
8120
            $user_row['link'] = $user['link'];
8121
            $users[] = array_values($user_row);
8122
        }
8123
8124
        return $users;
8125
    }
8126
8127
    /**
8128
     * @param string $current
8129
     */
8130
    public static function actionsLeft($current, $sessionId = 0)
8131
    {
8132
        $usersLink = Display::url(
8133
            Display::return_icon('user.png', get_lang('StudentsTracking'), [], ICON_SIZE_MEDIUM),
8134
            'courseLog.php?'.api_get_cidreq(true, false)
8135
        );
8136
8137
        $groupsLink = Display::url(
8138
            Display::return_icon('group.png', get_lang('GroupReporting'), [], ICON_SIZE_MEDIUM),
8139
            'course_log_groups.php?'.api_get_cidreq()
8140
        );
8141
8142
        $resourcesLink = Display::url(
8143
            Display::return_icon('tools.png', get_lang('ResourcesTracking'), [], ICON_SIZE_MEDIUM),
8144
            'course_log_resources.php?'.api_get_cidreq(true, false)
8145
        );
8146
8147
        $courseLink = Display::url(
8148
            Display::return_icon('course.png', get_lang('CourseTracking'), [], ICON_SIZE_MEDIUM),
8149
            'course_log_tools.php?'.api_get_cidreq(true, false)
8150
        );
8151
8152
        $examLink = Display::url(
8153
            Display::return_icon('quiz.png', get_lang('ExamTracking'), [], ICON_SIZE_MEDIUM),
8154
            api_get_path(WEB_CODE_PATH).'tracking/exams.php?'.api_get_cidreq()
8155
        );
8156
8157
        $eventsLink = Display::url(
8158
            Display::return_icon('security.png', get_lang('EventsReport'), [], ICON_SIZE_MEDIUM),
8159
            api_get_path(WEB_CODE_PATH).'tracking/course_log_events.php?'.api_get_cidreq()
8160
        );
8161
8162
        $attendanceLink = '';
8163
        if (!empty($sessionId)) {
8164
            $attendanceLink = Display::url(
8165
                Display::return_icon('attendance_list.png', get_lang('Logins'), '', ICON_SIZE_MEDIUM),
8166
                api_get_path(WEB_CODE_PATH).'attendance/index.php?'.api_get_cidreq().'&action=calendar_logins'
8167
            );
8168
        }
8169
8170
        switch ($current) {
8171
            case 'users':
8172
                $usersLink = Display::url(
8173
                        Display::return_icon(
8174
                        'user_na.png',
8175
                        get_lang('StudentsTracking'),
8176
                        [],
8177
                        ICON_SIZE_MEDIUM
8178
                    ),
8179
                    '#'
8180
                );
8181
                break;
8182
            case 'groups':
8183
                $groupsLink = Display::url(
8184
                    Display::return_icon('group_na.png', get_lang('GroupReporting'), [], ICON_SIZE_MEDIUM),
8185
                    '#'
8186
                );
8187
                break;
8188
            case 'courses':
8189
                $courseLink = Display::url(
8190
                    Display::return_icon('course_na.png', get_lang('CourseTracking'), [], ICON_SIZE_MEDIUM),
8191
                    '#'
8192
                );
8193
                break;
8194
            case 'resources':
8195
                $resourcesLink = Display::url(
8196
                    Display::return_icon(
8197
                    'tools_na.png',
8198
                    get_lang('ResourcesTracking'),
8199
                    [],
8200
                    ICON_SIZE_MEDIUM
8201
                    ),
8202
                    '#'
8203
                );
8204
                break;
8205
            case 'exams':
8206
                $examLink = Display::url(
8207
                    Display::return_icon('quiz_na.png', get_lang('ExamTracking'), [], ICON_SIZE_MEDIUM),
8208
                    '#'
8209
                );
8210
                break;
8211
            case 'logs':
8212
                $eventsLink = Display::url(
8213
                    Display::return_icon('security_na.png', get_lang('EventsReport'), [], ICON_SIZE_MEDIUM),
8214
                    '#'
8215
                );
8216
                break;
8217
            case 'attendance':
8218
                if (!empty($sessionId)) {
8219
                    $attendanceLink = Display::url(
8220
                        Display::return_icon('attendance_list.png', get_lang('Logins'), '', ICON_SIZE_MEDIUM),
8221
                        '#'
8222
                    );
8223
                }
8224
                break;
8225
        }
8226
8227
        $items = [
8228
            $usersLink,
8229
            $groupsLink,
8230
            $courseLink,
8231
            $resourcesLink,
8232
            $examLink,
8233
            $eventsLink,
8234
            $attendanceLink,
8235
        ];
8236
8237
        return implode('', $items).'&nbsp;';
8238
    }
8239
}
8240