Passed
Push — master ( 05e539...3ba91c )
by Julito
08:20
created

Tracking   F

Complexity

Total Complexity 925

Size/Duplication

Total Lines 7694
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 4349
dl 0
loc 7694
rs 0.8
c 0
b 0
f 0
wmc 925

62 Methods

Rating   Name   Duplication   Size   Complexity  
B get_group_reporting() 0 84 9
F getLpStats() 0 1182 185
C get_time_spent_on_the_platform() 0 86 14
A getTotalTimeSpentOnThePlatform() 0 32 5
B minimumTimeAvailable() 0 24 10
A get_first_connection_date_on_the_course() 0 38 5
B get_time_spent_on_the_course() 0 47 8
B get_last_connection_date() 0 38 6
D get_last_connection_date_on_the_course() 0 99 18
F getStats() 0 306 29
A get_first_connection_date() 0 20 3
A count_course_per_student() 0 21 2
F generate_exercise_result_thumbnail_graph() 0 181 17
F getCalculateTime() 0 159 40
C compareUserData() 0 47 13
F get_avg_student_exercise_score() 0 134 21
A count_number_of_forums_by_course() 0 45 5
A generate_session_exercise_graph() 0 51 1
F generate_exercise_result_graph() 0 177 17
A get_course_list_in_session_from_student() 0 20 2
F get_avg_student_score() 0 372 57
A count_student_visited_links() 0 19 1
A get_exercise_student_progress() 0 37 4
C get_time_spent_in_lp() 0 142 14
F show_course_detail() 0 380 36
B get_ip_from_user_event() 0 32 7
C getCourseLpProgress() 0 67 12
B get_last_connection_time_in_lp() 0 77 10
A get_tools_most_used_by_course() 0 31 4
A count_student_messages() 0 19 2
A get_links_most_visited_by_course() 0 34 4
A getLastConnectionDateByCourse() 0 23 3
A count_number_of_posts_by_course() 0 46 4
F get_courses_followed_by_coach() 0 90 12
A get_courses_list_from_session() 0 22 2
A getFirstConnectionTimeInLp() 0 46 4
F get_sessions_coached_by_user() 0 138 19
A chat_last_connection() 0 31 2
A get_exercise_student_average_best_attempt() 0 26 5
F get_exercise_progress() 0 224 26
A getNumberOfCourseAccessDates() 0 14 1
B getInactiveStudentsInCourse() 0 89 11
A isAllowToTrack() 0 8 5
A count_student_uploaded_documents() 0 58 4
A is_allowed_to_coach_student() 0 32 3
A setUserSearchForm() 0 29 1
B get_course_connections_count() 0 61 10
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 33 3
A count_number_of_threads_by_course() 0 55 5
B getToolInformation() 0 82 8
A getLastConnectionInAnyCourse() 0 22 3
A displayUserSkills() 0 9 3
F show_user_progress() 0 791 98
A count_student_assignments() 0 61 4
F get_avg_student_progress() 0 142 21
A count_student_exercise_attempts() 0 40 3
B get_student_followed_by_coach() 0 88 8
F processUserDataMove() 0 593 82
B getAverageStudentScore() 0 67 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
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\Course;
6
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
7
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
8
use Chamilo\CoreBundle\Entity\User;
9
use Chamilo\CoreBundle\Framework\Container;
10
use ChamiloSession as Session;
11
use CpChart\Cache as pCache;
12
use CpChart\Data as pData;
13
use CpChart\Image as pImage;
14
use ExtraField as ExtraFieldModel;
15
16
/**
17
 *  Class Tracking.
18
 *
19
 *  @author  Julio Montoya <[email protected]>
20
 */
21
class Tracking
22
{
23
    /**
24
     * Get group reporting.
25
     *
26
     * @param int    $course_id
27
     * @param int    $sessionId
28
     * @param int    $group_id
29
     * @param string $type
30
     * @param int    $start
31
     * @param int    $limit
32
     * @param int    $sidx
33
     * @param string $sord
34
     * @param array  $where_condition
35
     *
36
     * @return array|null
37
     */
38
    public static function get_group_reporting(
39
        $course_id,
40
        $sessionId = 0,
41
        $group_id = 0,
42
        $type = 'all',
43
        $start = 0,
44
        $limit = 1000,
45
        $sidx = 1,
46
        $sord = 'desc',
47
        $where_condition = []
48
    ) {
49
        $course_id = (int) $course_id;
50
        $sessionId = (int) $sessionId;
51
52
        if (empty($course_id)) {
53
            return null;
54
        }
55
        $courseInfo = api_get_course_info_by_id($course_id);
56
        if ('count' == $type) {
57
            return GroupManager::get_group_list(null, $courseInfo, null, $sessionId, true);
58
        }
59
60
        $groupList = GroupManager::get_group_list(null, $courseInfo, null, $sessionId);
61
        $parsedResult = [];
62
        if (!empty($groupList)) {
63
            foreach ($groupList as $group) {
64
                $users = GroupManager::get_users($group['id'], true, null, null, false, $courseInfo['real_id']);
65
                $time = 0;
66
                $avg_student_score = 0;
67
                $avg_student_progress = 0;
68
                $work = 0;
69
                $messages = 0;
70
71
                foreach ($users as $user_data) {
72
                    $time += self::get_time_spent_on_the_course(
73
                        $user_data['user_id'],
74
                        $courseInfo['real_id'],
75
                        $sessionId
76
                    );
77
                    $average = self::get_avg_student_score(
78
                        $user_data['user_id'],
79
                        $courseInfo['code'],
80
                        [],
81
                        $sessionId
82
                    );
83
                    if (is_numeric($average)) {
84
                        $avg_student_score += $average;
85
                    }
86
                    $avg_student_progress += self::get_avg_student_progress(
87
                        $user_data['user_id'],
88
                        $courseInfo['code'],
89
                        [],
90
                        $sessionId
91
                    );
92
                    $work += self::count_student_assignments(
93
                        $user_data['user_id'],
94
                        $courseInfo['code'],
95
                        $sessionId
96
                    );
97
                    $messages += self::count_student_messages(
98
                        $user_data['user_id'],
99
                        $courseInfo['code'],
100
                        $sessionId
101
                    );
102
                }
103
104
                $countUsers = count($users);
105
                $averageProgress = empty($countUsers) ? 0 : round($avg_student_progress / $countUsers, 2);
106
                $averageScore = empty($countUsers) ? 0 : round($avg_student_score / $countUsers, 2);
107
108
                $groupItem = [
109
                    'id' => $group['id'],
110
                    'name' => $group['name'],
111
                    'time' => api_time_to_hms($time),
112
                    'progress' => $averageProgress,
113
                    'score' => $averageScore,
114
                    'works' => $work,
115
                    'messages' => $messages,
116
                ];
117
                $parsedResult[] = $groupItem;
118
            }
119
        }
120
121
        return $parsedResult;
122
    }
123
124
    /**
125
     * @param int    $user_id
126
     * @param array  $courseInfo
127
     * @param int    $session_id
128
     * @param string $origin
129
     * @param bool   $export_csv
130
     * @param int    $lp_id
131
     * @param int    $lp_item_id
132
     * @param int    $extendId
133
     * @param int    $extendAttemptId
134
     * @param string $extendedAttempt
135
     * @param string $extendedAll
136
     * @param string $type            classic or simple
137
     * @param bool   $allowExtend     Optional. Allow or not extend te results
138
     *
139
     * @return string
140
     */
141
    public static function getLpStats(
142
        $user_id,
143
        $courseInfo,
144
        $session_id,
145
        $origin,
146
        $export_csv,
147
        $lp_id,
148
        $lp_item_id = null,
149
        $extendId = null,
150
        $extendAttemptId = null,
151
        $extendedAttempt = null,
152
        $extendedAll = null,
153
        $type = 'classic',
154
        $allowExtend = true
155
    ) {
156
        if (empty($courseInfo) || empty($lp_id)) {
157
            return '';
158
        }
159
160
        $hideTime = api_get_configuration_value('hide_lp_time');
161
        $allowNewTracking = api_get_configuration_value('use_new_tracking_in_lp_item');
162
        $lp_id = (int) $lp_id;
163
164
        if ($allowNewTracking) {
165
            $extraField = new ExtraFieldValue('lp');
166
            $result = $extraField->get_values_by_handler_and_field_variable($lp_id, 'track_lp_item');
167
            if (empty($result)) {
168
                $allowNewTracking = false;
169
            } else {
170
                if (isset($result['value']) && 1 == $result['value']) {
171
                    $allowNewTracking = true;
172
                }
173
            }
174
        }
175
176
        $lp_item_id = (int) $lp_item_id;
177
        $user_id = (int) $user_id;
178
        $session_id = (int) $session_id;
179
        $origin = Security::remove_XSS($origin);
180
        $list = learnpath::get_flat_ordered_items_list($lp_id, 0, $courseInfo['real_id']);
181
        $is_allowed_to_edit = api_is_allowed_to_edit(null, true);
182
        $course_id = $courseInfo['real_id'];
183
        $courseCode = $courseInfo['code'];
184
        $session_condition = api_get_session_condition($session_id);
185
186
        // Extend all button
187
        $output = '';
188
189
        $extra = '<script>
190
        $(function() {
191
            $( "#dialog:ui-dialog" ).dialog( "destroy" );
192
            $( "#dialog-confirm" ).dialog({
193
                autoOpen: false,
194
                show: "blind",
195
                resizable: false,
196
                height:300,
197
                modal: true
198
            });
199
200
            $(".export").click(function() {
201
                var targetUrl = $(this).attr("href");
202
                $( "#dialog-confirm" ).dialog({
203
                    width:400,
204
                    height:300,
205
                    buttons: {
206
                        "'.addslashes(get_lang('Download')).'": function() {
207
                            var option = $("input[name=add_logo]:checked").val();
208
                            location.href = targetUrl+"&add_logo="+option;
209
                            $(this).dialog("close");
210
                        }
211
                    }
212
                });
213
                $("#dialog-confirm").dialog("open");
214
215
                return false;
216
            });
217
        });
218
        </script>';
219
220
        $extra .= '<div id="dialog-confirm" title="'.get_lang('Please confirm your choice').'">';
221
        $form = new FormValidator('report', 'post', null, null, ['class' => 'form-vertical']);
222
        $form->addCheckBox('add_logo', '', get_lang('AddRightLogo'), ['id' => 'export_format_csv_label']);
223
        $extra .= $form->returnForm();
224
        $extra .= '</div>';
225
226
        $output .= $extra;
227
228
        $url_suffix = '&lp_id='.$lp_id;
229
        if ('tracking' === $origin) {
230
            $url_suffix = '&session_id='.$session_id.'&course='.$courseCode.'&student_id='.$user_id.'&lp_id='.$lp_id.'&origin='.$origin;
231
        }
232
233
        $extend_all = 0;
234
        if (!empty($extendedAll)) {
235
            $extend_all_link = Display::url(
236
                Display::return_icon('view_less_stats.gif', get_lang('Hide all attempts')),
237
                api_get_self().'?action=stats'.$url_suffix
238
            );
239
            $extend_all = 1;
240
        } else {
241
            $extend_all_link = Display::url(
242
                Display::return_icon('view_more_stats.gif', get_lang('Show all attempts')),
243
                api_get_self().'?action=stats&extend_all=1'.$url_suffix
244
            );
245
        }
246
247
        if ('tracking' != $origin) {
248
            $output .= '<div class="section-status">';
249
            $output .= Display::page_header(get_lang('My progress'));
250
            $output .= '</div>';
251
        }
252
253
        $actionColumn = null;
254
        if ('classic' === $type) {
255
            $actionColumn = ' <th>'.get_lang('Detail').'</th>';
256
        }
257
258
        $timeHeader = '<th class="lp_time" colspan="2">'.get_lang('Time').'</th>';
259
        if ($hideTime) {
260
            $timeHeader = '';
261
        }
262
        $output .= '<div class="table-responsive">';
263
        $output .= '<table id="lp_tracking" class="table tracking">
264
            <thead>
265
            <tr class="table-header">
266
                <th width="16">'.(true == $allowExtend ? $extend_all_link : '&nbsp;').'</th>
267
                <th colspan="4">
268
                    '.get_lang('Learning object name').'
269
                </th>
270
                <th colspan="2">
271
                    '.get_lang('Status').'
272
                </th>
273
                <th colspan="2">
274
                    '.get_lang('Score').'
275
                </th>
276
                '.$timeHeader.'
277
                '.$actionColumn.'
278
                </tr>
279
            </thead>
280
            <tbody>
281
        ';
282
283
        // Going through the items using the $items[] array instead of the database order ensures
284
        // we get them in the same order as in the imsmanifest file, which is rather random when using
285
        // the database table.
286
        $TBL_LP_ITEM = Database::get_course_table(TABLE_LP_ITEM);
287
        $TBL_LP_ITEM_VIEW = Database::get_course_table(TABLE_LP_ITEM_VIEW);
288
        $TBL_LP_VIEW = Database::get_course_table(TABLE_LP_VIEW);
289
        $tbl_quiz_questions = Database::get_course_table(TABLE_QUIZ_QUESTION);
290
        $TBL_QUIZ = Database::get_course_table(TABLE_QUIZ_TEST);
291
        $tbl_stats_exercices = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
292
        $tbl_stats_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
293
294
        $sql = "SELECT max(view_count)
295
                FROM $TBL_LP_VIEW
296
                WHERE
297
                    c_id = $course_id AND
298
                    lp_id = $lp_id AND
299
                    user_id = $user_id
300
                    $session_condition";
301
        $res = Database::query($sql);
302
        $view = 0;
303
        if (Database::num_rows($res) > 0) {
304
            $myrow = Database::fetch_array($res);
305
            $view = (int) $myrow[0];
306
        }
307
308
        $counter = 0;
309
        $total_time = 0;
310
        $h = get_lang('h');
311
312
        if (!empty($export_csv)) {
313
            $csvHeaders = [
314
                get_lang('Learning object name'),
315
                get_lang('Status'),
316
                get_lang('Score'),
317
            ];
318
319
            if (false === $hideTime) {
320
                $csvHeaders[] = get_lang('Time');
321
            }
322
323
            $csv_content[] = $csvHeaders;
324
        }
325
326
        $result_disabled_ext_all = true;
327
        $chapterTypes = learnpath::getChapterTypes();
328
        $accessToPdfExport = api_is_allowed_to_edit(false, false, true);
329
330
        $minimumAvailable = self::minimumTimeAvailable($session_id, $course_id);
331
        $timeCourse = [];
332
        if ($minimumAvailable) {
333
            $timeCourse = self::getCalculateTime($user_id, $course_id, $session_id);
334
            Session::write('trackTimeCourse', $timeCourse);
335
        }
336
337
        // Show lp items
338
        if (is_array($list) && count($list) > 0) {
339
            foreach ($list as $my_item_id) {
340
                $extend_this = 0;
341
                $order = 'DESC';
342
                if ((!empty($extendId) && $extendId == $my_item_id) || $extend_all) {
343
                    $extend_this = 1;
344
                    $order = 'ASC';
345
                }
346
347
                // Prepare statement to go through each attempt.
348
                $viewCondition = null;
349
                if (!empty($view)) {
350
                    $viewCondition = " AND v.view_count = $view  ";
351
                }
352
353
                $sql = "SELECT
354
                    iv.status as mystatus,
355
                    v.view_count as mycount,
356
                    iv.score as myscore,
357
                    iv.total_time as mytime,
358
                    i.iid as myid,
359
                    i.lp_id as mylpid,
360
                    iv.lp_view_id as mylpviewid,
361
                    i.title as mytitle,
362
                    i.max_score as mymaxscore,
363
                    iv.max_score as myviewmaxscore,
364
                    i.item_type as item_type,
365
                    iv.view_count as iv_view_count,
366
                    iv.iid as iv_id,
367
                    path
368
                FROM $TBL_LP_ITEM as i
369
                INNER JOIN $TBL_LP_ITEM_VIEW as iv
370
                ON (i.iid = iv.lp_item_id AND i.c_id = iv.c_id)
371
                INNER JOIN $TBL_LP_VIEW as v
372
                ON (iv.lp_view_id = v.iid AND v.c_id = iv.c_id)
373
                WHERE
374
                    v.c_id = $course_id AND
375
                    i.iid = $my_item_id AND
376
                    i.lp_id = $lp_id  AND
377
                    v.user_id = $user_id AND
378
                    v.session_id = $session_id
379
                    $viewCondition
380
                ORDER BY iv.view_count $order ";
381
382
                $result = Database::query($sql);
383
                $num = Database::num_rows($result);
384
                $time_for_total = 0;
385
                $attemptResult = 0;
386
387
                if ($allowNewTracking && $timeCourse) {
388
                    if (isset($timeCourse['learnpath_detailed']) &&
389
                        isset($timeCourse['learnpath_detailed'][$lp_id]) &&
390
                        isset($timeCourse['learnpath_detailed'][$lp_id][$my_item_id])
391
                    ) {
392
                        $attemptResult = $timeCourse['learnpath_detailed'][$lp_id][$my_item_id][$view];
393
                    }
394
                }
395
396
                // Extend all
397
                if (($extend_this || $extend_all) && $num > 0) {
398
                    $row = Database::fetch_array($result);
399
                    $result_disabled_ext_all = false;
400
                    if ('quiz' === $row['item_type']) {
401
                        // Check results_disabled in quiz table.
402
                        $my_path = Database::escape_string($row['path']);
403
                        $sql = "SELECT results_disabled
404
                                FROM $TBL_QUIZ
405
                                WHERE
406
                                    iid ='".$my_path."'";
407
                        $res_result_disabled = Database::query($sql);
408
                        $row_result_disabled = Database::fetch_row($res_result_disabled);
409
410
                        if (Database::num_rows($res_result_disabled) > 0 &&
411
                            1 === (int) $row_result_disabled[0]
412
                        ) {
413
                            $result_disabled_ext_all = true;
414
                        }
415
                    }
416
417
                    // If there are several attempts, and the link to extend has been clicked, show each attempt...
418
                    $oddclass = 'row_even';
419
                    if (0 === ($counter % 2)) {
420
                        $oddclass = 'row_odd';
421
                    }
422
                    $extend_link = '';
423
                    if (!empty($inter_num)) {
424
                        $extend_link = Display::url(
425
                            Display::return_icon(
426
                                'visible.png',
427
                                get_lang('Hide attempt view')
428
                            ),
429
                            api_get_self().'?action=stats&fold_id='.$my_item_id.$url_suffix
430
                        );
431
                    }
432
                    $title = $row['mytitle'];
433
434
                    if (empty($title)) {
435
                        $title = learnpath::rl_get_resource_name($courseInfo['code'], $lp_id, $row['myid']);
436
                    }
437
438
                    if (in_array($row['item_type'], $chapterTypes)) {
439
                        $title = "<h4> $title </h4>";
440
                    }
441
                    $lesson_status = $row['mystatus'];
442
                    $title = Security::remove_XSS($title);
443
                    $counter++;
444
445
                    $action = null;
446
                    if ('classic' === $type) {
447
                        $action = '<td></td>';
448
                    }
449
450
                    if (in_array($row['item_type'], $chapterTypes)) {
451
                        $output .= '<tr class="'.$oddclass.'">
452
                                <td>'.$extend_link.'</td>
453
                                <td colspan="4">
454
                                   '.$title.'
455
                                </td>
456
                                <td colspan="2">'.learnpathItem::humanize_status($lesson_status, true, $type).'</td>
457
                                <td colspan="2"></td>
458
                                <td colspan="2"></td>
459
                                '.$action.'
460
                            </tr>';
461
                        continue;
462
                    } else {
463
                        $output .= '<tr class="'.$oddclass.'">
464
                                <td>'.$extend_link.'</td>
465
                                <td colspan="4">'.$title.'</td>
466
                                <td colspan="2"></td>
467
                                <td colspan="2"></td>
468
                                <td colspan="2"></td>
469
                                '.$action.'
470
                            </tr>';
471
                    }
472
473
                    $attemptCount = 1;
474
                    do {
475
                        // Check if there are interactions below.
476
                        $extend_attempt_link = '';
477
                        $extend_this_attempt = 0;
478
479
                        if ($allowNewTracking && $timeCourse) {
480
                            //$attemptResult = 0;
481
                            if (isset($timeCourse['learnpath_detailed']) &&
482
                                isset($timeCourse['learnpath_detailed'][$lp_id]) &&
483
                                isset($timeCourse['learnpath_detailed'][$lp_id][$my_item_id])
484
                            ) {
485
                                $attemptResult = $timeCourse['learnpath_detailed'][$lp_id][$my_item_id][$row['iv_view_count']];
486
                            }
487
                        }
488
                        if ((
489
                            learnpath::get_interactions_count_from_db($row['iv_id'], $course_id) > 0 ||
490
                            learnpath::get_objectives_count_from_db($row['iv_id'], $course_id) > 0
491
                            ) &&
492
                            !$extend_all
493
                        ) {
494
                            if ($extendAttemptId == $row['iv_id']) {
495
                                // The extend button for this attempt has been clicked.
496
                                $extend_this_attempt = 1;
497
                                $extend_attempt_link = Display::url(
498
                                    Display::return_icon('visible.png', get_lang('Hide attempt view')),
499
                                    api_get_self().'?action=stats&extend_id='.$my_item_id.'&fold_attempt_id='.$row['iv_id'].$url_suffix
500
                                );
501
                                if ($accessToPdfExport) {
502
                                    $extend_attempt_link .= '&nbsp;'.
503
                                        Display::url(
504
                                            Display::return_icon('pdf.png', get_lang('Export to PDF')),
505
                                            api_get_self().'?action=export_stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix,
506
                                            ['class' => 'export']
507
                                        );
508
                                }
509
                            } else { // Same case if fold_attempt_id is set, so not implemented explicitly.
510
                                // The extend button for this attempt has not been clicked.
511
                                $extend_attempt_link = Display::url(
512
                                    Display::return_icon('invisible.png', get_lang('Extend attempt view')),
513
                                    api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix
514
                                );
515
                                if ($accessToPdfExport) {
516
                                    $extend_attempt_link .= '&nbsp;'.
517
                                        Display::url(
518
                                            Display::return_icon('pdf.png', get_lang('Export to PDF')),
519
                                            api_get_self().'?action=export_stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix,
520
                                            ['class' => 'export']
521
                                        );
522
                                }
523
                            }
524
                        }
525
526
                        $oddclass = 'row_even';
527
                        if (0 == ($counter % 2)) {
528
                            $oddclass = 'row_odd';
529
                        }
530
531
                        $lesson_status = $row['mystatus'];
532
                        $score = $row['myscore'];
533
                        $time_for_total += $row['mytime'];
534
                        $attemptTime = $row['mytime'];
535
536
                        if ($minimumAvailable) {
537
                            $lp_time = $timeCourse[TOOL_LEARNPATH];
538
                            $lpTime = null;
539
                            if (isset($lp_time[$lp_id])) {
540
                                $lpTime = (int) $lp_time[$lp_id];
541
                            }
542
                            $time_for_total = $lpTime;
543
544
                            if ($allowNewTracking) {
545
                                $time_for_total = (int) $attemptResult;
546
                                $attemptTime = (int) $attemptResult;
547
                            }
548
                        }
549
550
                        $time = learnpathItem::getScormTimeFromParameter('js', $attemptTime);
551
552
                        if (0 == $score) {
553
                            $maxscore = $row['mymaxscore'];
554
                        } else {
555
                            if ('sco' === $row['item_type']) {
556
                                if (!empty($row['myviewmaxscore']) && $row['myviewmaxscore'] > 0) {
557
                                    $maxscore = $row['myviewmaxscore'];
558
                                } elseif ('' === $row['myviewmaxscore']) {
559
                                    $maxscore = 0;
560
                                } else {
561
                                    $maxscore = $row['mymaxscore'];
562
                                }
563
                            } else {
564
                                $maxscore = $row['mymaxscore'];
565
                            }
566
                        }
567
568
                        // Remove "NaN" if any (@todo: locate the source of these NaN)
569
                        $time = str_replace('NaN', '00'.$h.'00\'00"', $time);
570
571
                        if ('dir' !== $row['item_type']) {
572
                            if (!$is_allowed_to_edit && $result_disabled_ext_all) {
573
                                $view_score = Display::return_icon(
574
                                    'invisible.png',
575
                                    get_lang('Results hidden by the exercise setting')
576
                                );
577
                            } else {
578
                                switch ($row['item_type']) {
579
                                    case 'sco':
580
                                        if (0 == $maxscore) {
581
                                            $view_score = $score;
582
                                        } else {
583
                                            $view_score = ExerciseLib::show_score(
584
                                                $score,
585
                                                $maxscore,
586
                                                false
587
                                            );
588
                                        }
589
                                        break;
590
                                    case 'document':
591
                                        $view_score = (0 == $score ? '/' : ExerciseLib::show_score($score, $maxscore, false));
592
                                        break;
593
                                    default:
594
                                        $view_score = ExerciseLib::show_score(
595
                                            $score,
596
                                            $maxscore,
597
                                            false
598
                                        );
599
                                        break;
600
                                }
601
                            }
602
603
                            $action = null;
604
                            if ('classic' == $type) {
605
                                $action = '<td></td>';
606
                            }
607
                            $timeRow = '<td class="lp_time" colspan="2">'.$time.'</td>';
608
                            if ($hideTime) {
609
                                $timeRow = '';
610
                            }
611
                            $output .= '<tr class="'.$oddclass.'">
612
                                    <td></td>
613
                                    <td style="width:70px;float:left;">'.$extend_attempt_link.'</td>
614
                                    <td colspan="3">'.get_lang('Attempt').' '.$attemptCount.'</td>
615
                                    <td colspan="2">'.learnpathItem::humanize_status($lesson_status, true, $type).'</td>
616
                                    <td colspan="2">'.$view_score.'</td>
617
                                    '.$timeRow.'
618
                                    '.$action.'
619
                                </tr>';
620
                            $attemptCount++;
621
                            if (!empty($export_csv)) {
622
                                $temp = [];
623
                                $temp[] = $title = Security::remove_XSS($title);
624
                                $temp[] = Security::remove_XSS(
625
                                    learnpathItem::humanize_status($lesson_status, false, $type)
626
                                );
627
628
                                if ('quiz' === $row['item_type']) {
629
                                    if (!$is_allowed_to_edit && $result_disabled_ext_all) {
630
                                        $temp[] = '/';
631
                                    } else {
632
                                        $temp[] = (0 == $score ? '0/'.$maxscore : (0 == $maxscore ? $score : $score.'/'.float_format($maxscore, 1)));
633
                                    }
634
                                } else {
635
                                    $temp[] = (0 == $score ? '/' : (0 == $maxscore ? $score : $score.'/'.float_format($maxscore, 1)));
636
                                }
637
638
                                if (false === $hideTime) {
639
                                    $temp[] = $time;
640
                                }
641
                                $csv_content[] = $temp;
642
                            }
643
                        }
644
645
                        $counter++;
646
                        $action = null;
647
                        if ('classic' === $type) {
648
                            $action = '<td></td>';
649
                        }
650
651
                        if ($extend_this_attempt || $extend_all) {
652
                            $list1 = learnpath::get_iv_interactions_array($row['iv_id'], $course_id);
653
                            foreach ($list1 as $id => $interaction) {
654
                                $oddclass = 'row_even';
655
                                if (0 == ($counter % 2)) {
656
                                    $oddclass = 'row_odd';
657
                                }
658
                                $timeRow = '<td class="lp_time">'.$interaction['time'].'</td>';
659
                                if ($hideTime) {
660
                                    $timeRow = '';
661
                                }
662
663
                                $output .= '<tr class="'.$oddclass.'">
664
                                        <td></td>
665
                                        <td></td>
666
                                        <td></td>
667
                                        <td>'.$interaction['order_id'].'</td>
668
                                        <td>'.$interaction['id'].'</td>';
669
670
                                $output .= '
671
                                        <td colspan="2">'.$interaction['type'].'</td>
672
                                        <td>'.$interaction['student_response_formatted'].'</td>
673
                                        <td>'.$interaction['result'].'</td>
674
                                        <td>'.$interaction['latency'].'</td>
675
                                        '.$timeRow.'
676
                                        '.$action.'
677
                                    </tr>';
678
                                $counter++;
679
                            }
680
                            $list2 = learnpath::get_iv_objectives_array($row['iv_id'], $course_id);
681
                            foreach ($list2 as $id => $interaction) {
682
                                $oddclass = 'row_even';
683
                                if (0 === ($counter % 2)) {
684
                                    $oddclass = 'row_odd';
685
                                }
686
                                $output .= '<tr class="'.$oddclass.'">
687
                                        <td></td>
688
                                        <td></td>
689
                                        <td></td>
690
                                        <td>'.$interaction['order_id'].'</td>
691
                                        <td colspan="2">'.$interaction['objective_id'].'</td>
692
                                        <td colspan="2">'.$interaction['status'].'</td>
693
                                        <td>'.$interaction['score_raw'].'</td>
694
                                        <td>'.$interaction['score_max'].'</td>
695
                                        <td>'.$interaction['score_min'].'</td>
696
                                        '.$action.'
697
                                     </tr>';
698
                                $counter++;
699
                            }
700
                        }
701
                    } while ($row = Database::fetch_array($result));
702
                } elseif ($num > 0) {
703
                    // Not extended.
704
                    $row = Database::fetch_array($result, 'ASSOC');
705
                    $my_id = $row['myid'];
706
                    $my_lp_id = $row['mylpid'];
707
                    $my_lp_view_id = $row['mylpviewid'];
708
                    $my_path = $row['path'];
709
                    $result_disabled_ext_all = false;
710
                    if ('quiz' === $row['item_type']) {
711
                        // Check results_disabled in quiz table.
712
                        $my_path = Database::escape_string($my_path);
713
                        $sql = "SELECT results_disabled
714
                                FROM $TBL_QUIZ
715
                                WHERE iid = '$my_path' ";
716
                        $res_result_disabled = Database::query($sql);
717
                        $row_result_disabled = Database::fetch_row($res_result_disabled);
718
719
                        if (Database::num_rows($res_result_disabled) > 0 &&
720
                            1 === (int) $row_result_disabled[0]
721
                        ) {
722
                            $result_disabled_ext_all = true;
723
                        }
724
                    }
725
726
                    // Check if there are interactions below
727
                    $extend_this_attempt = 0;
728
                    $inter_num = learnpath::get_interactions_count_from_db($row['iv_id'], $course_id);
729
                    $objec_num = learnpath::get_objectives_count_from_db($row['iv_id'], $course_id);
730
                    $extend_attempt_link = '';
731
                    if ($inter_num > 0 || $objec_num > 0) {
732
                        if (!empty($extendAttemptId) && $extendAttemptId == $row['iv_id']) {
733
                            // The extend button for this attempt has been clicked.
734
                            $extend_this_attempt = 1;
735
                            $extend_attempt_link = Display::url(
736
                                Display::return_icon('visible.png', get_lang('Hide attempt view')),
737
                                api_get_self().'?action=stats&extend_id='.$my_item_id.'&fold_attempt_id='.$row['iv_id'].$url_suffix
738
                            );
739
                        } else {
740
                            // Same case if fold_attempt_id is set, so not implemented explicitly.
741
                            // The extend button for this attempt has not been clicked.
742
                            $extend_attempt_link = Display::url(
743
                                Display::return_icon('invisible.png', get_lang('Extend attempt view')),
744
                                api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix
745
                            );
746
                        }
747
                    }
748
749
                    $oddclass = 'row_even';
750
                    if (0 == ($counter % 2)) {
751
                        $oddclass = 'row_odd';
752
                    }
753
754
                    $extend_link = '';
755
                    if ($inter_num > 1) {
756
                        $extend_link = Display::url(
757
                            Display::return_icon('invisible.png', get_lang('Extend attempt view')),
758
                            api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix
759
                        );
760
                    }
761
762
                    $lesson_status = $row['mystatus'];
763
                    $score = $row['myscore'];
764
                    $subtotal_time = $row['mytime'];
765
                    while ($tmp_row = Database::fetch_array($result)) {
766
                        $subtotal_time += $tmp_row['mytime'];
767
                    }
768
769
                    if ($allowNewTracking) {
770
                        $subtotal_time = $attemptResult;
771
                    }
772
773
                    $title = $row['mytitle'];
774
                    // Selecting the exe_id from stats attempts tables in order to look the max score value.
775
                    $sql = 'SELECT * FROM '.$tbl_stats_exercices.'
776
                            WHERE
777
                                exe_exo_id="'.$row['path'].'" AND
778
                                exe_user_id="'.$user_id.'" AND
779
                                orig_lp_id = "'.$lp_id.'" AND
780
                                orig_lp_item_id = "'.$row['myid'].'" AND
781
                                c_id = '.$course_id.' AND
782
                                status <> "incomplete" AND
783
                                session_id = '.$session_id.'
784
                             ORDER BY exe_date DESC
785
                             LIMIT 1';
786
787
                    $resultLastAttempt = Database::query($sql);
788
                    $num = Database::num_rows($resultLastAttempt);
789
                    $id_last_attempt = null;
790
                    if ($num > 0) {
791
                        while ($rowLA = Database::fetch_array($resultLastAttempt)) {
792
                            $id_last_attempt = $rowLA['exe_id'];
793
                        }
794
                    }
795
796
                    switch ($row['item_type']) {
797
                        case 'sco':
798
                            if (!empty($row['myviewmaxscore']) && $row['myviewmaxscore'] > 0) {
799
                                $maxscore = $row['myviewmaxscore'];
800
                            } elseif ('' === $row['myviewmaxscore']) {
801
                                $maxscore = 0;
802
                            } else {
803
                                $maxscore = $row['mymaxscore'];
804
                            }
805
                            break;
806
                        case 'quiz':
807
                            // Get score and total time from last attempt of a exercise en lp.
808
                            $sql = "SELECT iid, score
809
                                    FROM $TBL_LP_ITEM_VIEW
810
                                    WHERE
811
                                        c_id = $course_id AND
812
                                        lp_item_id = '".(int) $my_id."' AND
813
                                        lp_view_id = '".(int) $my_lp_view_id."'
814
                                    ORDER BY view_count DESC
815
                                    LIMIT 1";
816
                            $res_score = Database::query($sql);
817
                            $row_score = Database::fetch_array($res_score);
818
819
                            $sql = "SELECT SUM(total_time) as total_time
820
                                    FROM $TBL_LP_ITEM_VIEW
821
                                    WHERE
822
                                        c_id = $course_id AND
823
                                        lp_item_id = '".(int) $my_id."' AND
824
                                        lp_view_id = '".(int) $my_lp_view_id."'";
825
                            $res_time = Database::query($sql);
826
                            $row_time = Database::fetch_array($res_time);
827
828
                            $score = 0;
829
                            $subtotal_time = 0;
830
                            if (Database::num_rows($res_score) > 0 &&
831
                                Database::num_rows($res_time) > 0
832
                            ) {
833
                                $score = (float) $row_score['score'];
834
                                $subtotal_time = (int) $row_time['total_time'];
835
                            }
836
                            // Selecting the max score from an attempt.
837
                            $sql = "SELECT SUM(t.ponderation) as maxscore
838
                                    FROM (
839
                                        SELECT DISTINCT
840
                                            question_id, marks, ponderation
841
                                        FROM $tbl_stats_attempts as at
842
                                        INNER JOIN $tbl_quiz_questions as q
843
                                        ON (q.id = at.question_id AND q.c_id = $course_id)
844
                                        WHERE exe_id ='$id_last_attempt'
845
                                    ) as t";
846
847
                            $result = Database::query($sql);
848
                            $row_max_score = Database::fetch_array($result);
849
                            $maxscore = $row_max_score['maxscore'];
850
851
                            // Get duration time from track_e_exercises.exe_duration instead of lp_view_item.total_time
852
                            $sql = 'SELECT SUM(exe_duration) exe_duration
853
                                    FROM '.$tbl_stats_exercices.'
854
                                    WHERE
855
                                        exe_exo_id="'.$row['path'].'" AND
856
                                        exe_user_id="'.$user_id.'" AND
857
                                        orig_lp_id = "'.$lp_id.'" AND
858
                                        orig_lp_item_id = "'.$row['myid'].'" AND
859
                                        c_id = '.$course_id.' AND
860
                                        status <> "incomplete" AND
861
                                        session_id = '.$session_id.'
862
                                     ORDER BY exe_date DESC ';
863
                            $sumScoreResult = Database::query($sql);
864
                            $durationRow = Database::fetch_array($sumScoreResult, 'ASSOC');
865
                            if (!empty($durationRow['exe_duration'])) {
866
                                $exeDuration = $durationRow['exe_duration'];
867
                                if ($exeDuration != $subtotal_time &&
868
                                    !empty($row_score['iid']) &&
869
                                    !empty($exeDuration)
870
                                ) {
871
                                    $subtotal_time = $exeDuration;
872
                                    // Update c_lp_item_view.total_time
873
                                    $sqlUpdate = "UPDATE $TBL_LP_ITEM_VIEW SET total_time = '$exeDuration'
874
                                                  WHERE iid = ".$row_score['iid'];
875
                                    Database::query($sqlUpdate);
876
                                }
877
                            }
878
                            break;
879
                        default:
880
                            $maxscore = $row['mymaxscore'];
881
                            break;
882
                    }
883
884
                    $time_for_total = $subtotal_time;
885
                    $time = learnpathItem::getScormTimeFromParameter('js', $subtotal_time);
886
                    if (empty($title)) {
887
                        $title = learnpath::rl_get_resource_name(
888
                            $courseInfo['code'],
889
                            $lp_id,
890
                            $row['myid']
891
                        );
892
                    }
893
894
                    $action = null;
895
                    if ('classic' == $type) {
896
                        $action = '<td></td>';
897
                    }
898
899
                    if (in_array($row['item_type'], $chapterTypes)) {
900
                        $title = Security::remove_XSS($title);
901
                        $output .= '<tr class="'.$oddclass.'">
902
                                <td>'.$extend_link.'</td>
903
                                <td colspan="10">
904
                                <h4>'.$title.'</h4>
905
                                </td>
906
                                '.$action.'
907
                            </tr>';
908
                    } else {
909
                        $correct_test_link = '-';
910
                        $showRowspan = false;
911
                        if ('quiz' === $row['item_type']) {
912
                            $my_url_suffix = '&course='.$courseCode.'&student_id='.$user_id.'&lp_id='.intval($row['mylpid']).'&origin='.$origin;
913
                            $sql = 'SELECT * FROM '.$tbl_stats_exercices.'
914
                                     WHERE
915
                                        exe_exo_id="'.$row['path'].'" AND
916
                                        exe_user_id="'.$user_id.'" AND
917
                                        orig_lp_id = "'.$lp_id.'" AND
918
                                        orig_lp_item_id = "'.$row['myid'].'" AND
919
                                        c_id = '.$course_id.' AND
920
                                        status <> "incomplete" AND
921
                                        session_id = '.$session_id.'
922
                                     ORDER BY exe_date DESC ';
923
924
                            $resultLastAttempt = Database::query($sql);
925
                            $num = Database::num_rows($resultLastAttempt);
926
                            $showRowspan = false;
927
                            if ($num > 0) {
928
                                $linkId = 'link_'.$my_id;
929
                                if (1 == $extendedAttempt &&
930
                                    $lp_id == $my_lp_id &&
931
                                    $lp_item_id == $my_id
932
                                ) {
933
                                    $showRowspan = true;
934
                                    $correct_test_link = Display::url(
935
                                        Display::return_icon(
936
                                            'view_less_stats.gif',
937
                                            get_lang('Hide all attempts')
938
                                        ),
939
                                        api_get_self().'?action=stats'.$my_url_suffix.'&session_id='.$session_id.'&lp_item_id='.$my_id.'#'.$linkId,
940
                                        ['id' => $linkId]
941
                                    );
942
                                } else {
943
                                    $correct_test_link = Display::url(
944
                                        Display::return_icon(
945
                                            'view_more_stats.gif',
946
                                            get_lang(
947
                                                'Show all attemptsByExercise'
948
                                            )
949
                                        ),
950
                                        api_get_self().'?action=stats&extend_attempt=1'.$my_url_suffix.'&session_id='.$session_id.'&lp_item_id='.$my_id.'#'.$linkId,
951
                                        ['id' => $linkId]
952
                                    );
953
                                }
954
                            }
955
                        }
956
957
                        $title = Security::remove_XSS($title);
958
                        $action = null;
959
                        if ('classic' === $type) {
960
                            $action = '<td '.($showRowspan ? 'rowspan="2"' : '').'>'.$correct_test_link.'</td>';
961
                        }
962
963
                        if ($lp_id == $my_lp_id && false) {
964
                            $output .= '<tr class ='.$oddclass.'>
965
                                    <td>'.$extend_link.'</td>
966
                                    <td colspan="4">'.$title.'</td>
967
                                    <td colspan="2">&nbsp;</td>
968
                                    <td colspan="2">&nbsp;</td>
969
                                    <td colspan="2">&nbsp;</td>
970
                                    '.$action.'
971
                                </tr>';
972
                            $output .= '</tr>';
973
                        } else {
974
                            if ($lp_id == $my_lp_id && $lp_item_id == $my_id) {
975
                                $output .= "<tr class='$oddclass'>";
976
                            } else {
977
                                $output .= "<tr class='$oddclass'>";
978
                            }
979
980
                            $scoreItem = null;
981
                            if ('quiz' == $row['item_type']) {
982
                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
983
                                    $scoreItem .= Display::return_icon(
984
                                        'invisible.png',
985
                                        get_lang('Results hidden by the exercise setting')
986
                                    );
987
                                } else {
988
                                    $scoreItem .= ExerciseLib::show_score($score, $maxscore, false);
989
                                }
990
                            } else {
991
                                $scoreItem .= 0 == $score ? '/' : (0 == $maxscore ? $score : $score.'/'.$maxscore);
992
                            }
993
994
                            $timeRow = '<td class="lp_time" colspan="2">'.$time.'</td>';
995
                            if ($hideTime) {
996
                                $timeRow = '';
997
                            }
998
999
                            $output .= '
1000
                                <td>'.$extend_link.'</td>
1001
                                <td colspan="4">'.$title.'</td>
1002
                                <td colspan="2">'.learnpathitem::humanize_status($lesson_status).'</td>
1003
                                <td colspan="2">'.$scoreItem.'</td>
1004
                                '.$timeRow.'
1005
                                '.$action.'
1006
                             ';
1007
                            $output .= '</tr>';
1008
                        }
1009
1010
                        if (!empty($export_csv)) {
1011
                            $temp = [];
1012
                            $temp[] = api_html_entity_decode($title, ENT_QUOTES);
1013
                            $temp[] = api_html_entity_decode($lesson_status, ENT_QUOTES);
1014
                            if ('quiz' === $row['item_type']) {
1015
                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
1016
                                    $temp[] = '/';
1017
                                } else {
1018
                                    $temp[] = (0 == $score ? '0/'.$maxscore : (0 == $maxscore ? $score : $score.'/'.float_format($maxscore, 1)));
1019
                                }
1020
                            } else {
1021
                                $temp[] = (0 == $score ? '/' : (0 == $maxscore ? $score : $score.'/'.float_format($maxscore, 1)));
1022
                            }
1023
1024
                            if (false === $hideTime) {
1025
                                $temp[] = $time;
1026
                            }
1027
                            $csv_content[] = $temp;
1028
                        }
1029
                    }
1030
1031
                    $counter++;
1032
                    $action = null;
1033
                    if ('classic' === $type) {
1034
                        $action = '<td></td>';
1035
                    }
1036
1037
                    if ($extend_this_attempt || $extend_all) {
1038
                        $list1 = learnpath::get_iv_interactions_array($row['iv_id'], $course_id);
1039
                        foreach ($list1 as $id => $interaction) {
1040
                            $oddclass = 'row_even';
1041
                            if (0 == ($counter % 2)) {
1042
                                $oddclass = 'row_odd';
1043
                            }
1044
                            $timeRow = '<td class="lp_time">'.$interaction['time'].'</td>';
1045
                            if ($hideTime) {
1046
                                $timeRow = '';
1047
                            }
1048
1049
                            $output .= '<tr class="'.$oddclass.'">
1050
                                    <td></td>
1051
                                    <td></td>
1052
                                    <td></td>
1053
                                    <td>'.$interaction['order_id'].'</td>
1054
                                    <td>'.$interaction['id'].'</td>
1055
                                    <td colspan="2">'.$interaction['type'].'</td>
1056
                                    <td>'.urldecode($interaction['student_response']).'</td>
1057
                                    <td>'.$interaction['result'].'</td>
1058
                                    <td>'.$interaction['latency'].'</td>
1059
                                    '.$timeRow.'
1060
                                    '.$action.'
1061
                               </tr>';
1062
                            $counter++;
1063
                        }
1064
1065
                        $list2 = learnpath::get_iv_objectives_array($row['iv_id'], $course_id);
1066
                        foreach ($list2 as $id => $interaction) {
1067
                            $oddclass = 'row_even';
1068
                            if (0 == ($counter % 2)) {
1069
                                $oddclass = 'row_odd';
1070
                            }
1071
                            $output .= '<tr class="'.$oddclass.'">
1072
                                    <td></td>
1073
                                    <td></td>
1074
                                    <td></td>
1075
                                    <td>'.$interaction['order_id'].'</td>
1076
                                    <td colspan="2">'.$interaction['objective_id'].'</td>
1077
                                    <td colspan="2">'.$interaction['status'].'</td>
1078
                                    <td>'.$interaction['score_raw'].'</td>
1079
                                    <td>'.$interaction['score_max'].'</td>
1080
                                    <td>'.$interaction['score_min'].'</td>
1081
                                    '.$action.'
1082
                               </tr>';
1083
                            $counter++;
1084
                        }
1085
                    }
1086
1087
                    // Attempts listing by exercise.
1088
                    if ($lp_id == $my_lp_id && $lp_item_id == $my_id && $extendedAttempt) {
1089
                        // Get attempts of a exercise.
1090
                        if (!empty($lp_id) &&
1091
                            !empty($lp_item_id) &&
1092
                            'quiz' === $row['item_type']
1093
                        ) {
1094
                            $sql = "SELECT path FROM $TBL_LP_ITEM
1095
                                    WHERE
1096
                                        c_id = $course_id AND
1097
                                        iid = '$lp_item_id' AND
1098
                                        lp_id = '$lp_id'";
1099
                            $res_path = Database::query($sql);
1100
                            $row_path = Database::fetch_array($res_path);
1101
1102
                            if (Database::num_rows($res_path) > 0) {
1103
                                $sql = 'SELECT * FROM '.$tbl_stats_exercices.'
1104
                                        WHERE
1105
                                            exe_exo_id="'.(int) $row_path['path'].'" AND
1106
                                            status <> "incomplete" AND
1107
                                            exe_user_id="'.$user_id.'" AND
1108
                                            orig_lp_id = "'.(int) $lp_id.'" AND
1109
                                            orig_lp_item_id = "'.(int) $lp_item_id.'" AND
1110
                                            c_id = '.$course_id.'  AND
1111
                                            session_id = '.$session_id.'
1112
                                        ORDER BY exe_date';
1113
                                $res_attempts = Database::query($sql);
1114
                                $num_attempts = Database::num_rows($res_attempts);
1115
                                if ($num_attempts > 0) {
1116
                                    $n = 1;
1117
                                    while ($row_attempts = Database::fetch_array($res_attempts)) {
1118
                                        $my_score = $row_attempts['score'];
1119
                                        $my_maxscore = $row_attempts['max_score'];
1120
                                        $my_exe_id = $row_attempts['exe_id'];
1121
                                        $mktime_start_date = api_strtotime($row_attempts['start_date'], 'UTC');
1122
                                        $mktime_exe_date = api_strtotime($row_attempts['exe_date'], 'UTC');
1123
                                        $time_attemp = ' - ';
1124
                                        if ($mktime_start_date && $mktime_exe_date) {
1125
                                            $time_attemp = api_format_time($row_attempts['exe_duration'], 'js');
1126
                                        }
1127
                                        if (!$is_allowed_to_edit && $result_disabled_ext_all) {
1128
                                            $view_score = Display::return_icon(
1129
                                                'invisible.png',
1130
                                                get_lang(
1131
                                                    'Results hidden by the exercise setting'
1132
                                                )
1133
                                            );
1134
                                        } else {
1135
                                            // Show only float when need it
1136
                                            if (0 == $my_score) {
1137
                                                $view_score = ExerciseLib::show_score(
1138
                                                    0,
1139
                                                    $my_maxscore,
1140
                                                    false
1141
                                                );
1142
                                            } else {
1143
                                                if (0 == $my_maxscore) {
1144
                                                    $view_score = $my_score;
1145
                                                } else {
1146
                                                    $view_score = ExerciseLib::show_score(
1147
                                                        $my_score,
1148
                                                        $my_maxscore,
1149
                                                        false
1150
                                                    );
1151
                                                }
1152
                                            }
1153
                                        }
1154
                                        $my_lesson_status = $row_attempts['status'];
1155
                                        if ('' == $my_lesson_status) {
1156
                                            $my_lesson_status = learnpathitem::humanize_status('completed');
1157
                                        } elseif ('incomplete' == $my_lesson_status) {
1158
                                            $my_lesson_status = learnpathitem::humanize_status('incomplete');
1159
                                        }
1160
                                        $timeRow = '<td class="lp_time" colspan="2">'.$time_attemp.'</td>';
1161
                                        if ($hideTime) {
1162
                                            $timeRow = '';
1163
                                        }
1164
1165
                                        $output .= '<tr class="'.$oddclass.'" >
1166
                                        <td></td>
1167
                                        <td>'.$extend_attempt_link.'</td>
1168
                                        <td colspan="3">'.get_lang('Attempt').' '.$n.'</td>
1169
                                        <td colspan="2">'.$my_lesson_status.'</td>
1170
                                        <td colspan="2">'.$view_score.'</td>
1171
                                        '.$timeRow;
1172
1173
                                        if ('classic' == $action) {
1174
                                            if ('tracking' != $origin) {
1175
                                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
1176
                                                    $output .= '<td>
1177
                                                            <img src="'.Display::returnIconPath('quiz_na.gif').'" alt="'.get_lang('Show attempt').'" title="'.get_lang('Show attempt').'">
1178
                                                            </td>';
1179
                                                } else {
1180
                                                    $output .= '<td>
1181
                                                            <a href="../exercise/exercise_show.php?origin='.$origin.'&id='.$my_exe_id.'&cidReq='.$courseCode.'" target="_parent">
1182
                                                            <img src="'.Display::returnIconPath('quiz.png').'" alt="'.get_lang('Show attempt').'" title="'.get_lang('Show attempt').'">
1183
                                                            </a></td>';
1184
                                                }
1185
                                            } else {
1186
                                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
1187
                                                    $output .= '<td>
1188
                                                                <img src="'.Display::returnIconPath('quiz_na.gif').'" alt="'.get_lang('Show and grade attempt').'" title="'.get_lang('Show and grade attempt').'"></td>';
1189
                                                } else {
1190
                                                    $output .= '<td>
1191
                                                                    <a href="../exercise/exercise_show.php?cidReq='.$courseCode.'&origin=correct_exercise_in_lp&id='.$my_exe_id.'" target="_parent">
1192
                                                                    <img src="'.Display::returnIconPath('quiz.gif').'" alt="'.get_lang('Show and grade attempt').'" title="'.get_lang('Show and grade attempt').'"></a></td>';
1193
                                                }
1194
                                            }
1195
                                        }
1196
                                        $output .= '</tr>';
1197
                                        $n++;
1198
                                    }
1199
                                }
1200
                                $output .= '<tr><td colspan="12">&nbsp;</td></tr>';
1201
                            }
1202
                        }
1203
                    }
1204
                }
1205
1206
                $total_time += $time_for_total;
1207
                // QUIZZ IN LP
1208
                $a_my_id = [];
1209
                if (!empty($my_lp_id)) {
1210
                    $a_my_id[] = $my_lp_id;
1211
                }
1212
            }
1213
        }
1214
1215
        // NOT Extend all "left green cross"
1216
        if (!empty($a_my_id)) {
1217
            if ($extendedAttempt) {
1218
                // "Right green cross" extended
1219
                $total_score = self::get_avg_student_score(
1220
                    $user_id,
1221
                    $course_id,
1222
                    $a_my_id,
1223
                    $session_id,
1224
                    false,
1225
                    false
1226
                );
1227
            } else {
1228
                // "Left green cross" extended
1229
                $total_score = self::get_avg_student_score(
1230
                    $user_id,
1231
                    $course_id,
1232
                    $a_my_id,
1233
                    $session_id,
1234
                    false,
1235
                    true
1236
                );
1237
            }
1238
        } else {
1239
            // Extend all "left green cross"
1240
            $total_score = self::get_avg_student_score(
1241
                $user_id,
1242
                $course_id,
1243
                [$lp_id],
1244
                $session_id,
1245
                false,
1246
                false
1247
            );
1248
        }
1249
1250
        $total_time = learnpathItem::getScormTimeFromParameter('js', $total_time);
1251
        $total_time = str_replace('NaN', '00'.$h.'00\'00"', $total_time);
1252
1253
        if (!$is_allowed_to_edit && $result_disabled_ext_all) {
1254
            $final_score = Display::return_icon('invisible.png', get_lang('Results hidden by the exercise setting'));
1255
            $finalScoreToCsv = get_lang('Results hidden by the exercise setting');
1256
        } else {
1257
            if (is_numeric($total_score)) {
1258
                $final_score = $total_score.'%';
1259
            } else {
1260
                $final_score = $total_score;
1261
            }
1262
            $finalScoreToCsv = $final_score;
1263
        }
1264
        $progress = learnpath::getProgress($lp_id, $user_id, $course_id, $session_id);
1265
1266
        $oddclass = 'row_even';
1267
        if (0 == ($counter % 2)) {
1268
            $oddclass = 'row_odd';
1269
        }
1270
1271
        $action = null;
1272
        if ('classic' === $type) {
1273
            $action = '<td></td>';
1274
        }
1275
1276
        $timeTotal = '<td class="lp_time" colspan="2">'.$total_time.'</div>';
1277
        if ($hideTime) {
1278
            $timeTotal = '';
1279
        }
1280
1281
        $output .= '<tr class="'.$oddclass.'">
1282
                <td></td>
1283
                <td colspan="4">
1284
                    <i>'.get_lang('Total of completed learning objects').'</i>
1285
                </td>
1286
                <td colspan="2">'.$progress.'%</td>
1287
                <td colspan="2">'.$final_score.'</td>
1288
                '.$timeTotal.'
1289
                '.$action.'
1290
           </tr>';
1291
1292
        $output .= '
1293
                    </tbody>
1294
                </table>
1295
            </div>
1296
        ';
1297
1298
        if (!empty($export_csv)) {
1299
            $temp = [
1300
                '',
1301
                '',
1302
                '',
1303
                '',
1304
            ];
1305
            $csv_content[] = $temp;
1306
            $temp = [
1307
                get_lang('Total of completed learning objects'),
1308
                '',
1309
                $finalScoreToCsv,
1310
            ];
1311
1312
            if (false === $hideTime) {
1313
                $temp[] = $total_time;
1314
            }
1315
1316
            $csv_content[] = $temp;
1317
            ob_end_clean();
1318
            Export::arrayToCsv($csv_content, 'reporting_learning_path_details');
1319
            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...
1320
        }
1321
1322
        return $output;
1323
    }
1324
1325
    /**
1326
     * @param int  $userId
1327
     * @param bool $getCount
1328
     *
1329
     * @return array
1330
     */
1331
    public static function getStats($userId, $getCount = false)
1332
    {
1333
        $courses = [];
1334
        $assignedCourses = [];
1335
        $drhCount = 0;
1336
        $teachersCount = 0;
1337
        $studentsCount = 0;
1338
        $studentBossCount = 0;
1339
        $courseCount = 0;
1340
        $sessionCount = 0;
1341
        $assignedCourseCount = 0;
1342
1343
        if (api_is_drh() && api_drh_can_access_all_session_content()) {
1344
            $studentList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1345
                'drh_all',
1346
                $userId,
1347
                false,
1348
                null,
1349
                null,
1350
                null,
1351
                null,
1352
                null,
1353
                null,
1354
                null,
1355
                [],
1356
                [],
1357
                STUDENT
1358
            );
1359
1360
            $students = [];
1361
            if (is_array($studentList)) {
1362
                foreach ($studentList as $studentData) {
1363
                    $students[] = $studentData['user_id'];
1364
                }
1365
            }
1366
1367
            $studentBossesList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1368
                'drh_all',
1369
                $userId,
1370
                $getCount,
1371
                null,
1372
                null,
1373
                null,
1374
                null,
1375
                null,
1376
                null,
1377
                null,
1378
                [],
1379
                [],
1380
                STUDENT_BOSS
1381
            );
1382
1383
            if ($getCount) {
1384
                $studentBossCount = $studentBossesList;
1385
            } else {
1386
                $studentBosses = [];
1387
                if (is_array($studentBossesList)) {
1388
                    foreach ($studentBossesList as $studentBossData) {
1389
                        $studentBosses[] = $studentBossData['user_id'];
1390
                    }
1391
                }
1392
            }
1393
1394
            $teacherList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1395
                'drh_all',
1396
                $userId,
1397
                $getCount,
1398
                null,
1399
                null,
1400
                null,
1401
                null,
1402
                null,
1403
                null,
1404
                null,
1405
                [],
1406
                [],
1407
                COURSEMANAGER
1408
            );
1409
1410
            if ($getCount) {
1411
                $teachersCount = $teacherList;
1412
            } else {
1413
                $teachers = [];
1414
                foreach ($teacherList as $teacherData) {
1415
                    $teachers[] = $teacherData['user_id'];
1416
                }
1417
            }
1418
1419
            $humanResources = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1420
                'drh_all',
1421
                $userId,
1422
                $getCount,
1423
                null,
1424
                null,
1425
                null,
1426
                null,
1427
                null,
1428
                null,
1429
                null,
1430
                [],
1431
                [],
1432
                DRH
1433
            );
1434
1435
            if ($getCount) {
1436
                $drhCount = $humanResources;
1437
            } else {
1438
                $humanResourcesList = [];
1439
                if (is_array($humanResources)) {
1440
                    foreach ($humanResources as $item) {
1441
                        $humanResourcesList[] = $item['user_id'];
1442
                    }
1443
                }
1444
            }
1445
1446
            $platformCourses = SessionManager::getAllCoursesFollowedByUser(
1447
                $userId,
1448
                null,
1449
                null,
1450
                null,
1451
                null,
1452
                null,
1453
                $getCount
1454
            );
1455
1456
            if ($getCount) {
1457
                $courseCount = $platformCourses;
1458
            } else {
1459
                foreach ($platformCourses as $course) {
1460
                    $courses[$course['code']] = $course['code'];
1461
                }
1462
            }
1463
1464
            $sessions = SessionManager::get_sessions_followed_by_drh(
1465
                $userId,
1466
                null,
1467
                null,
1468
                false
1469
            );
1470
        } else {
1471
            $studentList = UserManager::getUsersFollowedByUser(
1472
                $userId,
1473
                STUDENT,
1474
                false,
1475
                false,
1476
                false,
1477
                null,
1478
                null,
1479
                null,
1480
                null,
1481
                null,
1482
                null,
1483
                COURSEMANAGER
1484
            );
1485
1486
            $students = [];
1487
            if (is_array($studentList)) {
1488
                foreach ($studentList as $studentData) {
1489
                    $students[] = $studentData['user_id'];
1490
                }
1491
            }
1492
1493
            $studentBossesList = UserManager::getUsersFollowedByUser(
1494
                $userId,
1495
                STUDENT_BOSS,
1496
                false,
1497
                false,
1498
                $getCount,
1499
                null,
1500
                null,
1501
                null,
1502
                null,
1503
                null,
1504
                null,
1505
                COURSEMANAGER
1506
            );
1507
1508
            if ($getCount) {
1509
                $studentBossCount = $studentBossesList;
1510
            } else {
1511
                $studentBosses = [];
1512
                if (is_array($studentBossesList)) {
1513
                    foreach ($studentBossesList as $studentBossData) {
1514
                        $studentBosses[] = $studentBossData['user_id'];
1515
                    }
1516
                }
1517
            }
1518
1519
            $teacherList = UserManager::getUsersFollowedByUser(
1520
                $userId,
1521
                COURSEMANAGER,
1522
                false,
1523
                false,
1524
                $getCount,
1525
                null,
1526
                null,
1527
                null,
1528
                null,
1529
                null,
1530
                null,
1531
                COURSEMANAGER
1532
            );
1533
1534
            if ($getCount) {
1535
                $teachersCount = $teacherList;
1536
            } else {
1537
                $teachers = [];
1538
                foreach ($teacherList as $teacherData) {
1539
                    $teachers[] = $teacherData['user_id'];
1540
                }
1541
            }
1542
1543
            $humanResources = UserManager::getUsersFollowedByUser(
1544
                $userId,
1545
                DRH,
1546
                false,
1547
                false,
1548
                $getCount,
1549
                null,
1550
                null,
1551
                null,
1552
                null,
1553
                null,
1554
                null,
1555
                COURSEMANAGER
1556
            );
1557
1558
            if ($getCount) {
1559
                $drhCount = $humanResources;
1560
            } else {
1561
                $humanResourcesList = [];
1562
                foreach ($humanResources as $item) {
1563
                    $humanResourcesList[] = $item['user_id'];
1564
                }
1565
            }
1566
1567
            $platformCourses = CourseManager::getCoursesFollowedByUser(
1568
                $userId,
1569
                COURSEMANAGER,
1570
                null,
1571
                null,
1572
                null,
1573
                null,
1574
                $getCount,
1575
                null,
1576
                null,
1577
                true
1578
            );
1579
1580
            if ($getCount) {
1581
                $assignedCourseCount = $platformCourses;
1582
            } else {
1583
                foreach ($platformCourses as $course) {
1584
                    $assignedCourses[$course['code']] = $course['code'];
1585
                }
1586
            }
1587
1588
            $platformCourses = CourseManager::getCoursesFollowedByUser(
1589
                $userId,
1590
                COURSEMANAGER,
1591
                null,
1592
                null,
1593
                null,
1594
                null,
1595
                $getCount
1596
            );
1597
1598
            if ($getCount) {
1599
                $courseCount = $platformCourses;
1600
            } else {
1601
                foreach ($platformCourses as $course) {
1602
                    $courses[$course['code']] = $course['code'];
1603
                }
1604
            }
1605
1606
            $sessions = SessionManager::getSessionsFollowedByUser(
1607
                $userId,
1608
                COURSEMANAGER,
1609
                null,
1610
                null,
1611
                false
1612
            );
1613
        }
1614
1615
        if ($getCount) {
1616
            return [
1617
                'drh' => $drhCount,
1618
                'teachers' => $teachersCount,
1619
                'student_count' => count($students),
1620
                'student_list' => $students,
1621
                'student_bosses' => $studentBossCount,
1622
                'courses' => $courseCount,
1623
                'session_count' => count($sessions),
1624
                'session_list' => $sessions,
1625
                'assigned_courses' => $assignedCourseCount,
1626
            ];
1627
        }
1628
1629
        return [
1630
            'drh' => $humanResourcesList,
1631
            'teachers' => $teachers,
1632
            'student_list' => $students,
1633
            'student_bosses' => $studentBosses,
1634
            'courses' => $courses,
1635
            'sessions' => $sessions,
1636
            'assigned_courses' => $assignedCourses,
1637
        ];
1638
    }
1639
1640
    /**
1641
     * Calculates the time spent on the platform by a user.
1642
     *
1643
     * @param int|array $userId
1644
     * @param string    $timeFilter       type of time filter: 'last_week' or 'custom'
1645
     * @param string    $start_date       start date date('Y-m-d H:i:s')
1646
     * @param string    $end_date         end date date('Y-m-d H:i:s')
1647
     * @param bool      $returnAllRecords
1648
     *
1649
     * @return int
1650
     */
1651
    public static function get_time_spent_on_the_platform(
1652
        $userId,
1653
        $timeFilter = 'last_7_days',
1654
        $start_date = null,
1655
        $end_date = null,
1656
        $returnAllRecords = false
1657
    ) {
1658
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1659
        $condition_time = '';
1660
1661
        if (is_array($userId)) {
1662
            $userList = array_map('intval', $userId);
1663
            $userCondition = " login_user_id IN ('".implode("','", $userList)."')";
1664
        } else {
1665
            $userId = (int) $userId;
1666
            $userCondition = " login_user_id = $userId ";
1667
        }
1668
1669
        $url_condition = null;
1670
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1671
        $url_table = null;
1672
        if (api_is_multiple_url_enabled()) {
1673
            $access_url_id = api_get_current_access_url_id();
1674
            $url_table = ", $tbl_url_rel_user as url_users";
1675
            $url_condition = " AND u.login_user_id = url_users.user_id AND access_url_id='$access_url_id'";
1676
        }
1677
1678
        if (empty($timeFilter)) {
1679
            $timeFilter = 'last_week';
1680
        }
1681
1682
        $today = new DateTime('now', new DateTimeZone('UTC'));
1683
1684
        switch ($timeFilter) {
1685
            case 'last_7_days':
1686
                $newDate = new DateTime('-7 day', new DateTimeZone('UTC'));
1687
                $condition_time = " AND (login_date >= '{$newDate->format('Y-m-d H:i:s')}'";
1688
                $condition_time .= " AND logout_date <= '{$today->format('Y-m-d H:i:s')}') ";
1689
                break;
1690
            case 'last_30_days':
1691
                $newDate = new DateTime('-30 days', new DateTimeZone('UTC'));
1692
                $condition_time = " AND (login_date >= '{$newDate->format('Y-m-d H:i:s')}'";
1693
                $condition_time .= "AND logout_date <= '{$today->format('Y-m-d H:i:s')}') ";
1694
                break;
1695
            case 'wide':
1696
                if (!empty($start_date) && !empty($end_date)) {
1697
                    $start_date = Database::escape_string($start_date);
1698
                    $end_date = Database::escape_string($end_date);
1699
                    $condition_time = ' AND (
1700
                        (login_date >= "'.$start_date.'" AND login_date <= "'.$end_date.'") OR
1701
                        (logout_date >= "'.$start_date.'" AND logout_date <= "'.$end_date.'") OR
1702
                        (login_date <= "'.$start_date.'" AND logout_date >= "'.$end_date.'")
1703
                    ) ';
1704
                }
1705
                break;
1706
            case 'custom':
1707
                if (!empty($start_date) && !empty($end_date)) {
1708
                    $start_date = Database::escape_string($start_date);
1709
                    $end_date = Database::escape_string($end_date);
1710
                    $condition_time = ' AND (login_date >= "'.$start_date.'" AND logout_date <= "'.$end_date.'" ) ';
1711
                }
1712
                break;
1713
        }
1714
1715
        if ($returnAllRecords) {
1716
            $sql = "SELECT login_date, logout_date, TIMESTAMPDIFF(SECOND, login_date, logout_date) diff
1717
                    FROM $tbl_track_login u $url_table
1718
                    WHERE $userCondition $condition_time $url_condition
1719
                    ORDER BY login_date";
1720
            $rs = Database::query($sql);
1721
1722
            return Database::store_result($rs, 'ASSOC');
1723
        }
1724
1725
        $sql = "SELECT SUM(TIMESTAMPDIFF(SECOND, login_date, logout_date)) diff
1726
    	        FROM $tbl_track_login u $url_table
1727
                WHERE $userCondition $condition_time $url_condition";
1728
        $rs = Database::query($sql);
1729
        $row = Database::fetch_array($rs, 'ASSOC');
1730
        $diff = $row['diff'];
1731
1732
        if ($diff >= 0) {
1733
            return $diff;
1734
        }
1735
1736
        return -1;
1737
    }
1738
1739
    /**
1740
     * @param string $startDate
1741
     * @param string $endDate
1742
     *
1743
     * @return int
1744
     */
1745
    public static function getTotalTimeSpentOnThePlatform(
1746
        $startDate = '',
1747
        $endDate = ''
1748
    ) {
1749
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1750
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1751
1752
        $url_table = null;
1753
        $url_condition = null;
1754
        if (api_is_multiple_url_enabled()) {
1755
            $access_url_id = api_get_current_access_url_id();
1756
            $url_table = ", ".$tbl_url_rel_user." as url_users";
1757
            $url_condition = " AND u.login_user_id = url_users.user_id AND access_url_id='$access_url_id'";
1758
        }
1759
1760
        if (!empty($startDate) && !empty($endDate)) {
1761
            $startDate = Database::escape_string($startDate);
1762
            $endDate = Database::escape_string($endDate);
1763
            $condition_time = ' (login_date >= "'.$startDate.'" AND logout_date <= "'.$endDate.'" ) ';
1764
        }
1765
        $sql = "SELECT SUM(TIMESTAMPDIFF(SECOND, login_date, logout_date)) diff
1766
    	        FROM $tbl_track_login u $url_table
1767
                WHERE $condition_time $url_condition";
1768
        $rs = Database::query($sql);
1769
        $row = Database::fetch_array($rs, 'ASSOC');
1770
        $diff = $row['diff'];
1771
1772
        if ($diff >= 0) {
1773
            return $diff;
1774
        }
1775
1776
        return -1;
1777
    }
1778
1779
    /**
1780
     * Checks if the "lp_minimum_time" feature is available for the course.
1781
     *
1782
     * @param int $sessionId
1783
     * @param int $courseId
1784
     *
1785
     * @return bool
1786
     */
1787
    public static function minimumTimeAvailable($sessionId, $courseId)
1788
    {
1789
        if (!api_get_configuration_value('lp_minimum_time')) {
1790
            return false;
1791
        }
1792
1793
        if (!empty($sessionId)) {
1794
            $extraFieldValue = new ExtraFieldValue('session');
1795
            $value = $extraFieldValue->get_values_by_handler_and_field_variable($sessionId, 'new_tracking_system');
1796
1797
            if ($value && isset($value['value']) && 1 == $value['value']) {
1798
                return true;
1799
            }
1800
        } else {
1801
            if ($courseId) {
1802
                $extraFieldValue = new ExtraFieldValue('course');
1803
                $value = $extraFieldValue->get_values_by_handler_and_field_variable($courseId, 'new_tracking_system');
1804
                if ($value && isset($value['value']) && 1 == $value['value']) {
1805
                    return true;
1806
                }
1807
            }
1808
        }
1809
1810
        return false;
1811
    }
1812
1813
    /**
1814
     * Calculates the time spent on the course.
1815
     *
1816
     * @param int $user_id
1817
     * @param int $courseId
1818
     * @param int $session_id
1819
     *
1820
     * @return int Time in seconds
1821
     */
1822
    public static function get_time_spent_on_the_course(
1823
        $user_id,
1824
        $courseId,
1825
        $session_id = 0
1826
    ) {
1827
        $courseId = (int) $courseId;
1828
1829
        if (empty($courseId) || empty($user_id)) {
1830
            return 0;
1831
        }
1832
1833
        if (self::minimumTimeAvailable($session_id, $courseId)) {
1834
            $courseTime = self::getCalculateTime($user_id, $courseId, $session_id);
1835
1836
            return isset($courseTime['total_time']) ? $courseTime['total_time'] : 0;
1837
        }
1838
1839
        $conditionUser = '';
1840
        $session_id = (int) $session_id;
1841
        if (is_array($user_id)) {
1842
            $user_id = array_map('intval', $user_id);
1843
            $conditionUser = " AND user_id IN (".implode(',', $user_id).") ";
1844
        } else {
1845
            if (!empty($user_id)) {
1846
                $user_id = (int) $user_id;
1847
                $conditionUser = " AND user_id = $user_id ";
1848
            }
1849
        }
1850
1851
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1852
        $sql = "SELECT
1853
                SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as nb_seconds
1854
                FROM $table
1855
                WHERE
1856
                    UNIX_TIMESTAMP(logout_course_date) > UNIX_TIMESTAMP(login_course_date) AND
1857
                    c_id = '$courseId' ";
1858
1859
        if (-1 != $session_id) {
1860
            $sql .= "AND session_id = '$session_id' ";
1861
        }
1862
1863
        $sql .= $conditionUser;
1864
1865
        $rs = Database::query($sql);
1866
        $row = Database::fetch_array($rs);
1867
1868
        return $row['nb_seconds'];
1869
    }
1870
1871
    /**
1872
     * Get first connection date for a student.
1873
     *
1874
     * @param int $student_id
1875
     *
1876
     * @return string|bool Date format long without day or false if there are no connections
1877
     */
1878
    public static function get_first_connection_date($student_id)
1879
    {
1880
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1881
        $sql = 'SELECT login_date
1882
                FROM '.$table.'
1883
                WHERE login_user_id = '.intval($student_id).'
1884
                ORDER BY login_date ASC
1885
                LIMIT 0,1';
1886
1887
        $rs = Database::query($sql);
1888
        if (Database::num_rows($rs) > 0) {
1889
            if ($first_login_date = Database::result($rs, 0, 0)) {
1890
                return api_convert_and_format_date(
1891
                    $first_login_date,
1892
                    DATE_FORMAT_SHORT
1893
                );
1894
            }
1895
        }
1896
1897
        return false;
1898
    }
1899
1900
    /**
1901
     * Get las connection date for a student.
1902
     *
1903
     * @param int  $student_id
1904
     * @param bool $warning_message  Show a warning message (optional)
1905
     * @param bool $return_timestamp True for returning results in timestamp (optional)
1906
     *
1907
     * @return string|int|bool Date format long without day, false if there are no connections or
1908
     *                         timestamp if parameter $return_timestamp is true
1909
     */
1910
    public static function get_last_connection_date(
1911
        $student_id,
1912
        $warning_message = false,
1913
        $return_timestamp = false
1914
    ) {
1915
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1916
        $sql = 'SELECT login_date
1917
                FROM '.$table.'
1918
                WHERE login_user_id = '.intval($student_id).'
1919
                ORDER BY login_date
1920
                DESC LIMIT 0,1';
1921
1922
        $rs = Database::query($sql);
1923
        if (Database::num_rows($rs) > 0) {
1924
            if ($last_login_date = Database::result($rs, 0, 0)) {
1925
                $last_login_date = api_get_local_time($last_login_date);
1926
                if ($return_timestamp) {
1927
                    return api_strtotime($last_login_date, 'UTC');
1928
                } else {
1929
                    if (!$warning_message) {
1930
                        return api_format_date($last_login_date, DATE_FORMAT_SHORT);
1931
                    } else {
1932
                        $timestamp = api_strtotime($last_login_date, 'UTC');
1933
                        $currentTimestamp = time();
1934
1935
                        //If the last connection is > than 7 days, the text is red
1936
                        //345600 = 7 days in seconds
1937
                        if ($currentTimestamp - $timestamp > 604800) {
1938
                            return '<span style="color: #F00;">'.api_format_date($last_login_date, DATE_FORMAT_SHORT).'</span>';
1939
                        } else {
1940
                            return api_format_date($last_login_date, DATE_FORMAT_SHORT);
1941
                        }
1942
                    }
1943
                }
1944
            }
1945
        }
1946
1947
        return false;
1948
    }
1949
1950
    /**
1951
     * Get first user's connection date on the course.
1952
     *
1953
     * @param int User id
1954
     * @param int $courseId
1955
     * @param int Session id (optional, default=0)
1956
     * @param bool $convert_date
1957
     *
1958
     * @return string|bool Date with format long without day or false if there is no date
1959
     */
1960
    public static function get_first_connection_date_on_the_course(
1961
        $student_id,
1962
        $courseId,
1963
        $session_id = 0,
1964
        $convert_date = true
1965
    ) {
1966
        $student_id = (int) $student_id;
1967
        $courseId = (int) $courseId;
1968
        $session_id = (int) $session_id;
1969
1970
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1971
        $sql = 'SELECT login_course_date
1972
                FROM '.$table.'
1973
                WHERE
1974
                    user_id = '.$student_id.' AND
1975
                    c_id = '.$courseId.' AND
1976
                    session_id = '.$session_id.'
1977
                ORDER BY login_course_date ASC
1978
                LIMIT 0,1';
1979
        $rs = Database::query($sql);
1980
        if (Database::num_rows($rs) > 0) {
1981
            if ($first_login_date = Database::result($rs, 0, 0)) {
1982
                if (empty($first_login_date)) {
1983
                    return false;
1984
                }
1985
1986
                if ($convert_date) {
1987
                    return api_convert_and_format_date(
1988
                        $first_login_date,
1989
                        DATE_FORMAT_SHORT
1990
                    );
1991
                }
1992
1993
                return $first_login_date;
1994
            }
1995
        }
1996
1997
        return false;
1998
    }
1999
2000
    /**
2001
     * Get last user's connection date on the course.
2002
     *
2003
     * @param     int         User id
2004
     * @param array $courseInfo real_id and code are used
2005
     * @param    int            Session id (optional, default=0)
2006
     * @param bool $convert_date
2007
     *
2008
     * @return string|bool Date with format long without day or false if there is no date
2009
     */
2010
    public static function get_last_connection_date_on_the_course(
2011
        $student_id,
2012
        $courseInfo,
2013
        $session_id = 0,
2014
        $convert_date = true
2015
    ) {
2016
        // protect data
2017
        $student_id = (int) $student_id;
2018
        $session_id = (int) $session_id;
2019
2020
        if (empty($courseInfo) || empty($student_id)) {
2021
            return false;
2022
        }
2023
2024
        $courseId = $courseInfo['real_id'];
2025
2026
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2027
2028
        if (self::minimumTimeAvailable($session_id, $courseId)) {
2029
            // Show the last date on which the user acceed the session when it was active
2030
            $where_condition = '';
2031
            $userInfo = api_get_user_info($student_id);
2032
            if (STUDENT == $userInfo['status'] && !empty($session_id)) {
2033
                // fin de acceso a la sesión
2034
                $sessionInfo = SessionManager::fetch($session_id);
2035
                $last_access = $sessionInfo['access_end_date'];
2036
                if (!empty($last_access)) {
2037
                    $where_condition = ' AND logout_course_date < "'.$last_access.'" ';
2038
                }
2039
            }
2040
            $sql = "SELECT logout_course_date
2041
                    FROM $table
2042
                    WHERE   user_id = $student_id AND
2043
                            c_id = $courseId AND
2044
                            session_id = $session_id $where_condition
2045
                    ORDER BY logout_course_date DESC
2046
                    LIMIT 0,1";
2047
2048
            $rs = Database::query($sql);
2049
            if (Database::num_rows($rs) > 0) {
2050
                if ($last_login_date = Database::result($rs, 0, 0)) {
2051
                    if (empty($last_login_date)) {
2052
                        return false;
2053
                    }
2054
                    if ($convert_date) {
2055
                        return api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
2056
                    }
2057
2058
                    return $last_login_date;
2059
                }
2060
            }
2061
        } else {
2062
            $sql = "SELECT logout_course_date
2063
                    FROM $table
2064
                    WHERE   user_id = $student_id AND
2065
                            c_id = $courseId AND
2066
                            session_id = $session_id
2067
                    ORDER BY logout_course_date DESC
2068
                    LIMIT 0,1";
2069
2070
            $rs = Database::query($sql);
2071
            if (Database::num_rows($rs) > 0) {
2072
                if ($last_login_date = Database::result($rs, 0, 0)) {
2073
                    if (empty($last_login_date)) {
2074
                        return false;
2075
                    }
2076
                    //see #5736
2077
                    $last_login_date_timestamp = api_strtotime($last_login_date);
2078
                    $now = time();
2079
                    //If the last connection is > than 7 days, the text is red
2080
                    //345600 = 7 days in seconds
2081
                    if ($now - $last_login_date_timestamp > 604800) {
2082
                        if ($convert_date) {
2083
                            $last_login_date = api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
2084
                            $icon = null;
2085
                            if (api_is_allowed_to_edit()) {
2086
                                $url = api_get_path(WEB_CODE_PATH).
2087
                                    'announcements/announcements.php?action=add&remind_inactive='.$student_id.'&cidReq='.$courseInfo['code'];
2088
                                $icon = '<a href="'.$url.'" title="'.get_lang('Remind inactive user').'">
2089
                                  '.Display::return_icon('messagebox_warning.gif').'
2090
                                 </a>';
2091
                            }
2092
2093
                            return $icon.Display::label($last_login_date, 'warning');
2094
                        }
2095
2096
                        return $last_login_date;
2097
                    } else {
2098
                        if ($convert_date) {
2099
                            return api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
2100
                        }
2101
2102
                        return $last_login_date;
2103
                    }
2104
                }
2105
            }
2106
        }
2107
2108
        return false;
2109
    }
2110
2111
    public static function getLastConnectionInAnyCourse($studentId)
2112
    {
2113
        $studentId = (int) $studentId;
2114
2115
        if (empty($studentId)) {
2116
            return false;
2117
        }
2118
2119
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2120
        $sql = "SELECT logout_course_date
2121
                FROM $table
2122
                WHERE user_id = $studentId
2123
                ORDER BY logout_course_date DESC
2124
                LIMIT 1";
2125
        $result = Database::query($sql);
2126
        if (Database::num_rows($result)) {
2127
            $row = Database::fetch_array($result);
2128
2129
            return $row['logout_course_date'];
2130
        }
2131
2132
        return false;
2133
    }
2134
    /**
2135
     * Get last course access by course/session.
2136
     */
2137
    public static function getLastConnectionDateByCourse($courseId, $sessionId = 0)
2138
    {
2139
        $courseId = (int) $courseId;
2140
        $sessionId = (int) $sessionId;
2141
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2142
2143
        $sql = "SELECT logout_course_date
2144
                FROM $table
2145
                WHERE
2146
                        c_id = $courseId AND
2147
                        session_id = $sessionId
2148
                ORDER BY logout_course_date DESC
2149
                LIMIT 0,1";
2150
2151
        $result = Database::query($sql);
2152
        if (Database::num_rows($result)) {
2153
            $row = Database::fetch_array($result);
2154
            if ($row) {
2155
                return $row['logout_course_date'];
2156
            }
2157
        }
2158
2159
        return '';
2160
    }
2161
2162
    /**
2163
     * Get count of the connections to the course during a specified period.
2164
     *
2165
     * @param int $courseId
2166
     * @param   int     Session id (optional)
2167
     * @param   int     Datetime from which to collect data (defaults to 0)
2168
     * @param   int     Datetime to which to collect data (defaults to now)
2169
     *
2170
     * @return int count connections
2171
     */
2172
    public static function get_course_connections_count(
2173
        $courseId,
2174
        $session_id = 0,
2175
        $start = 0,
2176
        $stop = null
2177
    ) {
2178
        if ($start < 0) {
2179
            $start = 0;
2180
        }
2181
        if (!isset($stop) || $stop < 0) {
2182
            $stop = api_get_utc_datetime();
2183
        }
2184
2185
        // Given we're storing in cache, round the start and end times
2186
        // to the lower minute
2187
        $roundedStart = substr($start, 0, -2).'00';
2188
        $roundedStop = substr($stop, 0, -2).'00';
2189
        $roundedStart = Database::escape_string($roundedStart);
2190
        $roundedStop = Database::escape_string($roundedStop);
2191
        $month_filter = " AND login_course_date > '$roundedStart' AND login_course_date < '$roundedStop' ";
2192
        $courseId = (int) $courseId;
2193
        $session_id = (int) $session_id;
2194
        $count = 0;
2195
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2196
        $sql = "SELECT count(*) as count_connections
2197
                FROM $table
2198
                WHERE
2199
                    c_id = $courseId AND
2200
                    session_id = $session_id
2201
                    $month_filter";
2202
2203
        //This query can be very slow (several seconds on an indexed table
2204
        // with 14M rows). As such, we'll try to use APCu if it is
2205
        // available to store the resulting value for a few seconds
2206
        $cacheAvailable = api_get_configuration_value('apc');
2207
        if (true === $cacheAvailable) {
2208
            $apc = apcu_cache_info(true);
2209
            $apc_end = $apc['start_time'] + $apc['ttl'];
2210
            $apc_var = api_get_configuration_value('apc_prefix').'course_access_'.$courseId.'_'.$session_id.'_'.strtotime($roundedStart).'_'.strtotime($roundedStop);
2211
            if (apcu_exists($apc_var) && (time() < $apc_end) &&
2212
                apcu_fetch($apc_var) > 0
2213
            ) {
2214
                $count = apcu_fetch($apc_var);
2215
            } else {
2216
                $rs = Database::query($sql);
2217
                if (Database::num_rows($rs) > 0) {
2218
                    $row = Database::fetch_object($rs);
2219
                    $count = $row->count_connections;
2220
                }
2221
                apcu_clear_cache();
2222
                apcu_store($apc_var, $count, 60);
2223
            }
2224
        } else {
2225
            $rs = Database::query($sql);
2226
            if (Database::num_rows($rs) > 0) {
2227
                $row = Database::fetch_object($rs);
2228
                $count = $row->count_connections;
2229
            }
2230
        }
2231
2232
        return $count;
2233
    }
2234
2235
    /**
2236
     * Get count courses per student.
2237
     *
2238
     * @param int  $user_id          Student id
2239
     * @param bool $include_sessions Include sessions (optional)
2240
     *
2241
     * @return int count courses
2242
     */
2243
    public static function count_course_per_student($user_id, $include_sessions = true)
2244
    {
2245
        $user_id = (int) $user_id;
2246
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2247
        $tbl_session_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2248
2249
        $sql = 'SELECT DISTINCT c_id
2250
                FROM '.$tbl_course_rel_user.'
2251
                WHERE user_id = '.$user_id.' AND relation_type<>'.COURSE_RELATION_TYPE_RRHH;
2252
        $rs = Database::query($sql);
2253
        $nb_courses = Database::num_rows($rs);
2254
2255
        if ($include_sessions) {
2256
            $sql = 'SELECT DISTINCT c_id
2257
                    FROM '.$tbl_session_course_rel_user.'
2258
                    WHERE user_id = '.$user_id;
2259
            $rs = Database::query($sql);
2260
            $nb_courses += Database::num_rows($rs);
2261
        }
2262
2263
        return $nb_courses;
2264
    }
2265
2266
    /**
2267
     * Gets the score average from all tests in a course by student.
2268
     *
2269
     * @param $student_id
2270
     * @param $course_code
2271
     * @param int  $exercise_id
2272
     * @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...
2273
     * @param int  $active_filter 2 for consider all tests
2274
     *                            1 for active <> -1
2275
     *                            0 for active <> 0
2276
     * @param int  $into_lp       1 for all exercises
2277
     *                            0 for without LP
2278
     * @param mixed id
2279
     * @param string code
2280
     * @param int id (optional), filtered by exercise
2281
     * @param int id (optional), if param $session_id is null
2282
     *                                                it'll return results including sessions, 0 = session is not filtered
2283
     *
2284
     * @return string value (number %) Which represents a round integer about the score average
2285
     */
2286
    public static function get_avg_student_exercise_score(
2287
        $student_id,
2288
        $course_code,
2289
        $exercise_id = 0,
2290
        $session_id = null,
2291
        $active_filter = 1,
2292
        $into_lp = 0
2293
    ) {
2294
        $course_code = Database::escape_string($course_code);
2295
        $course_info = api_get_course_info($course_code);
2296
        if (!empty($course_info)) {
2297
            // table definition
2298
            $tbl_course_quiz = Database::get_course_table(TABLE_QUIZ_TEST);
2299
            $tbl_stats_exercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2300
2301
            // Compose a filter based on optional exercise given
2302
            $condition_quiz = '';
2303
            if (!empty($exercise_id)) {
2304
                $exercise_id = (int) $exercise_id;
2305
                $condition_quiz = " AND iid = $exercise_id ";
2306
            }
2307
2308
            // Compose a filter based on optional session id given
2309
            $condition_session = '';
2310
            if (isset($session_id)) {
2311
                $session_id = (int) $session_id;
2312
                $condition_session = " AND session_id = $session_id ";
2313
            }
2314
            if (1 == $active_filter) {
2315
                $condition_active = 'AND active <> -1';
2316
            } elseif (0 == $active_filter) {
2317
                $condition_active = 'AND active <> 0';
2318
            } else {
2319
                $condition_active = '';
2320
            }
2321
            $condition_into_lp = '';
2322
            $select_lp_id = '';
2323
            if (0 == $into_lp) {
2324
                $condition_into_lp = 'AND orig_lp_id = 0 AND orig_lp_item_id = 0';
2325
            } else {
2326
                $select_lp_id = ', orig_lp_id as lp_id ';
2327
            }
2328
2329
            $sql = "SELECT count(iid)
2330
    		        FROM $tbl_course_quiz
2331
    				WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz ";
2332
            $count_quiz = 0;
2333
2334
            $countQuizResult = Database::query($sql);
2335
            if (!empty($countQuizResult)) {
2336
                $count_quiz = Database::fetch_row($countQuizResult);
2337
            }
2338
2339
            if (!empty($count_quiz[0]) && !empty($student_id)) {
2340
                if (is_array($student_id)) {
2341
                    $student_id = array_map('intval', $student_id);
2342
                    $condition_user = " AND exe_user_id IN (".implode(',', $student_id).") ";
2343
                } else {
2344
                    $student_id = (int) $student_id;
2345
                    $condition_user = " AND exe_user_id = '$student_id' ";
2346
                }
2347
2348
                if (empty($exercise_id)) {
2349
                    $sql = "SELECT iid FROM $tbl_course_quiz
2350
                            WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz";
2351
                    $result = Database::query($sql);
2352
                    $exercise_list = [];
2353
                    $exercise_id = null;
2354
                    if (!empty($result) && Database::num_rows($result)) {
2355
                        while ($row = Database::fetch_array($result)) {
2356
                            $exercise_list[] = $row['iid'];
2357
                        }
2358
                    }
2359
                    if (!empty($exercise_list)) {
2360
                        $exercise_id = implode("','", $exercise_list);
2361
                    }
2362
                }
2363
2364
                $count_quiz = Database::fetch_row(Database::query($sql));
2365
                $sql = "SELECT
2366
                        SUM(score/max_score*100) as avg_score,
2367
                        COUNT(*) as num_attempts
2368
                        $select_lp_id
2369
                        FROM $tbl_stats_exercise
2370
                        WHERE
2371
                            exe_exo_id IN ('".$exercise_id."')
2372
                            $condition_user AND
2373
                            status = '' AND
2374
                            c_id = {$course_info['real_id']}
2375
                            $condition_session
2376
                            $condition_into_lp
2377
                        ORDER BY exe_date DESC";
2378
2379
                $res = Database::query($sql);
2380
                $row = Database::fetch_array($res);
2381
                $quiz_avg_score = null;
2382
2383
                if (!empty($row['avg_score'])) {
2384
                    $quiz_avg_score = round($row['avg_score'], 2);
2385
                }
2386
2387
                if (!empty($row['num_attempts'])) {
2388
                    $quiz_avg_score = round($quiz_avg_score / $row['num_attempts'], 2);
2389
                }
2390
                if (is_array($student_id)) {
2391
                    $quiz_avg_score = round($quiz_avg_score / count($student_id), 2);
2392
                }
2393
                if (0 == $into_lp) {
2394
                    return $quiz_avg_score;
2395
                } else {
2396
                    if (!empty($row['lp_id'])) {
2397
                        $tbl_lp = Database::get_course_table(TABLE_LP_MAIN);
2398
                        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2399
                        $sql = "SELECT lp.name
2400
                                FROM $tbl_lp as lp, $tbl_course as c
2401
                                WHERE
2402
                                    c.code = '$course_code' AND
2403
                                    lp.iid = ".$row['lp_id']." AND
2404
                                    lp.c_id = c.id
2405
                                LIMIT 1;
2406
                        ";
2407
                        $result = Database::query($sql);
2408
                        $row_lp = Database::fetch_row($result);
2409
                        $lp_name = $row_lp[0];
2410
2411
                        return [$quiz_avg_score, $lp_name];
2412
                    }
2413
2414
                    return [$quiz_avg_score, null];
2415
                }
2416
            }
2417
        }
2418
2419
        return null;
2420
    }
2421
2422
    /**
2423
     * Get count student's exercise COMPLETED attempts.
2424
     *
2425
     * @param int $student_id
2426
     * @param int $courseId
2427
     * @param int $exercise_id
2428
     * @param int $lp_id
2429
     * @param int $lp_item_id
2430
     * @param int $session_id
2431
     * @param int $find_all_lp 0 = just LP specified
2432
     *                         1 = LP specified or whitout LP,
2433
     *                         2 = all rows
2434
     *
2435
     * @internal param \Student $int id
2436
     * @internal param \Course $string code
2437
     * @internal param \Exercise $int id
2438
     * @internal param \Learning $int path id (optional),
2439
     * for showing attempts inside a learning path $lp_id and $lp_item_id params are required
2440
     * @internal param \Learning $int path item id (optional),
2441
     * for showing attempts inside a learning path $lp_id and $lp_item_id params are required
2442
     *
2443
     * @return int count of attempts
2444
     */
2445
    public static function count_student_exercise_attempts(
2446
        $student_id,
2447
        $courseId,
2448
        $exercise_id,
2449
        $lp_id = 0,
2450
        $lp_item_id = 0,
2451
        $session_id = 0,
2452
        $find_all_lp = 0
2453
    ) {
2454
        $courseId = intval($courseId);
2455
        $student_id = intval($student_id);
2456
        $exercise_id = intval($exercise_id);
2457
        $session_id = intval($session_id);
2458
2459
        $lp_id = intval($lp_id);
2460
        $lp_item_id = intval($lp_item_id);
2461
        $tbl_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2462
2463
        $sql = "SELECT COUNT(ex.exe_id) as essais
2464
                FROM $tbl_stats_exercises AS ex
2465
                WHERE
2466
                    ex.c_id = $courseId AND
2467
                    ex.exe_exo_id = $exercise_id AND
2468
                    status = '' AND
2469
                    exe_user_id= $student_id AND
2470
                    session_id = $session_id ";
2471
2472
        if (1 == $find_all_lp) {
2473
            $sql .= "AND (orig_lp_id = $lp_id OR orig_lp_id = 0)
2474
                AND (orig_lp_item_id = $lp_item_id OR orig_lp_item_id = 0)";
2475
        } elseif (0 == $find_all_lp) {
2476
            $sql .= "AND orig_lp_id = $lp_id
2477
                AND orig_lp_item_id = $lp_item_id";
2478
        }
2479
2480
        $rs = Database::query($sql);
2481
        $row = Database::fetch_row($rs);
2482
        $count_attempts = $row[0];
2483
2484
        return $count_attempts;
2485
    }
2486
2487
    /**
2488
     * Get count student's exercise progress.
2489
     *
2490
     * @param array $exercise_list
2491
     * @param int   $user_id
2492
     * @param int   $courseId
2493
     * @param int   $session_id
2494
     *
2495
     * @return string
2496
     */
2497
    public static function get_exercise_student_progress(
2498
        $exercise_list,
2499
        $user_id,
2500
        $courseId,
2501
        $session_id
2502
    ) {
2503
        $courseId = (int) $courseId;
2504
        $user_id = (int) $user_id;
2505
        $session_id = (int) $session_id;
2506
2507
        if (empty($exercise_list)) {
2508
            return '0%';
2509
        }
2510
        $tbl_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2511
        $exercise_list = array_keys($exercise_list);
2512
        $exercise_list = array_map('intval', $exercise_list);
2513
2514
        $exercise_list_imploded = implode("' ,'", $exercise_list);
2515
2516
        $sql = "SELECT COUNT(DISTINCT ex.exe_exo_id)
2517
                FROM $tbl_stats_exercises AS ex
2518
                WHERE
2519
                    ex.c_id = $courseId AND
2520
                    ex.session_id  = $session_id AND
2521
                    ex.exe_user_id = $user_id AND
2522
                    ex.status = '' AND
2523
                    ex.exe_exo_id IN ('$exercise_list_imploded') ";
2524
2525
        $rs = Database::query($sql);
2526
        $count = 0;
2527
        if ($rs) {
2528
            $row = Database::fetch_row($rs);
2529
            $count = $row[0];
2530
        }
2531
        $count = (0 != $count) ? 100 * round(intval($count) / count($exercise_list), 2).'%' : '0%';
2532
2533
        return $count;
2534
    }
2535
2536
    /**
2537
     * @param array $exercise_list
2538
     * @param int   $user_id
2539
     * @param int   $courseId
2540
     * @param int   $session_id
2541
     *
2542
     * @return string
2543
     */
2544
    public static function get_exercise_student_average_best_attempt(
2545
        $exercise_list,
2546
        $user_id,
2547
        $courseId,
2548
        $session_id
2549
    ) {
2550
        $result = 0;
2551
        if (!empty($exercise_list)) {
2552
            foreach ($exercise_list as $exercise_data) {
2553
                $exercise_id = $exercise_data['iid'];
2554
                $best_attempt = Event::get_best_attempt_exercise_results_per_user(
2555
                    $user_id,
2556
                    $exercise_id,
2557
                    $courseId,
2558
                    $session_id
2559
                );
2560
2561
                if (!empty($best_attempt) && !empty($best_attempt['max_score'])) {
2562
                    $result += $best_attempt['score'] / $best_attempt['max_score'];
2563
                }
2564
            }
2565
            $result = $result / count($exercise_list);
2566
            $result = round($result, 2) * 100;
2567
        }
2568
2569
        return $result.'%';
2570
    }
2571
2572
    /**
2573
     * Returns the average student progress in the learning paths of the given
2574
     * course, it will take into account the progress that were not started.
2575
     *
2576
     * @param int|array $studentId
2577
     * @param string    $courseCode
2578
     * @param array     $lpIdList        Limit average to listed lp ids
2579
     * @param int       $sessionId       Session id (optional),
2580
     *                                   if parameter $session_id is null(default) it'll return results including
2581
     *                                   sessions, 0 = session is not filtered
2582
     * @param bool      $returnArray     Will return an array of the type:
2583
     *                                   [sum_of_progresses, number] if it is set to true
2584
     * @param bool      $onlySeriousGame Optional. Limit average to lp on seriousgame mode
2585
     *
2586
     * @return float Average progress of the user in this course from 0 to 100
2587
     */
2588
    public static function get_avg_student_progress(
2589
        $studentId,
2590
        $courseCode = null,
2591
        $lpIdList = [],
2592
        $sessionId = null,
2593
        $returnArray = false,
2594
        $onlySeriousGame = false
2595
    ) {
2596
        // If there is at least one learning path and one student.
2597
        if (empty($studentId)) {
2598
            return false;
2599
        }
2600
2601
        $sessionId = (int) $sessionId;
2602
        $courseInfo = api_get_course_info($courseCode);
2603
2604
        if (empty($courseInfo)) {
2605
            return false;
2606
        }
2607
2608
        $lPTable = Database::get_course_table(TABLE_LP_MAIN);
2609
        $lpViewTable = Database::get_course_table(TABLE_LP_VIEW);
2610
        $lpConditions = [];
2611
        $lpConditions['c_id = ? '] = $courseInfo['real_id'];
2612
2613
        if ($sessionId > 0) {
2614
            $lpConditions['AND (session_id = ? OR session_id = 0 OR session_id IS NULL)'] = $sessionId;
2615
        } else {
2616
            $lpConditions['AND session_id = ?'] = $sessionId;
2617
        }
2618
2619
        if (is_array($lpIdList) && count($lpIdList) > 0) {
2620
            $placeHolders = [];
2621
            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...
2622
                $placeHolders[] = '?';
2623
            }
2624
            $lpConditions['AND iid IN('.implode(', ', $placeHolders).') '] = $lpIdList;
2625
        }
2626
2627
        if ($onlySeriousGame) {
2628
            $lpConditions['AND seriousgame_mode = ? '] = true;
2629
        }
2630
2631
        $resultLP = Database::select(
2632
            'iid',
2633
            $lPTable,
2634
            ['where' => $lpConditions]
2635
        );
2636
        $filteredLP = array_keys($resultLP);
2637
2638
        if (empty($filteredLP)) {
2639
            return false;
2640
        }
2641
2642
        $conditions = [
2643
            " c_id = {$courseInfo['real_id']} ",
2644
            " lp_view.lp_id IN (".implode(', ', $filteredLP).") ",
2645
        ];
2646
2647
        $groupBy = 'GROUP BY lp_id';
2648
2649
        if (is_array($studentId)) {
2650
            $studentId = array_map('intval', $studentId);
2651
            $conditions[] = " lp_view.user_id IN (".implode(',', $studentId).")  ";
2652
        } else {
2653
            $studentId = (int) $studentId;
2654
            $conditions[] = " lp_view.user_id = '$studentId' ";
2655
2656
            if (empty($lpIdList)) {
2657
                $lpList = new LearnpathList(
2658
                    $studentId,
2659
                    $courseInfo,
2660
                    $sessionId,
2661
                    null,
2662
                    false,
2663
                    null,
2664
                    true
2665
                );
2666
                $lpList = $lpList->get_flat_list();
2667
                if (!empty($lpList)) {
2668
                    /** @var $lp */
2669
                    foreach ($lpList as $lpId => $lp) {
2670
                        $lpIdList[] = $lp['lp_old_id'];
2671
                    }
2672
                }
2673
            }
2674
        }
2675
2676
        if (!empty($sessionId)) {
2677
            $conditions[] = " session_id = $sessionId ";
2678
        } else {
2679
            $conditions[] = ' (session_id = 0 OR session_id IS NULL) ';
2680
        }
2681
2682
        $conditionToString = implode('AND', $conditions);
2683
        $sql = "SELECT lp_id, view_count, progress
2684
                FROM $lpViewTable lp_view
2685
                WHERE
2686
                    $conditionToString
2687
                    $groupBy
2688
                ORDER BY view_count DESC";
2689
2690
        $result = Database::query($sql);
2691
2692
        $progress = [];
2693
        $viewCount = [];
2694
        while ($row = Database::fetch_array($result, 'ASSOC')) {
2695
            if (!isset($viewCount[$row['lp_id']])) {
2696
                $progress[$row['lp_id']] = $row['progress'];
2697
            }
2698
            $viewCount[$row['lp_id']] = $row['view_count'];
2699
        }
2700
2701
        // Fill with lp ids
2702
        $newProgress = [];
2703
        if (!empty($lpIdList)) {
2704
            foreach ($lpIdList as $lpId) {
2705
                if (isset($progress[$lpId])) {
2706
                    $newProgress[] = $progress[$lpId];
2707
                }
2708
            }
2709
            $total = count($lpIdList);
2710
        } else {
2711
            $newProgress = $progress;
2712
            $total = count($newProgress);
2713
        }
2714
2715
        $average = 0;
2716
        $sum = 0;
2717
        if (!empty($newProgress)) {
2718
            $sum = array_sum($newProgress);
2719
            $average = $sum / $total;
2720
        }
2721
2722
        if ($returnArray) {
2723
            return [
2724
                $sum,
2725
                $total,
2726
            ];
2727
        }
2728
2729
        return round($average, 1);
2730
    }
2731
2732
    /**
2733
     * This function gets:
2734
     * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores.
2735
     * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores.
2736
     * 3. And finally it will return the average between 1. and 2.
2737
     *
2738
     * @todo improve performance, when loading 1500 users with 20 lps the script dies
2739
     * This function does not take the results of a Test out of a LP
2740
     *
2741
     * @param mixed  $student_id                      Array of user ids or an user id
2742
     * @param string $course_code
2743
     * @param array  $lp_ids                          List of LP ids
2744
     * @param int    $session_id                      Session id (optional),
2745
     *                                                if param $session_id is null(default) it'll return results
2746
     *                                                including sessions, 0 = session is not filtered
2747
     * @param bool   $return_array                    Returns an array of the
2748
     *                                                type [sum_score, num_score] if set to true
2749
     * @param bool   $get_only_latest_attempt_results get only the latest attempts or ALL attempts
2750
     * @param bool   $getOnlyBestAttempt
2751
     *
2752
     * @return string value (number %) Which represents a round integer explain in got in 3
2753
     */
2754
    public static function get_avg_student_score(
2755
        $student_id,
2756
        $course_code,
2757
        $lp_ids = [],
2758
        $session_id = null,
2759
        $return_array = false,
2760
        $get_only_latest_attempt_results = false,
2761
        $getOnlyBestAttempt = false
2762
    ) {
2763
        $debug = false;
2764
        if ($debug) {
2765
            echo '<h1>Tracking::get_avg_student_score</h1>';
2766
        }
2767
        $tbl_stats_exercices = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2768
        $tbl_stats_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
2769
        $course = api_get_course_info($course_code);
2770
2771
        if (empty($course)) {
2772
            return null;
2773
        }
2774
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 iid IN(".implode(',', $lp_ids).") ";
2787
        }
2788
2789
        // Compose a filter based on optional session id
2790
        $session_id = (int) $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(iid), 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(iid), 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['iid'];
2817
            $use_max_score[$row_lp['iid']] = $row_lp['use_max_score'];
2818
        }
2819
2820
        // prepare filter on users
2821
        if (is_array($student_id)) {
2822
            array_walk($student_id, 'intval');
2823
            $condition_user1 = " AND user_id IN (".implode(',', $student_id).") ";
2824
        } else {
2825
            $condition_user1 = " AND user_id = $student_id ";
2826
        }
2827
2828
        if (empty($count_row_lp) || empty($student_id)) {
2829
            return null;
2830
        }
2831
2832
        // Getting latest LP result for a student
2833
        //@todo problem when a  course have more than 1500 users
2834
        $sql = "SELECT MAX(view_count) as vc, iid, progress, lp_id, user_id
2835
                FROM $lp_view_table
2836
                WHERE
2837
                    c_id = $course_id AND
2838
                    lp_id IN (".implode(',', $lp_list).")
2839
                    $condition_user1 AND
2840
                    session_id = $session_id
2841
                GROUP BY lp_id, user_id";
2842
2843
        $rs_last_lp_view_id = Database::query($sql);
2844
        $global_result = 0;
2845
2846
        if (Database::num_rows($rs_last_lp_view_id) > 0) {
2847
            // Cycle through each line of the results (grouped by lp_id, user_id)
2848
            while ($row_lp_view = Database::fetch_array($rs_last_lp_view_id)) {
2849
                $count_items = 0;
2850
                $lpPartialTotal = 0;
2851
                $list = [];
2852
                $lp_view_id = $row_lp_view['iid'];
2853
                $lp_id = $row_lp_view['lp_id'];
2854
                $user_id = $row_lp_view['user_id'];
2855
2856
                if ($debug) {
2857
                    echo '<h2>LP id '.$lp_id.'</h2>';
2858
                    echo "get_only_latest_attempt_results: $get_only_latest_attempt_results <br />";
2859
                    echo "getOnlyBestAttempt: $getOnlyBestAttempt <br />";
2860
                }
2861
2862
                if ($get_only_latest_attempt_results || $getOnlyBestAttempt) {
2863
                    // Getting lp_items done by the user
2864
                    $sql = "SELECT DISTINCT lp_item_id
2865
                            FROM $lp_item_view_table
2866
                            WHERE
2867
                                c_id = $course_id AND
2868
                                lp_view_id = $lp_view_id
2869
                            ORDER BY lp_item_id";
2870
                    $res_lp_item = Database::query($sql);
2871
2872
                    while ($row_lp_item = Database::fetch_array($res_lp_item, 'ASSOC')) {
2873
                        $my_lp_item_id = $row_lp_item['lp_item_id'];
2874
                        $order = ' view_count DESC';
2875
                        if ($getOnlyBestAttempt) {
2876
                            $order = ' lp_iv.score DESC';
2877
                        }
2878
2879
                        // Getting the most recent attempt
2880
                        $sql = "SELECT
2881
                                    lp_iv.id as lp_item_view_id,
2882
                                    lp_iv.score as score,
2883
                                    lp_i.max_score,
2884
                                    lp_iv.max_score as max_score_item_view,
2885
                                    lp_i.path,
2886
                                    lp_i.item_type,
2887
                                    lp_i.iid
2888
                                FROM $lp_item_view_table as lp_iv
2889
                                INNER JOIN $lp_item_table as lp_i
2890
                                ON (
2891
                                    lp_i.iid = lp_iv.lp_item_id AND
2892
                                    lp_iv.c_id = lp_i.c_id
2893
                                )
2894
                                WHERE
2895
                                    lp_iv.c_id = $course_id AND
2896
                                    lp_i.c_id  = $course_id AND
2897
                                    lp_item_id = $my_lp_item_id AND
2898
                                    lp_view_id = $lp_view_id AND
2899
                                    (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."')
2900
                                ORDER BY $order
2901
                                LIMIT 1";
2902
2903
                        $res_lp_item_result = Database::query($sql);
2904
                        while ($row_max_score = Database::fetch_array($res_lp_item_result, 'ASSOC')) {
2905
                            $list[] = $row_max_score;
2906
                        }
2907
                    }
2908
                } else {
2909
                    // For the currently analysed view, get the score and
2910
                    // max_score of each item if it is a sco or a TOOL_QUIZ
2911
                    $sql = "SELECT
2912
                                lp_iv.id as lp_item_view_id,
2913
                                lp_iv.score as score,
2914
                                lp_i.max_score,
2915
                                lp_iv.max_score as max_score_item_view,
2916
                                lp_i.path,
2917
                                lp_i.item_type,
2918
                                lp_i.id as iid
2919
                              FROM $lp_item_view_table as lp_iv
2920
                              INNER JOIN $lp_item_table as lp_i
2921
                              ON lp_i.iid = lp_iv.lp_item_id AND
2922
                                 lp_iv.c_id = lp_i.c_id
2923
                              WHERE
2924
                                lp_iv.c_id = $course_id AND
2925
                                lp_i.c_id  = $course_id AND
2926
                                lp_view_id = $lp_view_id AND
2927
                                (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."')
2928
                            ";
2929
                    $res_max_score = Database::query($sql);
2930
                    while ($row_max_score = Database::fetch_array($res_max_score, 'ASSOC')) {
2931
                        $list[] = $row_max_score;
2932
                    }
2933
                }
2934
2935
                // Go through each scorable element of this view
2936
                $score_of_scorm_calculate = 0;
2937
                foreach ($list as $row_max_score) {
2938
                    // Came from the original lp_item
2939
                    $max_score = $row_max_score['max_score'];
2940
                    // Came from the lp_item_view
2941
                    $max_score_item_view = $row_max_score['max_score_item_view'];
2942
                    $score = $row_max_score['score'];
2943
                    if ($debug) {
2944
                        echo '<h3>Item Type: '.$row_max_score['item_type'].'</h3>';
2945
                    }
2946
2947
                    if ('sco' == $row_max_score['item_type']) {
2948
                        /* Check if it is sco (easier to get max_score)
2949
                           when there's no max score, we assume 100 as the max score,
2950
                           as the SCORM 1.2 says that the value should always be between 0 and 100.
2951
                        */
2952
                        if (0 == $max_score || is_null($max_score) || '' == $max_score) {
2953
                            // Chamilo style
2954
                            if ($use_max_score[$lp_id]) {
2955
                                $max_score = 100;
2956
                            } else {
2957
                                // Overwrites max score = 100 to use the one that came in the lp_item_view see BT#1613
2958
                                $max_score = $max_score_item_view;
2959
                            }
2960
                        }
2961
                        // Avoid division by zero errors
2962
                        if (!empty($max_score)) {
2963
                            $lpPartialTotal += $score / $max_score;
2964
                        }
2965
                        if ($debug) {
2966
                            var_dump("lpPartialTotal: $lpPartialTotal");
0 ignored issues
show
Security Debugging Code introduced by
var_dump('lpPartialTotal: '.$lpPartialTotal) looks like debug code. Are you sure you do not want to remove it?
Loading history...
2967
                            var_dump("score: $score");
2968
                            var_dump("max_score: $max_score");
2969
                        }
2970
                    } else {
2971
                        // Case of a TOOL_QUIZ element
2972
                        $item_id = $row_max_score['iid'];
2973
                        $item_path = $row_max_score['path'];
2974
                        $lp_item_view_id = (int) $row_max_score['lp_item_view_id'];
2975
2976
                        if (empty($lp_item_view_id)) {
2977
                            $lpItemCondition = ' (orig_lp_item_view_id = 0 OR orig_lp_item_view_id IS NULL) ';
2978
                        } else {
2979
                            $lpItemCondition = " orig_lp_item_view_id = $lp_item_view_id ";
2980
                        }
2981
2982
                        // Get last attempt to this exercise through
2983
                        // the current lp for the current user
2984
                        $order = 'exe_date DESC';
2985
                        if ($getOnlyBestAttempt) {
2986
                            $order = 'score DESC';
2987
                        }
2988
                        $sql = "SELECT exe_id, score
2989
                                FROM $tbl_stats_exercices
2990
                                WHERE
2991
                                    exe_exo_id = '$item_path' AND
2992
                                    exe_user_id = $user_id AND
2993
                                    orig_lp_item_id = $item_id AND
2994
                                    $lpItemCondition AND
2995
                                    c_id = $course_id AND
2996
                                    session_id = $session_id AND
2997
                                    status = ''
2998
                                ORDER BY $order
2999
                                LIMIT 1";
3000
3001
                        $result_last_attempt = Database::query($sql);
3002
                        $num = Database::num_rows($result_last_attempt);
3003
                        if ($num > 0) {
3004
                            $attemptResult = Database::fetch_array($result_last_attempt, 'ASSOC');
3005
                            $id_last_attempt = $attemptResult['exe_id'];
3006
                            // We overwrite the score with the best one not the one saved in the LP (latest)
3007
                            if ($getOnlyBestAttempt && false == $get_only_latest_attempt_results) {
3008
                                if ($debug) {
3009
                                    echo "Following score comes from the track_exercise table not in the LP because the score is the best<br />";
3010
                                }
3011
                                $score = $attemptResult['score'];
3012
                            }
3013
3014
                            if ($debug) {
3015
                                echo "Attempt id: $id_last_attempt with score $score<br />";
3016
                            }
3017
                            // Within the last attempt number tracking, get the sum of
3018
                            // the max_scores of all questions that it was
3019
                            // made of (we need to make this call dynamic because of random questions selection)
3020
                            $sql = "SELECT SUM(t.ponderation) as maxscore FROM
3021
                                            (
3022
                                                SELECT DISTINCT
3023
                                                    question_id,
3024
                                                    marks,
3025
                                                    ponderation
3026
                                                FROM $tbl_stats_attempts AS at
3027
                                                INNER JOIN $tbl_quiz_questions AS q
3028
                                                ON (q.id = at.question_id AND q.c_id = q.c_id)
3029
                                                WHERE
3030
                                                    exe_id ='$id_last_attempt' AND
3031
                                                    q.c_id = $course_id
3032
                                            )
3033
                                            AS t";
3034
3035
                            $res_max_score_bis = Database::query($sql);
3036
                            $row_max_score_bis = Database::fetch_array($res_max_score_bis);
3037
3038
                            if (!empty($row_max_score_bis['maxscore'])) {
3039
                                $max_score = $row_max_score_bis['maxscore'];
3040
                            }
3041
                            if (!empty($max_score) && floatval($max_score) > 0) {
3042
                                $lpPartialTotal += $score / $max_score;
3043
                            }
3044
                            if ($debug) {
3045
                                var_dump("score: $score");
3046
                                var_dump("max_score: $max_score");
3047
                                var_dump("lpPartialTotal: $lpPartialTotal");
3048
                            }
3049
                        }
3050
                    }
3051
3052
                    if (in_array($row_max_score['item_type'], ['quiz', 'sco'])) {
3053
                        // Normal way
3054
                        if ($use_max_score[$lp_id]) {
3055
                            $count_items++;
3056
                        } else {
3057
                            if ('' != $max_score) {
3058
                                $count_items++;
3059
                            }
3060
                        }
3061
                        if ($debug) {
3062
                            echo '$count_items: '.$count_items;
3063
                        }
3064
                    }
3065
                } //end for
3066
3067
                $score_of_scorm_calculate += $count_items ? (($lpPartialTotal / $count_items) * 100) : 0;
3068
                $global_result += $score_of_scorm_calculate;
3069
3070
                if ($debug) {
3071
                    var_dump("count_items: $count_items");
3072
                    var_dump("score_of_scorm_calculate: $score_of_scorm_calculate");
3073
                    var_dump("global_result: $global_result");
3074
                }
3075
            } // end while
3076
        }
3077
3078
        $lp_with_quiz = 0;
3079
        foreach ($lp_list as $lp_id) {
3080
            // Check if LP have a score we assume that all SCO have an score
3081
            $sql = "SELECT count(iid) as count
3082
                    FROM $lp_item_table
3083
                    WHERE
3084
                        c_id = $course_id AND
3085
                        (item_type = 'quiz' OR item_type = 'sco') AND
3086
                        lp_id = ".$lp_id;
3087
            $result_have_quiz = Database::query($sql);
3088
            if (Database::num_rows($result_have_quiz) > 0) {
3089
                $row = Database::fetch_array($result_have_quiz, 'ASSOC');
3090
                if (is_numeric($row['count']) && 0 != $row['count']) {
3091
                    $lp_with_quiz++;
3092
                }
3093
            }
3094
        }
3095
3096
        if ($debug) {
3097
            echo '<h3>$lp_with_quiz '.$lp_with_quiz.' </h3>';
3098
        }
3099
        if ($debug) {
3100
            echo '<h3>Final return</h3>';
3101
        }
3102
3103
        if (0 != $lp_with_quiz) {
3104
            if (!$return_array) {
3105
                $score_of_scorm_calculate = round(($global_result / $lp_with_quiz), 2);
3106
                if ($debug) {
3107
                    var_dump($score_of_scorm_calculate);
3108
                }
3109
                if (empty($lp_ids)) {
3110
                    if ($debug) {
3111
                        echo '<h2>All lps fix: '.$score_of_scorm_calculate.'</h2>';
3112
                    }
3113
                }
3114
3115
                return $score_of_scorm_calculate;
3116
            }
3117
3118
            if ($debug) {
3119
                var_dump($global_result, $lp_with_quiz);
3120
            }
3121
3122
            return [$global_result, $lp_with_quiz];
3123
        }
3124
3125
        return '-';
3126
    }
3127
3128
    /**
3129
     * This function gets:
3130
     * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores.
3131
     * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores.
3132
     * 3. And finally it will return the average between 1. and 2.
3133
     * This function does not take the results of a Test out of a LP.
3134
     *
3135
     * @param int|array $student_id  Array of user ids or an user id
3136
     * @param string    $course_code Course code
3137
     * @param array     $lp_ids      List of LP ids
3138
     * @param int       $session_id  Session id (optional), if param $session_id is 0(default)
3139
     *                               it'll return results including sessions, 0 = session is not filtered
3140
     *
3141
     * @return string value (number %) Which represents a round integer explain in got in 3
3142
     */
3143
    public static function getAverageStudentScore(
3144
        $student_id,
3145
        $course_code = '',
3146
        $lp_ids = [],
3147
        $session_id = 0
3148
    ) {
3149
        if (empty($student_id)) {
3150
            return 0;
3151
        }
3152
3153
        $conditions = [];
3154
        if (!empty($course_code)) {
3155
            $course = api_get_course_info($course_code);
3156
            $courseId = $course['real_id'];
3157
            $conditions[] = " lp.c_id = $courseId";
3158
        }
3159
3160
        // Get course tables names
3161
        $lp_table = Database::get_course_table(TABLE_LP_MAIN);
3162
        $lp_item_table = Database::get_course_table(TABLE_LP_ITEM);
3163
        $lp_view_table = Database::get_course_table(TABLE_LP_VIEW);
3164
        $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3165
3166
        // Compose a filter based on optional learning paths list given
3167
        if (!empty($lp_ids) && count($lp_ids) > 0) {
3168
            $conditions[] = ' lp.iid IN ('.implode(',', $lp_ids).') ';
3169
        }
3170
3171
        // Compose a filter based on optional session id
3172
        $session_id = (int) $session_id;
3173
        if (!empty($session_id)) {
3174
            $conditions[] = " lp_view.session_id = $session_id ";
3175
        }
3176
3177
        if (is_array($student_id)) {
3178
            array_walk($student_id, 'intval');
3179
            $conditions[] = " lp_view.user_id IN (".implode(',', $student_id).") ";
3180
        } else {
3181
            $student_id = (int) $student_id;
3182
            $conditions[] = " lp_view.user_id = $student_id ";
3183
        }
3184
3185
        $conditionsToString = implode(' AND ', $conditions);
3186
        $sql = "SELECT
3187
                    SUM(lp_iv.score) sum_score,
3188
                    SUM(lp_i.max_score) sum_max_score
3189
                FROM $lp_table as lp
3190
                INNER JOIN $lp_item_table as lp_i
3191
                ON lp.iid = lp_id AND lp.c_id = lp_i.c_id
3192
                INNER JOIN $lp_view_table as lp_view
3193
                ON lp_view.lp_id = lp_i.lp_id AND lp_view.c_id = lp_i.c_id
3194
                INNER JOIN $lp_item_view_table as lp_iv
3195
                ON
3196
                    lp_i.iid = lp_iv.lp_item_id AND
3197
                    lp_view.c_id = lp_iv.c_id AND
3198
                    lp_iv.lp_view_id = lp_view.iid
3199
                WHERE (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."') AND
3200
                $conditionsToString
3201
        ";
3202
        $result = Database::query($sql);
3203
        $row = Database::fetch_array($result, 'ASSOC');
3204
3205
        if (empty($row['sum_max_score'])) {
3206
            return 0;
3207
        }
3208
3209
        return ($row['sum_score'] / $row['sum_max_score']) * 100;
3210
    }
3211
3212
    /**
3213
     * This function gets time spent in learning path for a student inside a course.
3214
     *
3215
     * @param int|array $student_id  Student id(s)
3216
     * @param string    $course_code Course code
3217
     * @param array     $lp_ids      Limit average to listed lp ids
3218
     * @param int       $session_id  Session id (optional), if param $session_id is null(default)
3219
     *                               it'll return results including sessions, 0 = session is not filtered
3220
     *
3221
     * @return int Total time in seconds
3222
     */
3223
    public static function get_time_spent_in_lp(
3224
        $student_id,
3225
        $course_code,
3226
        $lp_ids = [],
3227
        $session_id = 0
3228
    ) {
3229
        $course = api_get_course_info($course_code);
3230
        $student_id = (int) $student_id;
3231
        $session_id = (int) $session_id;
3232
        $total_time = 0;
3233
3234
        if (!empty($course)) {
3235
            $lpTable = Database::get_course_table(TABLE_LP_MAIN);
3236
            $lpItemTable = Database::get_course_table(TABLE_LP_ITEM);
3237
            $lpViewTable = Database::get_course_table(TABLE_LP_VIEW);
3238
            $lpItemViewTable = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3239
            $trackExercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
3240
            $course_id = $course['real_id'];
3241
3242
            // Compose a filter based on optional learning paths list given
3243
            $condition_lp = '';
3244
            if (count($lp_ids) > 0) {
3245
                $condition_lp = " AND iid IN(".implode(',', $lp_ids).") ";
3246
            }
3247
3248
            // Check the real number of LPs corresponding to the filter in the
3249
            // database (and if no list was given, get them all)
3250
            $sql = "SELECT DISTINCT(iid) FROM $lpTable
3251
                    WHERE c_id = $course_id $condition_lp";
3252
            $result = Database::query($sql);
3253
            $session_condition = api_get_session_condition($session_id);
3254
3255
            // calculates time
3256
            if (Database::num_rows($result) > 0) {
3257
                while ($row = Database::fetch_array($result)) {
3258
                    $lp_id = (int) $row['iid'];
3259
3260
                    // Start Exercise in LP total_time
3261
                    // Get duration time from track_e_exercises.exe_duration instead of lp_view_item.total_time
3262
                    $list = learnpath::get_flat_ordered_items_list($lp_id, 0, $course_id);
3263
                    foreach ($list as $itemId) {
3264
                        $sql = "SELECT max(view_count)
3265
                                FROM $lpViewTable
3266
                                WHERE
3267
                                    c_id = $course_id AND
3268
                                    lp_id = $lp_id AND
3269
                                    user_id = $student_id
3270
                                    $session_condition";
3271
                        $res = Database::query($sql);
3272
                        $view = '';
3273
                        if (Database::num_rows($res) > 0) {
3274
                            $myrow = Database::fetch_array($res);
3275
                            $view = $myrow[0];
3276
                        }
3277
                        $viewCondition = null;
3278
                        if (!empty($view)) {
3279
                            $viewCondition = " AND v.view_count = $view  ";
3280
                        }
3281
                        $sql = "SELECT
3282
                            iv.iid,
3283
                            iv.total_time as mytime,
3284
                            i.iid as myid,
3285
                            iv.view_count as iv_view_count,
3286
                            path
3287
                        FROM $lpItemTable as i
3288
                        INNER JOIN $lpItemViewTable as iv
3289
                        ON (i.iid = iv.lp_item_id AND i.c_id = iv.c_id)
3290
                        INNER JOIN $lpViewTable as v
3291
                        ON (iv.lp_view_id = v.iid AND v.c_id = iv.c_id)
3292
                        WHERE
3293
                            v.c_id = $course_id AND
3294
                            i.iid = $itemId AND
3295
                            i.lp_id = $lp_id  AND
3296
                            v.user_id = $student_id AND
3297
                            item_type = 'quiz' AND
3298
                            path <> '' AND
3299
                            v.session_id = $session_id
3300
                            $viewCondition
3301
                        ORDER BY iv.view_count DESC ";
3302
3303
                        $resultRow = Database::query($sql);
3304
                        if (Database::num_rows($resultRow)) {
3305
                            $row = Database::fetch_array($resultRow);
3306
                            $totalTimeInLpItemView = $row['mytime'];
3307
                            $lpItemViewId = $row['iid'];
3308
3309
                            $sql = 'SELECT SUM(exe_duration) exe_duration
3310
                                    FROM '.$trackExercises.'
3311
                                    WHERE
3312
                                        exe_exo_id="'.$row['path'].'" AND
3313
                                        exe_user_id="'.$student_id.'" AND
3314
                                        orig_lp_id = "'.$lp_id.'" AND
3315
                                        orig_lp_item_id = "'.$row['myid'].'" AND
3316
                                        c_id = '.$course_id.' AND
3317
                                        status <> "incomplete" AND
3318
                                        session_id = '.$session_id.'
3319
                                     ORDER BY exe_date DESC ';
3320
3321
                            $sumScoreResult = Database::query($sql);
3322
                            $durationRow = Database::fetch_array($sumScoreResult, 'ASSOC');
3323
                            if (!empty($durationRow['exe_duration'])) {
3324
                                $exeDuration = $durationRow['exe_duration'];
3325
                                if ($exeDuration != $totalTimeInLpItemView &&
3326
                                    !empty($lpItemViewId) &&
3327
                                    !empty($exeDuration)
3328
                                ) {
3329
                                    // Update c_lp_item_view.total_time
3330
                                    $sqlUpdate = "UPDATE $lpItemViewTable
3331
                                                  SET total_time = '$exeDuration'
3332
                                                  WHERE iid = ".$lpItemViewId;
3333
                                    Database::query($sqlUpdate);
3334
                                }
3335
                            }
3336
                        }
3337
                    }
3338
3339
                    // End total_time fix
3340
3341
                    // Calculate total time
3342
                    $sql = "SELECT SUM(total_time)
3343
                            FROM $lpItemViewTable AS item_view
3344
                            INNER JOIN $lpViewTable AS view
3345
                            ON (
3346
                                item_view.lp_view_id = view.iid AND
3347
                                item_view.c_id = view.c_id
3348
                            )
3349
                            WHERE
3350
                                item_view.c_id = $course_id AND
3351
                                view.c_id = $course_id AND
3352
                                view.lp_id = $lp_id AND
3353
                                view.user_id = $student_id AND
3354
                                session_id = $session_id";
3355
3356
                    $rs = Database::query($sql);
3357
                    if (Database::num_rows($rs) > 0) {
3358
                        $total_time += Database::result($rs, 0, 0);
3359
                    }
3360
                }
3361
            }
3362
        }
3363
3364
        return $total_time;
3365
    }
3366
3367
    /**
3368
     * This function gets last connection time to one learning path.
3369
     *
3370
     * @param int|array $student_id  Student id(s)
3371
     * @param string    $course_code Course code
3372
     * @param int       $lp_id       Learning path id
3373
     * @param int       $session_id
3374
     *
3375
     * @return int last connection timestamp
3376
     */
3377
    public static function get_last_connection_time_in_lp(
3378
        $student_id,
3379
        $course_code,
3380
        $lp_id,
3381
        $session_id = 0
3382
    ) {
3383
        $course = api_get_course_info($course_code);
3384
        if (empty($course)) {
3385
            return 0;
3386
        }
3387
3388
        $course_id = $course['real_id'];
3389
        $student_id = (int) $student_id;
3390
        $lp_id = (int) $lp_id;
3391
        $session_id = (int) $session_id;
3392
        $lastTime = 0;
3393
3394
        if (self::minimumTimeAvailable($session_id, $course_id)) {
3395
            $sql = "SELECT MAX(date_reg) max
3396
                    FROM track_e_access_complete
3397
                    WHERE
3398
                        user_id = $student_id AND
3399
                        c_id = $course_id AND
3400
                        session_id = $session_id AND
3401
                        tool = 'learnpath' AND
3402
                        tool_id = $lp_id AND
3403
                        action = 'view' AND
3404
                        login_as = 0
3405
                    ORDER BY date_reg ASC
3406
                    LIMIT 1";
3407
            $rs = Database::query($sql);
3408
3409
            $lastConnection = 0;
3410
            if (Database::num_rows($rs) > 0) {
3411
                $value = Database::fetch_array($rs);
3412
                if (isset($value['max']) && !empty($value['max'])) {
3413
                    $lastConnection = api_strtotime($value['max'], 'UTC');
3414
                }
3415
            }
3416
3417
            if (!empty($lastConnection)) {
3418
                return $lastConnection;
3419
            }
3420
        }
3421
        if (!empty($course)) {
3422
            $lp_table = Database::get_course_table(TABLE_LP_MAIN);
3423
            $t_lpv = Database::get_course_table(TABLE_LP_VIEW);
3424
            $t_lpiv = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3425
3426
            // Check the real number of LPs corresponding to the filter in the
3427
            // database (and if no list was given, get them all)
3428
            $sql = "SELECT iid FROM $lp_table
3429
                    WHERE c_id = $course_id AND iid = $lp_id ";
3430
            $row = Database::query($sql);
3431
            $count = Database::num_rows($row);
3432
3433
            // calculates last connection time
3434
            if ($count > 0) {
3435
                $sql = 'SELECT MAX(start_time)
3436
                        FROM '.$t_lpiv.' AS item_view
3437
                        INNER JOIN '.$t_lpv.' AS view
3438
                        ON (item_view.lp_view_id = view.iid AND item_view.c_id = view.c_id)
3439
                        WHERE
3440
                            status != "not attempted" AND
3441
                            item_view.c_id = '.$course_id.' AND
3442
                            view.c_id = '.$course_id.' AND
3443
                            view.lp_id = '.$lp_id.' AND
3444
                            view.user_id = '.$student_id.' AND
3445
                            view.session_id = '.$session_id;
3446
                $rs = Database::query($sql);
3447
                if (Database::num_rows($rs) > 0) {
3448
                    $lastTime = Database::result($rs, 0, 0);
3449
                }
3450
            }
3451
        }
3452
3453
        return $lastTime;
3454
    }
3455
3456
    public static function getFirstConnectionTimeInLp(
3457
        $student_id,
3458
        $course_code,
3459
        $lp_id,
3460
        $session_id = 0
3461
    ) {
3462
        $course = api_get_course_info($course_code);
3463
        $student_id = (int) $student_id;
3464
        $lp_id = (int) $lp_id;
3465
        $session_id = (int) $session_id;
3466
        $time = 0;
3467
3468
        if (!empty($course)) {
3469
            $course_id = $course['real_id'];
3470
            $lp_table = Database::get_course_table(TABLE_LP_MAIN);
3471
            $t_lpv = Database::get_course_table(TABLE_LP_VIEW);
3472
            $t_lpiv = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3473
3474
            // Check the real number of LPs corresponding to the filter in the
3475
            // database (and if no list was given, get them all)
3476
            $sql = "SELECT iid FROM $lp_table
3477
                    WHERE c_id = $course_id AND iid = $lp_id ";
3478
            $row = Database::query($sql);
3479
            $count = Database::num_rows($row);
3480
3481
            // calculates first connection time
3482
            if ($count > 0) {
3483
                $sql = 'SELECT MIN(start_time)
3484
                        FROM '.$t_lpiv.' AS item_view
3485
                        INNER JOIN '.$t_lpv.' AS view
3486
                        ON (item_view.lp_view_id = view.iid AND item_view.c_id = view.c_id)
3487
                        WHERE
3488
                            status != "not attempted" AND
3489
                            item_view.c_id = '.$course_id.' AND
3490
                            view.c_id = '.$course_id.' AND
3491
                            view.lp_id = '.$lp_id.' AND
3492
                            view.user_id = '.$student_id.' AND
3493
                            view.session_id = '.$session_id;
3494
                $rs = Database::query($sql);
3495
                if (Database::num_rows($rs) > 0) {
3496
                    $time = Database::result($rs, 0, 0);
3497
                }
3498
            }
3499
        }
3500
3501
        return $time;
3502
    }
3503
3504
    /**
3505
     * gets the list of students followed by coach.
3506
     *
3507
     * @param int $coach_id Coach id
3508
     *
3509
     * @return array List of students
3510
     */
3511
    public static function get_student_followed_by_coach($coach_id)
3512
    {
3513
        $coach_id = intval($coach_id);
3514
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3515
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3516
        $tbl_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
3517
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3518
3519
        $students = [];
3520
        // At first, courses where $coach_id is coach of the course //
3521
        $sql = 'SELECT session_id, c_id
3522
                FROM '.$tbl_session_course_user.'
3523
                WHERE user_id='.$coach_id.' AND status=2';
3524
3525
        if (api_is_multiple_url_enabled()) {
3526
            $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3527
            $access_url_id = api_get_current_access_url_id();
3528
            if (-1 != $access_url_id) {
3529
                $sql = 'SELECT scu.session_id, scu.c_id
3530
                        FROM '.$tbl_session_course_user.' scu
3531
                        INNER JOIN '.$tbl_session_rel_access_url.'  sru
3532
                        ON (scu.session_id=sru.session_id)
3533
                        WHERE
3534
                            scu.user_id='.$coach_id.' AND
3535
                            scu.status=2 AND
3536
                            sru.access_url_id = '.$access_url_id;
3537
            }
3538
        }
3539
3540
        $result = Database::query($sql);
3541
3542
        while ($a_courses = Database::fetch_array($result)) {
3543
            $courseId = $a_courses['c_id'];
3544
            $id_session = $a_courses['session_id'];
3545
3546
            $sql = "SELECT DISTINCT srcru.user_id
3547
                    FROM $tbl_session_course_user AS srcru
3548
                    INNER JOIN $tbl_session_user sru
3549
                    ON (srcru.user_id = sru.user_id AND srcru.session_id = sru.session_id)
3550
                    WHERE
3551
                        sru.relation_type <> ".SESSION_RELATION_TYPE_RRHH." AND
3552
                        srcru.c_id = '$courseId' AND
3553
                        srcru.session_id = '$id_session'";
3554
3555
            $rs = Database::query($sql);
3556
            while ($row = Database::fetch_array($rs)) {
3557
                $students[$row['user_id']] = $row['user_id'];
3558
            }
3559
        }
3560
3561
        // Then, courses where $coach_id is coach of the session
3562
        $sql = 'SELECT session_course_user.user_id
3563
                FROM '.$tbl_session_course_user.' as session_course_user
3564
                INNER JOIN '.$tbl_session_user.' sru
3565
                ON session_course_user.user_id = sru.user_id AND session_course_user.session_id = sru.session_id
3566
                INNER JOIN '.$tbl_session_course.' as session_course
3567
                ON session_course.c_id = session_course_user.c_id
3568
                AND session_course_user.session_id = session_course.session_id
3569
                INNER JOIN '.$tbl_session.' as session
3570
                ON session.id = session_course.session_id
3571
                AND session.id_coach = '.$coach_id;
3572
        if (api_is_multiple_url_enabled()) {
3573
            $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3574
            $access_url_id = api_get_current_access_url_id();
3575
            if (-1 != $access_url_id) {
3576
                $sql = 'SELECT session_course_user.user_id
3577
                        FROM '.$tbl_session_course_user.' as session_course_user
3578
                        INNER JOIN '.$tbl_session_user.' sru
3579
                        ON session_course_user.user_id = sru.user_id AND
3580
                           session_course_user.session_id = sru.session_id
3581
                        INNER JOIN '.$tbl_session_course.' as session_course
3582
                        ON session_course.c_id = session_course_user.c_id AND
3583
                        session_course_user.session_id = session_course.session_id
3584
                        INNER JOIN '.$tbl_session.' as session
3585
                        ON session.id = session_course.session_id AND
3586
                        session.id_coach = '.$coach_id.'
3587
                        INNER JOIN '.$tbl_session_rel_access_url.' session_rel_url
3588
                        ON session.id = session_rel_url.session_id
3589
                        WHERE access_url_id = '.$access_url_id;
3590
            }
3591
        }
3592
3593
        $result = Database::query($sql);
3594
        while ($row = Database::fetch_array($result)) {
3595
            $students[$row['user_id']] = $row['user_id'];
3596
        }
3597
3598
        return $students;
3599
    }
3600
3601
    /**
3602
     * Check if a coach is allowed to follow a student.
3603
     *
3604
     * @param    int        Coach id
3605
     * @param    int        Student id
3606
     *
3607
     * @return bool
3608
     */
3609
    public static function is_allowed_to_coach_student($coach_id, $student_id)
3610
    {
3611
        $coach_id = intval($coach_id);
3612
        $student_id = intval($student_id);
3613
3614
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3615
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3616
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3617
3618
        // At first, courses where $coach_id is coach of the course
3619
        $sql = 'SELECT 1 FROM '.$tbl_session_course_user.'
3620
                WHERE user_id='.$coach_id.' AND status=2';
3621
        $result = Database::query($sql);
3622
        if (Database::num_rows($result) > 0) {
3623
            return true;
3624
        }
3625
3626
        // Then, courses where $coach_id is coach of the session
3627
        $sql = 'SELECT session_course_user.user_id
3628
                FROM '.$tbl_session_course_user.' as session_course_user
3629
                INNER JOIN '.$tbl_session_course.' as session_course
3630
                ON session_course.c_id = session_course_user.c_id
3631
                INNER JOIN '.$tbl_session.' as session
3632
                ON session.id = session_course.session_id
3633
                AND session.id_coach = '.$coach_id.'
3634
                WHERE user_id = '.$student_id;
3635
        $result = Database::query($sql);
3636
        if (Database::num_rows($result) > 0) {
3637
            return true;
3638
        }
3639
3640
        return false;
3641
    }
3642
3643
    /**
3644
     * Get courses followed by coach.
3645
     *
3646
     * @param     int        Coach id
3647
     * @param    int        Session id (optional)
3648
     *
3649
     * @return array Courses list
3650
     */
3651
    public static function get_courses_followed_by_coach($coach_id, $id_session = 0)
3652
    {
3653
        $coach_id = intval($coach_id);
3654
        if (!empty($id_session)) {
3655
            $id_session = intval($id_session);
3656
        }
3657
3658
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3659
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3660
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3661
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3662
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3663
3664
        // At first, courses where $coach_id is coach of the course.
3665
        $sql = 'SELECT DISTINCT c.code
3666
                FROM '.$tbl_session_course_user.' sc
3667
                INNER JOIN '.$tbl_course.' c
3668
                ON (c.id = sc.c_id)
3669
                WHERE user_id = '.$coach_id.' AND status = 2';
3670
3671
        if (api_is_multiple_url_enabled()) {
3672
            $access_url_id = api_get_current_access_url_id();
3673
            if (-1 != $access_url_id) {
3674
                $sql = 'SELECT DISTINCT c.code
3675
                        FROM '.$tbl_session_course_user.' scu
3676
                        INNER JOIN '.$tbl_course.' c
3677
                        ON (c.code = scu.c_id)
3678
                        INNER JOIN '.$tbl_course_rel_access_url.' cru
3679
                        ON (c.id = cru.c_id)
3680
                        WHERE
3681
                            scu.user_id='.$coach_id.' AND
3682
                            scu.status=2 AND
3683
                            cru.access_url_id = '.$access_url_id;
3684
            }
3685
        }
3686
3687
        if (!empty($id_session)) {
3688
            $sql .= ' AND session_id='.$id_session;
3689
        }
3690
3691
        $courseList = [];
3692
        $result = Database::query($sql);
3693
        while ($row = Database::fetch_array($result)) {
3694
            $courseList[$row['code']] = $row['code'];
3695
        }
3696
3697
        // Then, courses where $coach_id is coach of the session
3698
        $sql = 'SELECT DISTINCT course.code
3699
                FROM '.$tbl_session_course.' as session_course
3700
                INNER JOIN '.$tbl_session.' as session
3701
                    ON session.id = session_course.session_id
3702
                    AND session.id_coach = '.$coach_id.'
3703
                INNER JOIN '.$tbl_course.' as course
3704
                    ON course.id = session_course.c_id';
3705
3706
        if (api_is_multiple_url_enabled()) {
3707
            $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3708
            $access_url_id = api_get_current_access_url_id();
3709
            if (-1 != $access_url_id) {
3710
                $sql = 'SELECT DISTINCT c.code
3711
                    FROM '.$tbl_session_course.' as session_course
3712
                    INNER JOIN '.$tbl_course.' c
3713
                    ON (c.id = session_course.c_id)
3714
                    INNER JOIN '.$tbl_session.' as session
3715
                    ON session.id = session_course.session_id
3716
                        AND session.id_coach = '.$coach_id.'
3717
                    INNER JOIN '.$tbl_course.' as course
3718
                        ON course.id = session_course.c_id
3719
                     INNER JOIN '.$tbl_course_rel_access_url.' course_rel_url
3720
                    ON (course_rel_url.c_id = c.id)';
3721
            }
3722
        }
3723
3724
        if (!empty($id_session)) {
3725
            $sql .= ' WHERE session_course.session_id='.$id_session;
3726
            if (api_is_multiple_url_enabled()) {
3727
                $sql .= ' AND access_url_id = '.$access_url_id;
3728
            }
3729
        } else {
3730
            if (api_is_multiple_url_enabled()) {
3731
                $sql .= ' WHERE access_url_id = '.$access_url_id;
3732
            }
3733
        }
3734
3735
        $result = Database::query($sql);
3736
        while ($row = Database::fetch_array($result)) {
3737
            $courseList[$row['code']] = $row['code'];
3738
        }
3739
3740
        return $courseList;
3741
    }
3742
3743
    /**
3744
     * Get sessions coached by user.
3745
     *
3746
     * @param int    $coach_id
3747
     * @param int    $start
3748
     * @param int    $limit
3749
     * @param bool   $getCount
3750
     * @param string $keyword
3751
     * @param string $description
3752
     * @param string $orderByName
3753
     * @param string $orderByDirection
3754
     * @param array  $options
3755
     *
3756
     * @return mixed
3757
     */
3758
    public static function get_sessions_coached_by_user(
3759
        $coach_id,
3760
        $start = 0,
3761
        $limit = 0,
3762
        $getCount = false,
3763
        $keyword = '',
3764
        $description = '',
3765
        $orderByName = '',
3766
        $orderByDirection = '',
3767
        $options = []
3768
    ) {
3769
        // table definition
3770
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3771
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3772
        $coach_id = (int) $coach_id;
3773
3774
        $select = ' SELECT * FROM ';
3775
        if ($getCount) {
3776
            $select = ' SELECT count(DISTINCT id) as count FROM ';
3777
        }
3778
3779
        $limitCondition = null;
3780
        if (!empty($start) && !empty($limit)) {
3781
            $limitCondition = " LIMIT ".intval($start).", ".intval($limit);
3782
        }
3783
3784
        $keywordCondition = null;
3785
        if (!empty($keyword)) {
3786
            $keyword = Database::escape_string($keyword);
3787
            $keywordCondition = " AND (name LIKE '%$keyword%' ) ";
3788
3789
            if (!empty($description)) {
3790
                $description = Database::escape_string($description);
3791
                $keywordCondition = " AND (name LIKE '%$keyword%' OR description LIKE '%$description%' ) ";
3792
            }
3793
        }
3794
3795
        $extraFieldModel = new ExtraFieldModel('session');
3796
        $conditions = $extraFieldModel->parseConditions($options);
3797
        $sqlInjectJoins = $conditions['inject_joins'];
3798
        $extraFieldsConditions = $conditions['where'];
3799
        $sqlInjectWhere = $conditions['inject_where'];
3800
        $injectExtraFields = $conditions['inject_extra_fields'];
3801
3802
        $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3803
        $access_url_id = api_get_current_access_url_id();
3804
3805
        $orderBy = '';
3806
        if (!empty($orderByName)) {
3807
            if (in_array($orderByName, ['name', 'access_start_date'])) {
3808
                $orderByDirection = in_array(strtolower($orderByDirection), ['asc', 'desc']) ? $orderByDirection : 'asc';
3809
                $orderByName = Database::escape_string($orderByName);
3810
                $orderBy .= " ORDER BY $orderByName $orderByDirection";
3811
            }
3812
        }
3813
3814
        $sql = "
3815
            $select
3816
            (
3817
                SELECT DISTINCT
3818
                    s.id,
3819
                    name,
3820
                    $injectExtraFields
3821
                    access_start_date,
3822
                    access_end_date
3823
                FROM $tbl_session s
3824
                INNER JOIN $tbl_session_rel_access_url session_rel_url
3825
                ON (s.id = session_rel_url.session_id)
3826
                $sqlInjectJoins
3827
                WHERE
3828
                    id_coach = $coach_id AND
3829
                    access_url_id = $access_url_id
3830
                    $keywordCondition
3831
                    $extraFieldsConditions
3832
                    $sqlInjectWhere
3833
            UNION
3834
                SELECT DISTINCT
3835
                    s.id,
3836
                    s.name,
3837
                    $injectExtraFields
3838
                    s.access_start_date,
3839
                    s.access_end_date
3840
                FROM $tbl_session as s
3841
                INNER JOIN $tbl_session_course_user as session_course_user
3842
                ON
3843
                    s.id = session_course_user.session_id AND
3844
                    session_course_user.user_id = $coach_id AND
3845
                    session_course_user.status = 2
3846
                INNER JOIN $tbl_session_rel_access_url session_rel_url
3847
                ON (s.id = session_rel_url.session_id)
3848
                $sqlInjectJoins
3849
                WHERE
3850
                    access_url_id = $access_url_id
3851
                    $keywordCondition
3852
                    $extraFieldsConditions
3853
                    $sqlInjectWhere
3854
            ) as sessions $limitCondition $orderBy
3855
            ";
3856
3857
        $rs = Database::query($sql);
3858
        if ($getCount) {
3859
            $row = Database::fetch_array($rs);
3860
3861
            return $row['count'];
3862
        }
3863
3864
        $sessions = [];
3865
        while ($row = Database::fetch_array($rs)) {
3866
            if ('0000-00-00 00:00:00' === $row['access_start_date']) {
3867
                $row['access_start_date'] = null;
3868
            }
3869
3870
            $sessions[$row['id']] = $row;
3871
        }
3872
3873
        if (!empty($sessions)) {
3874
            foreach ($sessions as &$session) {
3875
                if (empty($session['access_start_date'])) {
3876
                    $session['status'] = get_lang('active');
3877
                } else {
3878
                    $time_start = api_strtotime($session['access_start_date'], 'UTC');
3879
                    $time_end = api_strtotime($session['access_end_date'], 'UTC');
3880
                    if ($time_start < time() && time() < $time_end) {
3881
                        $session['status'] = get_lang('active');
3882
                    } else {
3883
                        if (time() < $time_start) {
3884
                            $session['status'] = get_lang('Not yet begun');
3885
                        } else {
3886
                            if (time() > $time_end) {
3887
                                $session['status'] = get_lang('Past');
3888
                            }
3889
                        }
3890
                    }
3891
                }
3892
            }
3893
        }
3894
3895
        return $sessions;
3896
    }
3897
3898
    /**
3899
     * Get courses list from a session.
3900
     *
3901
     * @param    int        Session id
3902
     *
3903
     * @return array Courses list
3904
     */
3905
    public static function get_courses_list_from_session($session_id)
3906
    {
3907
        $session_id = (int) $session_id;
3908
3909
        // table definition
3910
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3911
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
3912
3913
        $sql = "SELECT DISTINCT code, c_id
3914
                FROM $tbl_session_course sc
3915
                INNER JOIN $courseTable c
3916
                ON sc.c_id = c.id
3917
                WHERE session_id= $session_id";
3918
3919
        $result = Database::query($sql);
3920
3921
        $courses = [];
3922
        while ($row = Database::fetch_array($result)) {
3923
            $courses[$row['code']] = $row;
3924
        }
3925
3926
        return $courses;
3927
    }
3928
3929
    /**
3930
     * Count the number of documents that an user has uploaded to a course.
3931
     *
3932
     * @param    int|array   Student id(s)
3933
     * @param    string      Course code
3934
     * @param    int         Session id (optional),
3935
     * if param $session_id is null(default)
3936
     * return count of assignments including sessions, 0 = session is not filtered
3937
     *
3938
     * @return int Number of documents
3939
     */
3940
    public static function count_student_uploaded_documents(
3941
        $student_id,
3942
        $course_code,
3943
        $session_id = null
3944
    ) {
3945
        $a_course = api_get_course_info($course_code);
3946
        $repo = Container::getDocumentRepository();
3947
3948
        $user = api_get_user_entity($student_id);
3949
        $course = api_get_course_entity($a_course['real_id']);
3950
        $session = api_get_session_entity($session_id);
3951
        //$group = api_get_group_entity(api_get_group_id());
3952
3953
        $qb = $repo->getResourcesByCourseLinkedToUser($user, $course, $session);
3954
3955
        $qb->select('count(resource)');
3956
        $count = $qb->getQuery()->getSingleScalarResult();
3957
3958
        return $count;
3959
3960
        // get the information of the course
3961
        $a_course = api_get_course_info($course_code);
0 ignored issues
show
Unused Code introduced by
$a_course = api_get_course_info($course_code) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
3962
        if (!empty($a_course)) {
3963
            // table definition
3964
            $tbl_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
3965
            $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
3966
            $course_id = $a_course['real_id'];
3967
            if (is_array($student_id)) {
3968
                $studentList = array_map('intval', $student_id);
3969
                $condition_user = " AND ip.insert_user_id IN ('".implode(',', $studentList)."') ";
3970
            } else {
3971
                $student_id = (int) $student_id;
3972
                $condition_user = " AND ip.insert_user_id = '$student_id' ";
3973
            }
3974
3975
            $condition_session = null;
3976
            if (isset($session_id)) {
3977
                $session_id = (int) $session_id;
3978
                $condition_session = " AND pub.session_id = $session_id ";
3979
            }
3980
3981
            $sql = "SELECT count(ip.tool) AS count
3982
                    FROM $tbl_item_property ip
3983
                    INNER JOIN $tbl_document pub
3984
                    ON (ip.ref = pub.iid AND ip.c_id = pub.c_id)
3985
                    WHERE
3986
                        ip.c_id  = $course_id AND
3987
                        pub.c_id  = $course_id AND
3988
                        pub.filetype ='file' AND
3989
                        ip.tool = 'document'
3990
                        $condition_user $condition_session ";
3991
            $rs = Database::query($sql);
3992
            $row = Database::fetch_array($rs, 'ASSOC');
3993
3994
            return $row['count'];
3995
        }
3996
3997
        return null;
3998
    }
3999
4000
    /**
4001
     * Count assignments per student.
4002
     *
4003
     * @param array|int $student_id
4004
     * @param string    $course_code
4005
     * @param int       $session_id  if param is null(default) return count of assignments including sessions,
4006
     *                               0 = session is not filtered
4007
     *
4008
     * @return int Count of assignments
4009
     */
4010
    public static function count_student_assignments(
4011
        $student_id,
4012
        $course_code = null,
4013
        $session_id = null
4014
    ) {
4015
        if (empty($student_id)) {
4016
            return 0;
4017
        }
4018
4019
        $a_course = api_get_course_info($course_code);
4020
        $repo = Container::getStudentPublicationRepository();
4021
4022
        $user = api_get_user_entity($student_id);
4023
        $course = api_get_course_entity($a_course['real_id']);
4024
        $session = api_get_session_entity($session_id);
4025
        //$group = api_get_group_entity(api_get_group_id());
4026
4027
        $qb = $repo->getResourcesByCourseLinkedToUser($user, $course, $session);
4028
4029
        $qb->select('count(resource)');
4030
        $count = $qb->getQuery()->getSingleScalarResult();
4031
4032
        return $count;
4033
4034
        $conditions = [];
0 ignored issues
show
Unused Code introduced by
$conditions = array() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
4035
4036
        // Get the information of the course
4037
        $a_course = api_get_course_info($course_code);
4038
        if (!empty($a_course)) {
4039
            $course_id = $a_course['real_id'];
4040
            $conditions[] = " ip.c_id  = $course_id AND pub.c_id  = $course_id ";
4041
        }
4042
4043
        // table definition
4044
        $tbl_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
4045
        $tbl_student_publication = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4046
4047
        if (is_array($student_id)) {
4048
            $studentList = array_map('intval', $student_id);
4049
            $conditions[] = " ip.insert_user_id IN ('".implode("','", $studentList)."') ";
4050
        } else {
4051
            $student_id = (int) $student_id;
4052
            $conditions[] = " ip.insert_user_id = '$student_id' ";
4053
        }
4054
4055
        $conditions[] = ' pub.active <> 2 ';
4056
        $conditionToString = implode(' AND ', $conditions);
4057
        $sessionCondition = api_get_session_condition($session_id, true, false, 'pub.session_id');
4058
        $conditionToString .= $sessionCondition;
4059
4060
        $sql = "SELECT count(ip.tool) as count
4061
                FROM $tbl_item_property ip
4062
                INNER JOIN $tbl_student_publication pub
4063
                ON (ip.ref = pub.iid AND ip.c_id = pub.c_id)
4064
                WHERE
4065
                    ip.tool='work' AND
4066
                    $conditionToString";
4067
        $rs = Database::query($sql);
4068
        $row = Database::fetch_array($rs, 'ASSOC');
4069
4070
        return $row['count'];
4071
    }
4072
4073
    /**
4074
     * Count messages per student inside forum tool.
4075
     *
4076
     * @param int|array  Student id
4077
     * @param string     Course code
4078
     * @param int        Session id if null(default) return count of messages including sessions, 0 = session is not filtered
4079
     *
4080
     * @return int Count of messages
4081
     */
4082
    public static function count_student_messages($student_id, $courseCode = null, $session_id = null)
4083
    {
4084
        if (empty($student_id)) {
4085
            return 0;
4086
        }
4087
4088
        $a_course = api_get_course_info($courseCode);
4089
        $repo = Container::getForumPostRepository();
4090
4091
        $user = api_get_user_entity($student_id);
4092
        $course = api_get_course_entity($a_course['real_id']);
4093
        $session = api_get_session_entity($session_id);
4094
        //$group = api_get_group_entity(api_get_group_id());
4095
4096
        $qb = $repo->getResourcesByCourseLinkedToUser($user, $course, $session);
4097
4098
        $qb->select('count(resource)');
4099
4100
        return $qb->getQuery()->getSingleScalarResult();
4101
    }
4102
4103
    /**
4104
     * This function counts the number of post by course.
4105
     *
4106
     * @param string $course_code
4107
     * @param int    $session_id  (optional), if is null(default) it'll return results including sessions,
4108
     *                            0 = session is not filtered
4109
     * @param int    $groupId
4110
     *
4111
     * @return int The number of post by course
4112
     */
4113
    public static function count_number_of_posts_by_course($course_code, $session_id = null, $groupId = 0)
4114
    {
4115
        $courseInfo = api_get_course_info($course_code);
4116
        if (!empty($courseInfo)) {
4117
            $tbl_posts = Database::get_course_table(TABLE_FORUM_POST);
4118
            $tbl_forums = Database::get_course_table(TABLE_FORUM);
4119
4120
            $condition_session = '';
4121
            if (isset($session_id)) {
4122
                $session_id = (int) $session_id;
4123
                $condition_session = api_get_session_condition(
4124
                    $session_id,
4125
                    true,
4126
                    false,
4127
                    'f.session_id'
4128
                );
4129
            }
4130
4131
            $course_id = $courseInfo['real_id'];
4132
            $groupId = (int) $groupId;
4133
            if (!empty($groupId)) {
4134
                $groupCondition = " i.to_group_id = $groupId ";
4135
            } else {
4136
                $groupCondition = ' (i.to_group_id = 0 OR i.to_group_id IS NULL) ';
4137
            }
4138
4139
            $item = Database::get_course_table(TABLE_ITEM_PROPERTY);
4140
            $sql = "SELECT count(*) FROM $tbl_posts p
4141
                    INNER JOIN $tbl_forums f
4142
                    ON f.forum_id = p.forum_id AND p.c_id = f.c_id
4143
                    INNER JOIN $item i
4144
                    ON (tool = '".TOOL_FORUM."' AND f.c_id = i.c_id AND f.iid = i.ref)
4145
                    WHERE
4146
                        p.c_id = $course_id AND
4147
                        f.c_id = $course_id AND
4148
                        $groupCondition
4149
                        $condition_session
4150
                    ";
4151
            $result = Database::query($sql);
4152
            $row = Database::fetch_row($result);
4153
            $count = $row[0];
4154
4155
            return $count;
4156
        }
4157
4158
        return 0;
4159
    }
4160
4161
    /**
4162
     * This function counts the number of threads by course.
4163
     *
4164
     * @param      string     Course code
4165
     * @param    int        Session id (optional),
4166
     * if param $session_id is null(default) it'll return results including
4167
     * sessions, 0 = session is not filtered
4168
     * @param int $groupId
4169
     *
4170
     * @return int The number of threads by course
4171
     */
4172
    public static function count_number_of_threads_by_course(
4173
        $course_code,
4174
        $session_id = null,
4175
        $groupId = 0
4176
    ) {
4177
        $course_info = api_get_course_info($course_code);
4178
        if (empty($course_info)) {
4179
            return null;
4180
        }
4181
4182
        $course_id = $course_info['real_id'];
4183
        $tbl_threads = Database::get_course_table(TABLE_FORUM_THREAD);
4184
        $tbl_forums = Database::get_course_table(TABLE_FORUM);
4185
4186
        $condition_session = '';
4187
        if (isset($session_id)) {
4188
            $session_id = (int) $session_id;
4189
            $condition_session = ' AND f.session_id = '.$session_id;
4190
        }
4191
4192
        $groupId = (int) $groupId;
4193
4194
        if (!empty($groupId)) {
4195
            $groupCondition = " i.to_group_id = $groupId ";
4196
        } else {
4197
            $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) ";
4198
        }
4199
4200
        $item = Database::get_course_table(TABLE_ITEM_PROPERTY);
4201
        $sql = "SELECT count(*)
4202
                FROM $tbl_threads t
4203
                INNER JOIN $tbl_forums f
4204
                ON f.iid = t.forum_id AND f.c_id = t.c_id
4205
                INNER JOIN $item i
4206
                ON (
4207
                    tool = '".TOOL_FORUM_THREAD."' AND
4208
                    f.c_id = i.c_id AND
4209
                    t.iid = i.ref
4210
                )
4211
                WHERE
4212
                    t.c_id = $course_id AND
4213
                    f.c_id = $course_id AND
4214
                    $groupCondition
4215
                    $condition_session
4216
                ";
4217
4218
        $result = Database::query($sql);
4219
        if (Database::num_rows($result)) {
4220
            $row = Database::fetch_row($result);
4221
            $count = $row[0];
4222
4223
            return $count;
4224
        }
4225
4226
        return 0;
4227
    }
4228
4229
    /**
4230
     * This function counts the number of forums by course.
4231
     *
4232
     * @param      string     Course code
4233
     * @param    int        Session id (optional),
4234
     * if param $session_id is null(default) it'll return results
4235
     * including sessions, 0 = session is not filtered
4236
     * @param int $groupId
4237
     *
4238
     * @return int The number of forums by course
4239
     */
4240
    public static function count_number_of_forums_by_course(
4241
        $course_code,
4242
        $session_id = null,
4243
        $groupId = 0
4244
    ) {
4245
        $course_info = api_get_course_info($course_code);
4246
        if (empty($course_info)) {
4247
            return null;
4248
        }
4249
        $course_id = $course_info['real_id'];
4250
4251
        $condition_session = '';
4252
        if (isset($session_id)) {
4253
            $session_id = (int) $session_id;
4254
            $condition_session = ' AND f.session_id = '.$session_id;
4255
        }
4256
4257
        $groupId = (int) $groupId;
4258
        if (!empty($groupId)) {
4259
            $groupCondition = " i.to_group_id = $groupId ";
4260
        } else {
4261
            $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) ";
4262
        }
4263
4264
        $tbl_forums = Database::get_course_table(TABLE_FORUM);
4265
        $item = Database::get_course_table(TABLE_ITEM_PROPERTY);
4266
4267
        $sql = "SELECT count(*)
4268
                FROM $tbl_forums f
4269
                INNER JOIN $item i
4270
                ON f.c_id = i.c_id AND f.iid = i.ref AND tool = '".TOOL_FORUM."'
4271
                WHERE
4272
                    f.c_id = $course_id AND
4273
                    $groupCondition
4274
                    $condition_session
4275
                ";
4276
        $result = Database::query($sql);
4277
        if (Database::num_rows($result)) {
4278
            $row = Database::fetch_row($result);
4279
            $count = $row[0];
4280
4281
            return $count;
4282
        }
4283
4284
        return 0;
4285
    }
4286
4287
    /**
4288
     * This function counts the chat last connections by course in x days.
4289
     *
4290
     * @param      string     Course code
4291
     * @param      int     Last x days
4292
     * @param    int        Session id (optional)
4293
     *
4294
     * @return int Chat last connections by course in x days
4295
     */
4296
    public static function chat_connections_during_last_x_days_by_course(
4297
        $course_code,
4298
        $last_days,
4299
        $session_id = 0
4300
    ) {
4301
        $course_info = api_get_course_info($course_code);
4302
        if (empty($course_info)) {
4303
            return null;
4304
        }
4305
        $course_id = $course_info['real_id'];
4306
4307
        // Protect data
4308
        $last_days = (int) $last_days;
4309
        $session_id = (int) $session_id;
4310
4311
        $tbl_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
4312
        $now = api_get_utc_datetime();
4313
4314
        $sql = "SELECT count(*) FROM $tbl_stats_access
4315
                WHERE
4316
                    DATE_SUB('$now',INTERVAL $last_days DAY) <= access_date AND
4317
                    c_id = '$course_id' AND
4318
                    access_tool='".TOOL_CHAT."' AND
4319
                    access_session_id = '$session_id' ";
4320
        $result = Database::query($sql);
4321
        if (Database::num_rows($result)) {
4322
            $row = Database::fetch_row($result);
4323
            $count = $row[0];
4324
4325
            return $count;
4326
        }
4327
4328
        return 0;
4329
    }
4330
4331
    /**
4332
     * This function gets the last student's connection in chat.
4333
     *
4334
     * @param      int     Student id
4335
     * @param      string     Course code
4336
     * @param    int        Session id (optional)
4337
     *
4338
     * @return string datetime formatted without day (e.g: February 23, 2010 10:20:50 )
4339
     */
4340
    public static function chat_last_connection(
4341
        $student_id,
4342
        $courseId,
4343
        $session_id = 0
4344
    ) {
4345
        $student_id = (int) $student_id;
4346
        $courseId = (int) $courseId;
4347
        $session_id = (int) $session_id;
4348
        $date_time = '';
4349
4350
        // table definition
4351
        $tbl_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4352
        $sql = "SELECT access_date
4353
                FROM $tbl_stats_access
4354
                WHERE
4355
                     access_tool='".TOOL_CHAT."' AND
4356
                     access_user_id='$student_id' AND
4357
                     c_id = $courseId AND
4358
                     access_session_id = '$session_id'
4359
                ORDER BY access_date DESC limit 1";
4360
        $rs = Database::query($sql);
4361
        if (Database::num_rows($rs) > 0) {
4362
            $row = Database::fetch_array($rs);
4363
            $date_time = api_convert_and_format_date(
4364
                $row['access_date'],
4365
                null,
4366
                date_default_timezone_get()
4367
            );
4368
        }
4369
4370
        return $date_time;
4371
    }
4372
4373
    /**
4374
     * Get count student's visited links.
4375
     *
4376
     * @param int $student_id Student id
4377
     * @param int $courseId
4378
     * @param int $session_id Session id (optional)
4379
     *
4380
     * @return int count of visited links
4381
     */
4382
    public static function count_student_visited_links($student_id, $courseId, $session_id = 0)
4383
    {
4384
        $student_id = (int) $student_id;
4385
        $courseId = (int) $courseId;
4386
        $session_id = (int) $session_id;
4387
4388
        // table definition
4389
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
4390
4391
        $sql = 'SELECT 1
4392
                FROM '.$table.'
4393
                WHERE
4394
                    links_user_id= '.$student_id.' AND
4395
                    c_id = "'.$courseId.'" AND
4396
                    links_session_id = '.$session_id.' ';
4397
4398
        $rs = Database::query($sql);
4399
4400
        return Database::num_rows($rs);
4401
    }
4402
4403
    /**
4404
     * Get count student downloaded documents.
4405
     *
4406
     * @param    int        Student id
4407
     * @param int $courseId
4408
     * @param    int        Session id (optional)
4409
     *
4410
     * @return int Count downloaded documents
4411
     */
4412
    public static function count_student_downloaded_documents($student_id, $courseId, $session_id = 0)
4413
    {
4414
        $student_id = (int) $student_id;
4415
        $courseId = (int) $courseId;
4416
        $session_id = (int) $session_id;
4417
4418
        // table definition
4419
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
4420
4421
        $sql = 'SELECT 1
4422
                FROM '.$table.'
4423
                WHERE down_user_id = '.$student_id.'
4424
                AND c_id  = "'.$courseId.'"
4425
                AND down_session_id = '.$session_id.' ';
4426
        $rs = Database::query($sql);
4427
4428
        return Database::num_rows($rs);
4429
    }
4430
4431
    /**
4432
     * Get course list inside a session from a student.
4433
     *
4434
     * @param int $user_id    Student id
4435
     * @param int $id_session Session id (optional)
4436
     *
4437
     * @return array Courses list
4438
     */
4439
    public static function get_course_list_in_session_from_student($user_id, $id_session = 0)
4440
    {
4441
        $user_id = intval($user_id);
4442
        $id_session = intval($id_session);
4443
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4444
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
4445
4446
        $sql = "SELECT c.code
4447
                FROM $tbl_session_course_user sc
4448
                INNER JOIN $courseTable c
4449
                WHERE
4450
                    user_id= $user_id  AND
4451
                    session_id = $id_session";
4452
        $result = Database::query($sql);
4453
        $courses = [];
4454
        while ($row = Database::fetch_array($result)) {
4455
            $courses[$row['code']] = $row['code'];
4456
        }
4457
4458
        return $courses;
4459
    }
4460
4461
    /**
4462
     * Get inactive students in course.
4463
     *
4464
     * @param int        $courseId
4465
     * @param string|int $since      Since login course date (optional, default = 'never')
4466
     * @param int        $session_id (optional)
4467
     *
4468
     * @return array Inactive users
4469
     */
4470
    public static function getInactiveStudentsInCourse(
4471
        $courseId,
4472
        $since = 'never',
4473
        $session_id = 0
4474
    ) {
4475
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
4476
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4477
        $table_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4478
        $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
4479
        $now = api_get_utc_datetime();
4480
        $courseId = (int) $courseId;
4481
        $session_id = (int) $session_id;
4482
4483
        if (empty($courseId)) {
4484
            return false;
4485
        }
4486
4487
        if ('never' === $since) {
4488
            if (empty($session_id)) {
4489
                $sql = 'SELECT course_user.user_id
4490
                        FROM '.$table_course_rel_user.' course_user
4491
                        LEFT JOIN '.$tbl_track_login.' stats_login
4492
                        ON course_user.user_id = stats_login.user_id AND
4493
                        relation_type<>'.COURSE_RELATION_TYPE_RRHH.'
4494
                        INNER JOIN '.$tableCourse.' c
4495
                        ON (c.id = course_user.c_id)
4496
                        WHERE
4497
                            course_user.c_id = '.$courseId.' AND
4498
                            stats_login.login_course_date IS NULL
4499
                        GROUP BY course_user.user_id';
4500
            } else {
4501
                $sql = 'SELECT session_course_user.user_id
4502
                        FROM '.$tbl_session_course_user.' session_course_user
4503
                        LEFT JOIN '.$tbl_track_login.' stats_login
4504
                        ON session_course_user.user_id = stats_login.user_id
4505
                        INNER JOIN '.$tableCourse.' c
4506
                        ON (c.id = session_course_user.c_id)
4507
                        WHERE
4508
                            session_course_user.c_id = '.$courseId.' AND
4509
                            stats_login.login_course_date IS NULL
4510
                        GROUP BY session_course_user.user_id';
4511
            }
4512
        } else {
4513
            $since = (int) $since;
4514
            if (empty($session_id)) {
4515
                $inner = 'INNER JOIN '.$table_course_rel_user.' course_user
4516
                          ON course_user.user_id = stats_login.user_id AND course_user.c_id = c.id ';
4517
            } else {
4518
                $inner = 'INNER JOIN '.$tbl_session_course_user.' session_course_user
4519
                          ON
4520
                            c.id = session_course_user.c_id AND
4521
                            session_course_user.session_id = '.$session_id.' AND
4522
                            session_course_user.user_id = stats_login.user_id ';
4523
            }
4524
4525
            $sql = 'SELECT
4526
                    stats_login.user_id,
4527
                    MAX(login_course_date) max_date
4528
                FROM '.$tbl_track_login.' stats_login
4529
                INNER JOIN '.$tableCourse.' c
4530
                ON (c.id = stats_login.c_id)
4531
                '.$inner.'
4532
                WHERE c.id = '.$courseId.'
4533
                GROUP BY stats_login.user_id
4534
                HAVING DATE_SUB("'.$now.'", INTERVAL '.$since.' DAY) > max_date ';
4535
        }
4536
4537
        $rs = Database::query($sql);
4538
4539
        $allow = 'true' === api_get_plugin_setting('pausetraining', 'tool_enable');
4540
        $allowPauseFormation = 'true' === api_get_plugin_setting('pausetraining', 'allow_users_to_edit_pause_formation');
4541
4542
        $extraFieldValue = new ExtraFieldValue('user');
4543
        $users = [];
4544
        while ($user = Database::fetch_array($rs)) {
4545
            $userId = $user['user_id'];
4546
4547
            if ($allow && $allowPauseFormation) {
4548
                $pause = $extraFieldValue->get_values_by_handler_and_field_variable($userId, 'pause_formation');
4549
                if (!empty($pause) && isset($pause['value']) && 1 == $pause['value']) {
4550
                    // Skip user because he paused his formation.
4551
                    continue;
4552
                }
4553
            }
4554
4555
            $users[] = $userId;
4556
        }
4557
4558
        return $users;
4559
    }
4560
4561
    /**
4562
     * get count clicks about tools most used by course.
4563
     *
4564
     * @param int $courseId
4565
     * @param    int        Session id (optional),
4566
     * if param $session_id is null(default) it'll return results
4567
     * including sessions, 0 = session is not filtered
4568
     *
4569
     * @return array tools data
4570
     */
4571
    public static function get_tools_most_used_by_course($courseId, $session_id = null)
4572
    {
4573
        $courseId = (int) $courseId;
4574
        $data = [];
4575
        $TABLETRACK_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4576
        $condition_session = '';
4577
        if (isset($session_id)) {
4578
            $session_id = (int) $session_id;
4579
            $condition_session = ' AND access_session_id = '.$session_id;
4580
        }
4581
        $sql = "SELECT
4582
                    access_tool,
4583
                    COUNT(DISTINCT access_user_id),
4584
                    count(access_tool) as count_access_tool
4585
                FROM $TABLETRACK_ACCESS
4586
                WHERE
4587
                    access_tool IS NOT NULL AND
4588
                    access_tool != '' AND
4589
                    c_id = '$courseId'
4590
                    $condition_session
4591
                GROUP BY access_tool
4592
                ORDER BY count_access_tool DESC
4593
                LIMIT 0, 3";
4594
        $rs = Database::query($sql);
4595
        if (Database::num_rows($rs) > 0) {
4596
            while ($row = Database::fetch_array($rs)) {
4597
                $data[] = $row;
4598
            }
4599
        }
4600
4601
        return $data;
4602
    }
4603
4604
    /**
4605
     * get documents most downloaded by course.
4606
     *
4607
     * @param      string     Course code
4608
     * @param    int        Session id (optional),
4609
     * if param $session_id is null(default) it'll return results including
4610
     * sessions, 0 = session is not filtered
4611
     * @param    int        Limit (optional, default = 0, 0 = without limit)
4612
     *
4613
     * @return array documents downloaded
4614
     */
4615
    public static function get_documents_most_downloaded_by_course(
4616
        $course_code,
4617
        $session_id = 0,
4618
        $limit = 0
4619
    ) {
4620
        $courseId = api_get_course_int_id($course_code);
4621
        $data = [];
4622
4623
        $TABLETRACK_DOWNLOADS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
4624
        $condition_session = '';
4625
        $session_id = intval($session_id);
4626
        if (!empty($session_id)) {
4627
            $condition_session = ' AND down_session_id = '.$session_id;
4628
        }
4629
        $sql = "SELECT
4630
                    down_doc_path,
4631
                    COUNT(DISTINCT down_user_id),
4632
                    COUNT(down_doc_path) as count_down
4633
                FROM $TABLETRACK_DOWNLOADS
4634
                WHERE c_id = $courseId
4635
                    $condition_session
4636
                GROUP BY down_doc_path
4637
                ORDER BY count_down DESC
4638
                LIMIT 0,  $limit";
4639
        $rs = Database::query($sql);
4640
4641
        if (Database::num_rows($rs) > 0) {
4642
            while ($row = Database::fetch_array($rs)) {
4643
                $data[] = $row;
4644
            }
4645
        }
4646
4647
        return $data;
4648
    }
4649
4650
    /**
4651
     * get links most visited by course.
4652
     *
4653
     * @param      string     Course code
4654
     * @param    int        Session id (optional),
4655
     * if param $session_id is null(default) it'll
4656
     * return results including sessions, 0 = session is not filtered
4657
     *
4658
     * @return array links most visited
4659
     */
4660
    public static function get_links_most_visited_by_course($course_code, $session_id = null)
4661
    {
4662
        $course_code = Database::escape_string($course_code);
4663
        $course_info = api_get_course_info($course_code);
4664
        $course_id = $course_info['real_id'];
4665
        $data = [];
4666
4667
        $TABLETRACK_LINKS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
4668
        $TABLECOURSE_LINKS = Database::get_course_table(TABLE_LINK);
4669
4670
        $condition_session = '';
4671
        if (isset($session_id)) {
4672
            $session_id = intval($session_id);
4673
            $condition_session = ' AND cl.session_id = '.$session_id;
4674
        }
4675
4676
        $sql = "SELECT cl.title, cl.url,count(DISTINCT sl.links_user_id), count(cl.title) as count_visits
4677
                FROM $TABLETRACK_LINKS AS sl, $TABLECOURSE_LINKS AS cl
4678
                WHERE
4679
                    cl.c_id = $course_id AND
4680
                    sl.links_link_id = cl.id AND
4681
                    sl.c_id = $course_id
4682
                    $condition_session
4683
                GROUP BY cl.title, cl.url
4684
                ORDER BY count_visits DESC
4685
                LIMIT 0, 3";
4686
        $rs = Database::query($sql);
4687
        if (Database::num_rows($rs) > 0) {
4688
            while ($row = Database::fetch_array($rs)) {
4689
                $data[] = $row;
4690
            }
4691
        }
4692
4693
        return $data;
4694
    }
4695
4696
    /**
4697
     * Shows the user progress (when clicking in the Progress tab).
4698
     *
4699
     * @param int    $user_id
4700
     * @param int    $session_id
4701
     * @param string $extra_params
4702
     * @param bool   $show_courses
4703
     * @param bool   $showAllSessions
4704
     * @param bool   $returnArray
4705
     *
4706
     * @return string|array
4707
     */
4708
    public static function show_user_progress(
4709
        $user_id,
4710
        $session_id = 0,
4711
        $extra_params = '',
4712
        $show_courses = true,
4713
        $showAllSessions = true,
4714
        $returnArray = false
4715
    ) {
4716
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
4717
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
4718
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4719
        $tbl_access_rel_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4720
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4721
        $tbl_access_rel_session = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
4722
4723
        $trackingColumns = [
4724
            'course_session' => [
4725
                'course_title' => true,
4726
                'published_exercises' => true,
4727
                'new_exercises' => true,
4728
                'my_average' => true,
4729
                'average_exercise_result' => true,
4730
                'time_spent' => true,
4731
                'lp_progress' => true,
4732
                'score' => true,
4733
                'best_score' => true,
4734
                'last_connection' => true,
4735
                'details' => true,
4736
            ],
4737
        ];
4738
4739
        $trackingColumnsConfig = api_get_configuration_value('tracking_columns');
4740
        if (!empty($trackingColumnsConfig)) {
4741
            $trackingColumns = $trackingColumnsConfig;
4742
        }
4743
4744
        $user_id = (int) $user_id;
4745
        $session_id = (int) $session_id;
4746
        $urlId = api_get_current_access_url_id();
4747
4748
        if (api_is_multiple_url_enabled()) {
4749
            $sql = "SELECT c.id, c.code, title
4750
                    FROM $tbl_course_user cu
4751
                    INNER JOIN $tbl_course c
4752
                    ON (cu.c_id = c.id)
4753
                    INNER JOIN $tbl_access_rel_course a
4754
                    ON (a.c_id = c.id)
4755
                    WHERE
4756
                        cu.user_id = $user_id AND
4757
                        relation_type<> ".COURSE_RELATION_TYPE_RRHH." AND
4758
                        access_url_id = $urlId
4759
                    ORDER BY title";
4760
        } else {
4761
            $sql = "SELECT c.id, c.code, title
4762
                    FROM $tbl_course_user u
4763
                    INNER JOIN $tbl_course c ON (c_id = c.id)
4764
                    WHERE
4765
                        u.user_id= $user_id AND
4766
                        relation_type <> ".COURSE_RELATION_TYPE_RRHH."
4767
                    ORDER BY title";
4768
        }
4769
4770
        $rs = Database::query($sql);
4771
        $courses = $course_in_session = $temp_course_in_session = [];
4772
        $courseIdList = [];
4773
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4774
            $courses[$row['code']] = $row['title'];
4775
            $courseIdList[] = $row['id'];
4776
        }
4777
4778
        $orderBy = ' ORDER BY name ';
4779
        $extraInnerJoin = null;
4780
4781
        if (SessionManager::orderCourseIsEnabled() && !empty($session_id)) {
4782
            $orderBy = ' ORDER BY s.id, src.position ';
4783
            $tableSessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
4784
            $extraInnerJoin = " INNER JOIN $tableSessionRelCourse src
4785
                                ON (cu.c_id = src.c_id AND src.session_id = $session_id) ";
4786
        }
4787
4788
        $sessionCondition = '';
4789
        if (!empty($session_id)) {
4790
            $sessionCondition = " AND s.id = $session_id";
4791
        }
4792
4793
        // Get the list of sessions where the user is subscribed as student
4794
        if (api_is_multiple_url_enabled()) {
4795
            $sql = "SELECT DISTINCT c.code, s.id as session_id, name
4796
                    FROM $tbl_session_course_user cu
4797
                    INNER JOIN $tbl_access_rel_session a
4798
                    ON (a.session_id = cu.session_id)
4799
                    INNER JOIN $tbl_session s
4800
                    ON (s.id = a.session_id)
4801
                    INNER JOIN $tbl_course c
4802
                    ON (c.id = cu.c_id)
4803
                    $extraInnerJoin
4804
                    WHERE
4805
                        cu.user_id = $user_id AND
4806
                        access_url_id = ".$urlId."
4807
                        $sessionCondition
4808
                    $orderBy ";
4809
        } else {
4810
            $sql = "SELECT DISTINCT c.code, s.id as session_id, name
4811
                    FROM $tbl_session_course_user cu
4812
                    INNER JOIN $tbl_session s
4813
                    ON (s.id = cu.session_id)
4814
                    INNER JOIN $tbl_course c
4815
                    ON (c.id = cu.c_id)
4816
                    $extraInnerJoin
4817
                    WHERE
4818
                        cu.user_id = $user_id
4819
                        $sessionCondition
4820
                    $orderBy ";
4821
        }
4822
4823
        $rs = Database::query($sql);
4824
        $simple_session_array = [];
4825
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4826
            $course_info = api_get_course_info($row['code']);
4827
            $temp_course_in_session[$row['session_id']]['course_list'][$course_info['real_id']] = $course_info;
4828
            $temp_course_in_session[$row['session_id']]['name'] = $row['name'];
4829
            $simple_session_array[$row['session_id']] = $row['name'];
4830
        }
4831
4832
        foreach ($simple_session_array as $my_session_id => $session_name) {
4833
            $course_list = $temp_course_in_session[$my_session_id]['course_list'];
4834
            $my_course_data = [];
4835
            foreach ($course_list as $courseId => $course_data) {
4836
                $my_course_data[$courseId] = $course_data['title'];
4837
            }
4838
4839
            if (empty($session_id)) {
4840
                $my_course_data = utf8_sort($my_course_data);
4841
            }
4842
4843
            $final_course_data = [];
4844
            foreach ($my_course_data as $course_id => $value) {
4845
                if (isset($course_list[$course_id])) {
4846
                    $final_course_data[$course_id] = $course_list[$course_id];
4847
                }
4848
            }
4849
            $course_in_session[$my_session_id]['course_list'] = $final_course_data;
4850
            $course_in_session[$my_session_id]['name'] = $session_name;
4851
        }
4852
4853
        if ($returnArray) {
4854
            $course_in_session[0] = $courseIdList;
4855
4856
            return $course_in_session;
4857
        }
4858
4859
        $html = '';
4860
        // Course list
4861
        if ($show_courses) {
4862
            if (!empty($courses)) {
4863
                $html .= Display::page_subheader(
4864
                    Display::return_icon(
4865
                        'course.png',
4866
                        get_lang('My courses'),
4867
                        [],
4868
                        ICON_SIZE_SMALL
4869
                    ).' '.get_lang('My courses')
4870
                );
4871
4872
                $columns = [
4873
                    'course_title' => get_lang('Course'),
4874
                    'time_spent' => get_lang('Time spent in the course'),
4875
                    'progress' => get_lang('Progress'),
4876
                    'best_score_in_lp' => get_lang('Best score in learning path'),
4877
                    'best_score_not_in_lp' => get_lang('Best score not in learning path'),
4878
                    'latest_login' => get_lang('Latest login'),
4879
                    'details' => get_lang('Details'),
4880
                ];
4881
                $availableColumns = [];
4882
                if (isset($trackingColumns['my_progress_courses'])) {
4883
                    $availableColumns = $trackingColumns['my_progress_courses'];
4884
                }
4885
                $html .= '<div class="table-responsive">';
4886
                $html .= '<table class="table table-striped table-hover">';
4887
                $html .= '<thead><tr>';
4888
                foreach ($columns as $columnKey => $name) {
4889
                    if (!empty($availableColumns)) {
4890
                        if (isset($availableColumns[$columnKey]) && false == $availableColumns[$columnKey]) {
4891
                            continue;
4892
                        }
4893
                    }
4894
                    $html .= Display::tag('th', $name);
4895
                }
4896
                $html .= '</tr></thead><tbody>';
4897
4898
                foreach ($courses as $course_code => $course_title) {
4899
                    $courseInfo = api_get_course_info($course_code);
4900
                    $courseId = $courseInfo['real_id'];
4901
4902
                    $total_time_login = self::get_time_spent_on_the_course(
4903
                        $user_id,
4904
                        $courseId
4905
                    );
4906
                    $time = api_time_to_hms($total_time_login);
4907
                    $progress = self::get_avg_student_progress(
4908
                        $user_id,
4909
                        $course_code
4910
                    );
4911
                    $bestScore = self::get_avg_student_score(
4912
                        $user_id,
4913
                        $course_code,
4914
                        [],
4915
                        null,
4916
                        false,
4917
                        false,
4918
                        true
4919
                    );
4920
4921
                    $exerciseList = ExerciseLib::get_all_exercises(
4922
                        $courseInfo,
4923
                        0,
4924
                        false,
4925
                        null,
4926
                        false,
4927
                        1
4928
                    );
4929
4930
                    $bestScoreAverageNotInLP = 0;
4931
                    if (!empty($exerciseList)) {
4932
                        foreach ($exerciseList as $exerciseData) {
4933
                            $results = Event::get_best_exercise_results_by_user(
4934
                                $exerciseData['id'],
4935
                                $courseInfo['real_id'],
4936
                                0,
4937
                                $user_id
4938
                            );
4939
                            $best = 0;
4940
                            if (!empty($results)) {
4941
                                foreach ($results as $result) {
4942
                                    if (!empty($result['max_score'])) {
4943
                                        $score = $result['score'] / $result['max_score'];
4944
                                        if ($score > $best) {
4945
                                            $best = $score;
4946
                                        }
4947
                                    }
4948
                                }
4949
                            }
4950
                            $bestScoreAverageNotInLP += $best;
4951
                        }
4952
                        $bestScoreAverageNotInLP = round($bestScoreAverageNotInLP / count($exerciseList) * 100, 2);
4953
                    }
4954
4955
                    $last_connection = self::get_last_connection_date_on_the_course(
4956
                        $user_id,
4957
                        $courseInfo
4958
                    );
4959
4960
                    if (is_null($progress) || empty($progress)) {
4961
                        $progress = '0%';
4962
                    } else {
4963
                        $progress = $progress.'%';
4964
                    }
4965
4966
                    if (isset($_GET['course']) &&
4967
                        $course_code == $_GET['course'] &&
4968
                        empty($_GET['session_id'])
4969
                    ) {
4970
                        $html .= '<tr class="row_odd" style="background-color:#FBF09D">';
4971
                    } else {
4972
                        $html .= '<tr class="row_even">';
4973
                    }
4974
                    $url = api_get_course_url($course_code, $session_id);
4975
                    $course_url = Display::url($course_title, $url, ['target' => SESSION_LINK_TARGET]);
4976
                    $bestScoreResult = '';
4977
                    if (empty($bestScore)) {
4978
                        $bestScoreResult = '-';
4979
                    } else {
4980
                        $bestScoreResult = $bestScore.'%';
4981
                    }
4982
                    $bestScoreNotInLP = '';
4983
                    if (empty($bestScoreAverageNotInLP)) {
4984
                        $bestScoreNotInLP = '-';
4985
                    } else {
4986
                        $bestScoreNotInLP = $bestScoreAverageNotInLP.'%';
4987
                    }
4988
4989
                    $detailsLink = '';
4990
                    if (isset($_GET['course']) &&
4991
                        $course_code == $_GET['course'] &&
4992
                        empty($_GET['session_id'])
4993
                    ) {
4994
                        $detailsLink .= '<a href="#course_session_header">';
4995
                        $detailsLink .= Display::return_icon('2rightarrow_na.png', get_lang('Details'));
4996
                        $detailsLink .= '</a>';
4997
                    } else {
4998
                        $detailsLink .= '<a href="'.api_get_self().'?course='.$course_code.$extra_params.'#course_session_header">';
4999
                        $detailsLink .= Display::return_icon('2rightarrow.png', get_lang('Details'));
5000
                        $detailsLink .= '</a>';
5001
                    }
5002
5003
                    $result = [
5004
                        'course_title' => $course_url,
5005
                        'time_spent' => $time,
5006
                        'progress' => $progress,
5007
                        'best_score_in_lp' => $bestScoreResult,
5008
                        'best_score_not_in_lp' => $bestScoreNotInLP,
5009
                        'latest_login' => $last_connection,
5010
                        'details' => $detailsLink,
5011
                    ];
5012
5013
                    foreach ($result as $columnKey => $data) {
5014
                        if (!empty($availableColumns)) {
5015
                            if (isset($availableColumns[$columnKey]) && false == $availableColumns[$columnKey]) {
5016
                                continue;
5017
                            }
5018
                        }
5019
                        $html .= '<td>'.$data.'</td>';
5020
                    }
5021
5022
                    $html .= '</tr>';
5023
                }
5024
                $html .= '</tbody></table>';
5025
                $html .= '</div>';
5026
            }
5027
        }
5028
5029
        // Session list
5030
        if (!empty($course_in_session)) {
5031
            $main_session_graph = '';
5032
            // Load graphics only when calling to an specific session
5033
            $all_exercise_graph_name_list = [];
5034
            $my_results = [];
5035
            $all_exercise_graph_list = [];
5036
            $all_exercise_start_time = [];
5037
            foreach ($course_in_session as $my_session_id => $session_data) {
5038
                $course_list = $session_data['course_list'];
5039
                $user_count = count(SessionManager::get_users_by_session($my_session_id));
5040
                $exercise_graph_name_list = [];
5041
                $exercise_graph_list = [];
5042
5043
                foreach ($course_list as $course_data) {
5044
                    $exercise_list = ExerciseLib::get_all_exercises(
5045
                        $course_data,
5046
                        $my_session_id,
5047
                        false,
5048
                        null,
5049
                        false,
5050
                        1
5051
                    );
5052
5053
                    foreach ($exercise_list as $exercise_data) {
5054
                        $exercise_obj = new Exercise($course_data['real_id']);
5055
                        $exercise_obj->read($exercise_data['id']);
5056
                        // Exercise is not necessary to be visible to show results check the result_disable configuration instead
5057
                        //$visible_return = $exercise_obj->is_visible();
5058
                        if (0 == $exercise_data['results_disabled'] || 2 == $exercise_data['results_disabled']) {
5059
                            $best_average = (int)
5060
                                ExerciseLib::get_best_average_score_by_exercise(
5061
                                    $exercise_data['id'],
5062
                                    $course_data['real_id'],
5063
                                    $my_session_id,
5064
                                    $user_count
5065
                                )
5066
                            ;
5067
5068
                            $exercise_graph_list[] = $best_average;
5069
                            $all_exercise_graph_list[] = $best_average;
5070
5071
                            $user_result_data = ExerciseLib::get_best_attempt_by_user(
5072
                                api_get_user_id(),
5073
                                $exercise_data['id'],
5074
                                $course_data['real_id'],
5075
                                $my_session_id
5076
                            );
5077
5078
                            $score = 0;
5079
                            if (!empty($user_result_data['max_score']) && 0 != intval($user_result_data['max_score'])) {
5080
                                $score = intval($user_result_data['score'] / $user_result_data['max_score'] * 100);
5081
                            }
5082
                            $time = api_strtotime($exercise_data['start_time']) ? api_strtotime($exercise_data['start_time'], 'UTC') : 0;
5083
                            $all_exercise_start_time[] = $time;
5084
                            $my_results[] = $score;
5085
                            if (count($exercise_list) <= 10) {
5086
                                $title = cut($course_data['title'], 30)." \n ".cut($exercise_data['title'], 30);
5087
                                $exercise_graph_name_list[] = $title;
5088
                                $all_exercise_graph_name_list[] = $title;
5089
                            } else {
5090
                                // if there are more than 10 results, space becomes difficult to find,
5091
                                // so only show the title of the exercise, not the tool
5092
                                $title = cut($exercise_data['title'], 30);
5093
                                $exercise_graph_name_list[] = $title;
5094
                                $all_exercise_graph_name_list[] = $title;
5095
                            }
5096
                        }
5097
                    }
5098
                }
5099
            }
5100
5101
            // Complete graph
5102
            if (!empty($my_results) && !empty($all_exercise_graph_list)) {
5103
                asort($all_exercise_start_time);
5104
5105
                //Fix exams order
5106
                $final_all_exercise_graph_name_list = [];
5107
                $my_results_final = [];
5108
                $final_all_exercise_graph_list = [];
5109
5110
                foreach ($all_exercise_start_time as $key => $time) {
5111
                    $label_time = '';
5112
                    if (!empty($time)) {
5113
                        $label_time = date('d-m-y', $time);
5114
                    }
5115
                    $final_all_exercise_graph_name_list[] = $all_exercise_graph_name_list[$key].' '.$label_time;
5116
                    $my_results_final[] = $my_results[$key];
5117
                    $final_all_exercise_graph_list[] = $all_exercise_graph_list[$key];
5118
                }
5119
                $main_session_graph = self::generate_session_exercise_graph(
5120
                    $final_all_exercise_graph_name_list,
5121
                    $my_results_final,
5122
                    $final_all_exercise_graph_list
5123
                );
5124
            }
5125
5126
            $sessionIcon = Display::return_icon(
5127
                'session.png',
5128
                get_lang('Course sessions'),
5129
                [],
5130
                ICON_SIZE_SMALL
5131
            );
5132
5133
            $anchor = Display::url('', '', ['name' => 'course_session_header']);
5134
            $html .= $anchor.Display::page_subheader(
5135
                $sessionIcon.' '.get_lang('Course sessions')
5136
            );
5137
5138
            $html .= '<div class="table-responsive">';
5139
            $html .= '<table class="table table-striped table-hover">';
5140
            $html .= '<thead>';
5141
            $html .= '<tr>
5142
                  '.Display::tag('th', get_lang('Session'), ['width' => '300px']).'
5143
                  '.Display::tag('th', get_lang('Tests available'), ['width' => '300px']).'
5144
                  '.Display::tag('th', get_lang('New exercises')).'
5145
                  '.Display::tag('th', get_lang('Average exercise result')).'
5146
                  '.Display::tag('th', get_lang('Details')).'
5147
                  </tr>';
5148
            $html .= '</thead>';
5149
            $html .= '<tbody>';
5150
5151
            foreach ($course_in_session as $my_session_id => $session_data) {
5152
                $course_list = $session_data['course_list'];
5153
                $session_name = $session_data['name'];
5154
                if (false == $showAllSessions) {
5155
                    if (isset($session_id) && !empty($session_id)) {
5156
                        if ($session_id != $my_session_id) {
5157
                            continue;
5158
                        }
5159
                    }
5160
                }
5161
5162
                $all_exercises = 0;
5163
                $all_unanswered_exercises_by_user = 0;
5164
                $all_average = 0;
5165
                $stats_array = [];
5166
5167
                foreach ($course_list as $course_data) {
5168
                    // All exercises in the course @todo change for a real count
5169
                    $exercises = ExerciseLib::get_all_exercises($course_data, $my_session_id);
5170
                    $count_exercises = 0;
5171
                    if (is_array($exercises) && !empty($exercises)) {
5172
                        $count_exercises = count($exercises);
5173
                    }
5174
5175
                    // Count of user results
5176
                    $done_exercises = null;
5177
                    $courseInfo = api_get_course_info($course_data['code']);
5178
5179
                    $answered_exercises = 0;
5180
                    if (!empty($exercises)) {
5181
                        foreach ($exercises as $exercise_item) {
5182
                            $attempts = Event::count_exercise_attempts_by_user(
5183
                                api_get_user_id(),
5184
                                $exercise_item['id'],
5185
                                $courseInfo['real_id'],
5186
                                $my_session_id
5187
                            );
5188
                            if ($attempts > 1) {
5189
                                $answered_exercises++;
5190
                            }
5191
                        }
5192
                    }
5193
5194
                    // Average
5195
                    $average = ExerciseLib::get_average_score_by_course(
5196
                        $courseInfo['real_id'],
5197
                        $my_session_id
5198
                    );
5199
                    $all_exercises += $count_exercises;
5200
                    $all_unanswered_exercises_by_user += $count_exercises - $answered_exercises;
5201
                    $all_average += $average;
5202
                }
5203
5204
                if (!empty($course_list)) {
5205
                    $all_average = $all_average / count($course_list);
5206
                }
5207
5208
                if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) {
5209
                    $html .= '<tr style="background-color:#FBF09D">';
5210
                } else {
5211
                    $html .= '<tr>';
5212
                }
5213
                $url = api_get_path(WEB_CODE_PATH)."session/index.php?session_id={$my_session_id}";
5214
5215
                $html .= Display::tag('td', Display::url($session_name, $url, ['target' => SESSION_LINK_TARGET]));
5216
                $html .= Display::tag('td', $all_exercises);
5217
                $html .= Display::tag('td', $all_unanswered_exercises_by_user);
5218
                $html .= Display::tag('td', ExerciseLib::convert_to_percentage($all_average));
5219
5220
                if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) {
5221
                    $icon = Display::url(
5222
                        Display::return_icon(
5223
                            '2rightarrow_na.png',
5224
                            get_lang('Details')
5225
                        ),
5226
                        api_get_self().'?session_id='.$my_session_id.'#course_session_list'
5227
                    );
5228
                } else {
5229
                    $icon = Display::url(
5230
                        Display::return_icon(
5231
                            '2rightarrow.png',
5232
                            get_lang('Details')
5233
                        ),
5234
                        api_get_self().'?session_id='.$my_session_id.'#course_session_list'
5235
                    );
5236
                }
5237
                $html .= Display::tag('td', $icon);
5238
                $html .= '</tr>';
5239
            }
5240
            $html .= '</tbody>';
5241
            $html .= '</table></div><br />';
5242
            $html .= Display::div(
5243
                $main_session_graph,
5244
                [
5245
                    'id' => 'session_graph',
5246
                    'class' => 'chart-session',
5247
                    'style' => 'position:relative; text-align: center;',
5248
                ]
5249
            );
5250
5251
            // Checking selected session.
5252
            if (isset($_GET['session_id'])) {
5253
                $session_id_from_get = (int) $_GET['session_id'];
5254
                $session_data = $course_in_session[$session_id_from_get];
5255
                $course_list = $session_data['course_list'];
5256
5257
                $html .= '<a name= "course_session_list"></a>';
5258
                $html .= Display::tag('h3', $session_data['name'].' - '.get_lang('Course list'));
5259
5260
                $html .= '<div class="table-responsive">';
5261
                $html .= '<table class="table table-hover table-striped">';
5262
5263
                $columnHeaders = [
5264
                    'course_title' => [
5265
                        get_lang('Course'),
5266
                        ['width' => '300px'],
5267
                    ],
5268
                    'published_exercises' => [
5269
                        get_lang('Tests available'),
5270
                    ],
5271
                    'new_exercises' => [
5272
                        get_lang('New exercises'),
5273
                    ],
5274
                    'my_average' => [
5275
                        get_lang('My average'),
5276
                    ],
5277
                    'average_exercise_result' => [
5278
                        get_lang('Average exercise result'),
5279
                    ],
5280
                    'time_spent' => [
5281
                        get_lang('Time spent in the course'),
5282
                    ],
5283
                    'lp_progress' => [
5284
                        get_lang('Learning path progress'),
5285
                    ],
5286
                    'score' => [
5287
                        get_lang('Score').
5288
                        Display::return_icon(
5289
                            'info3.gif',
5290
                            get_lang('Average of tests in Learning Paths'),
5291
                            ['align' => 'absmiddle', 'hspace' => '3px']
5292
                        ),
5293
                    ],
5294
                    'best_score' => [
5295
                        get_lang('Best score'),
5296
                    ],
5297
                    'last_connection' => [
5298
                        get_lang('Latest login'),
5299
                    ],
5300
                    'details' => [
5301
                        get_lang('Details'),
5302
                    ],
5303
                ];
5304
5305
                $html .= '<thead><tr>';
5306
                foreach ($columnHeaders as $key => $columnSetting) {
5307
                    if (isset($trackingColumns['course_session']) &&
5308
                        in_array($key, $trackingColumns['course_session']) &&
5309
                        $trackingColumns['course_session'][$key]
5310
                    ) {
5311
                        $settings = isset($columnSetting[1]) ? $columnSetting[1] : [];
5312
                        $html .= Display::tag(
5313
                             'th',
5314
                             $columnSetting[0],
5315
                             $settings
5316
                         );
5317
                    }
5318
                }
5319
5320
                $html .= '</tr>
5321
                    </thead>
5322
                    <tbody>';
5323
5324
                foreach ($course_list as $course_data) {
5325
                    $course_code = $course_data['code'];
5326
                    $course_title = $course_data['title'];
5327
                    $courseId = $course_data['real_id'];
5328
5329
                    // All exercises in the course @todo change for a real count
5330
                    $exercises = ExerciseLib::get_all_exercises(
5331
                        $course_data,
5332
                        $session_id_from_get
5333
                    );
5334
                    $count_exercises = 0;
5335
                    if (!empty($exercises)) {
5336
                        $count_exercises = count($exercises);
5337
                    }
5338
                    $answered_exercises = 0;
5339
                    foreach ($exercises as $exercise_item) {
5340
                        $attempts = Event::count_exercise_attempts_by_user(
5341
                            api_get_user_id(),
5342
                            $exercise_item['id'],
5343
                            $courseId,
5344
                            $session_id_from_get
5345
                        );
5346
                        if ($attempts > 1) {
5347
                            $answered_exercises++;
5348
                        }
5349
                    }
5350
5351
                    $unanswered_exercises = $count_exercises - $answered_exercises;
5352
5353
                    // Average
5354
                    $average = ExerciseLib::get_average_score_by_course(
5355
                        $courseId,
5356
                        $session_id_from_get
5357
                    );
5358
                    $my_average = ExerciseLib::get_average_score_by_course_by_user(
5359
                        api_get_user_id(),
5360
                        $courseId,
5361
                        $session_id_from_get
5362
                    );
5363
5364
                    $bestScore = self::get_avg_student_score(
5365
                        $user_id,
5366
                        $course_code,
5367
                        [],
5368
                        $session_id_from_get,
5369
                        false,
5370
                        false,
5371
                        true
5372
                    );
5373
5374
                    $stats_array[$course_code] = [
5375
                        'exercises' => $count_exercises,
5376
                        'unanswered_exercises_by_user' => $unanswered_exercises,
5377
                        'done_exercises' => $done_exercises,
5378
                        'average' => $average,
5379
                        'my_average' => $my_average,
5380
                        'best_score' => $bestScore,
5381
                    ];
5382
5383
                    $last_connection = self::get_last_connection_date_on_the_course(
5384
                        $user_id,
5385
                        $course_data,
5386
                        $session_id_from_get
5387
                    );
5388
5389
                    $progress = self::get_avg_student_progress(
5390
                        $user_id,
5391
                        $course_code,
5392
                        [],
5393
                        $session_id_from_get
5394
                    );
5395
5396
                    $total_time_login = self::get_time_spent_on_the_course(
5397
                        $user_id,
5398
                        $courseId,
5399
                        $session_id_from_get
5400
                    );
5401
                    $time = api_time_to_hms($total_time_login);
5402
5403
                    $percentage_score = self::get_avg_student_score(
5404
                        $user_id,
5405
                        $course_code,
5406
                        [],
5407
                        $session_id_from_get
5408
                    );
5409
                    $courseCodeFromGet = isset($_GET['course']) ? $_GET['course'] : null;
5410
5411
                    if ($course_code == $courseCodeFromGet && $_GET['session_id'] == $session_id_from_get) {
5412
                        $html .= '<tr class="row_odd" style="background-color:#FBF09D" >';
5413
                    } else {
5414
                        $html .= '<tr class="row_even">';
5415
                    }
5416
5417
                    $url = api_get_course_url($course_code, $session_id_from_get);
5418
                    $course_url = Display::url(
5419
                        $course_title,
5420
                        $url,
5421
                        ['target' => SESSION_LINK_TARGET]
5422
                    );
5423
5424
                    if (is_numeric($progress)) {
5425
                        $progress = $progress.'%';
5426
                    } else {
5427
                        $progress = '0%';
5428
                    }
5429
                    if (is_numeric($percentage_score)) {
5430
                        $percentage_score = $percentage_score.'%';
5431
                    } else {
5432
                        $percentage_score = '0%';
5433
                    }
5434
5435
                    if (is_numeric($stats_array[$course_code]['best_score'])) {
5436
                        $bestScore = $stats_array[$course_code]['best_score'].'%';
5437
                    } else {
5438
                        $bestScore = '-';
5439
                    }
5440
5441
                    if (empty($last_connection) || is_bool($last_connection)) {
5442
                        $last_connection = '';
5443
                    }
5444
5445
                    if ($course_code == $courseCodeFromGet &&
5446
                        $_GET['session_id'] == $session_id_from_get
5447
                    ) {
5448
                        $details = Display::url(
5449
                            Display::return_icon('2rightarrow_na.png', get_lang('Details')),
5450
                        '#course_session_data'
5451
                        );
5452
                    } else {
5453
                        $url = api_get_self().'?course='.$course_code.'&session_id='.$session_id_from_get.$extra_params.'#course_session_data';
5454
                        $details = Display::url(
5455
                            Display::return_icon(
5456
                                '2rightarrow.png',
5457
                                get_lang('Details')
5458
                            ),
5459
                            $url
5460
                        );
5461
                    }
5462
                    $details .= '</a>';
5463
5464
                    $data = [
5465
                        'course_title' => $course_url,
5466
                        'published_exercises' => $stats_array[$course_code]['exercises'], // exercise available
5467
                        'new_exercises' => $stats_array[$course_code]['unanswered_exercises_by_user'],
5468
                        'my_average' => ExerciseLib::convert_to_percentage($stats_array[$course_code]['my_average']),
5469
                        'average_exercise_result' => 0 == $stats_array[$course_code]['average'] ? '-' : '('.ExerciseLib::convert_to_percentage($stats_array[$course_code]['average']).')',
5470
                        'time_spent' => $time,
5471
                        'lp_progress' => $progress,
5472
                        'score' => $percentage_score,
5473
                        'best_score' => $bestScore,
5474
                        'last_connection' => $last_connection,
5475
                        'details' => $details,
5476
                    ];
5477
5478
                    foreach ($data as $key => $value) {
5479
                        if (in_array($key, $trackingColumns['course_session'])
5480
                            && $trackingColumns['course_session'][$key]
5481
                        ) {
5482
                            $html .= Display::tag('td', $value);
5483
                        }
5484
                    }
5485
                    $html .= '</tr>';
5486
                }
5487
                $html .= '</tbody></table></div>';
5488
            }
5489
        }
5490
5491
        $pluginCalendar = 'true' === api_get_plugin_setting('learning_calendar', 'enabled');
5492
        if ($pluginCalendar) {
5493
            $course_in_session[0] = $courseIdList;
5494
            $plugin = LearningCalendarPlugin::create();
5495
            $html .= $plugin->getUserStatsPanel($user_id, $course_in_session);
5496
        }
5497
5498
        return $html;
5499
    }
5500
5501
    /**
5502
     * Shows the user detail progress (when clicking in the details link).
5503
     *
5504
     * @param int    $user_id
5505
     * @param string $course_code
5506
     * @param int    $session_id
5507
     *
5508
     * @return string html code
5509
     */
5510
    public static function show_course_detail($user_id, $course_code, $session_id)
5511
    {
5512
        $html = '';
5513
        if (isset($course_code)) {
5514
            $user_id = (int) $user_id;
5515
            $session_id = (int) $session_id;
5516
            $course = Database::escape_string($course_code);
5517
            $course_info = api_get_course_info($course);
5518
            if (empty($course_info)) {
5519
                return '';
5520
            }
5521
5522
            $html .= '<a name="course_session_data"></a>';
5523
            $html .= Display::page_subheader($course_info['title']);
5524
            $html .= '<div class="table-responsive">';
5525
            $html .= '<table class="table table-striped table-hover">';
5526
5527
            // Course details
5528
            $html .= '
5529
                <thead>
5530
                <tr>
5531
                <th>'.get_lang('Tests').'</th>
5532
                <th>'.get_lang('Attempts').'</th>
5533
                <th>'.get_lang('Best attempt').'</th>
5534
                <th>'.get_lang('Ranking').'</th>
5535
                <th>'.get_lang('Best result in course').'</th>
5536
                <th>'.get_lang('Statistics').' '.Display::return_icon('info3.gif', get_lang('In case of multiple attempts, only shows the best result of each learner'), ['align' => 'absmiddle', 'hspace' => '3px']).'</th>
5537
                </tr>
5538
                </thead>
5539
                <tbody>';
5540
5541
            if (empty($session_id)) {
5542
                $user_list = CourseManager::get_user_list_from_course_code(
5543
                    $course,
5544
                    $session_id,
5545
                    null,
5546
                    null,
5547
                    STUDENT
5548
                );
5549
            } else {
5550
                $user_list = CourseManager::get_user_list_from_course_code(
5551
                    $course,
5552
                    $session_id,
5553
                    null,
5554
                    null,
5555
                    0
5556
                );
5557
            }
5558
5559
            // Show exercise results of invisible exercises? see BT#4091
5560
            $exercise_list = ExerciseLib::get_all_exercises(
5561
                $course_info,
5562
                $session_id,
5563
                false,
5564
                null,
5565
                false,
5566
                2
5567
            );
5568
5569
            $to_graph_exercise_result = [];
5570
            if (!empty($exercise_list)) {
5571
                $score = $weighting = $exe_id = 0;
5572
                foreach ($exercise_list as $exercices) {
5573
                    $exercise_obj = new Exercise($course_info['real_id']);
5574
                    $exercise_obj->read($exercices['id']);
5575
                    $visible_return = $exercise_obj->is_visible();
5576
                    $score = $weighting = $attempts = 0;
5577
5578
                    // Getting count of attempts by user
5579
                    $attempts = Event::count_exercise_attempts_by_user(
5580
                        api_get_user_id(),
5581
                        $exercices['id'],
5582
                        $course_info['real_id'],
5583
                        $session_id
5584
                    );
5585
5586
                    $html .= '<tr class="row_even">';
5587
                    $url = api_get_path(WEB_CODE_PATH)."exercise/overview.php?cidReq={$course_info['code']}&id_session=$session_id&exerciseId={$exercices['id']}";
5588
5589
                    if (true == $visible_return['value']) {
5590
                        $exercices['title'] = Display::url(
5591
                            $exercices['title'],
5592
                            $url,
5593
                            ['target' => SESSION_LINK_TARGET]
5594
                        );
5595
                    } elseif (-1 == $exercices['active']) {
5596
                        $exercices['title'] = sprintf(get_lang('%s (deleted)'), $exercices['title']);
5597
                    }
5598
5599
                    $html .= Display::tag('td', $exercices['title']);
5600
5601
                    // Exercise configuration show results or show only score
5602
                    if (0 == $exercices['results_disabled'] || 2 == $exercices['results_disabled']) {
5603
                        //For graphics
5604
                        $best_exercise_stats = Event::get_best_exercise_results_by_user(
5605
                            $exercices['id'],
5606
                            $course_info['real_id'],
5607
                            $session_id
5608
                        );
5609
5610
                        $to_graph_exercise_result[$exercices['id']] = [
5611
                            'title' => $exercices['title'],
5612
                            'data' => $best_exercise_stats,
5613
                        ];
5614
5615
                        $latest_attempt_url = '';
5616
                        $best_score = $position = $percentage_score_result = '-';
5617
                        $graph = $normal_graph = null;
5618
5619
                        // Getting best results
5620
                        $best_score_data = ExerciseLib::get_best_attempt_in_course(
5621
                            $exercices['id'],
5622
                            $course_info['real_id'],
5623
                            $session_id
5624
                        );
5625
5626
                        $best_score = '';
5627
                        if (!empty($best_score_data)) {
5628
                            $best_score = ExerciseLib::show_score(
5629
                                $best_score_data['score'],
5630
                                $best_score_data['max_score']
5631
                            );
5632
                        }
5633
5634
                        if ($attempts > 0) {
5635
                            $exercise_stat = ExerciseLib::get_best_attempt_by_user(
5636
                                api_get_user_id(),
5637
                                $exercices['id'],
5638
                                $course_info['real_id'],
5639
                                $session_id
5640
                            );
5641
                            if (!empty($exercise_stat)) {
5642
                                // Always getting the BEST attempt
5643
                                $score = $exercise_stat['score'];
5644
                                $weighting = $exercise_stat['max_score'];
5645
                                $exe_id = $exercise_stat['exe_id'];
5646
5647
                                $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;
5648
                                $percentage_score_result = Display::url(
5649
                                    ExerciseLib::show_score($score, $weighting),
5650
                                    $latest_attempt_url
5651
                                );
5652
                                $my_score = 0;
5653
                                if (!empty($weighting) && 0 != intval($weighting)) {
5654
                                    $my_score = $score / $weighting;
5655
                                }
5656
                                //@todo this function slows the page
5657
                                if (is_int($user_list)) {
5658
                                    $user_list = [$user_list];
5659
                                }
5660
                                $position = ExerciseLib::get_exercise_result_ranking(
5661
                                    $my_score,
5662
                                    $exe_id,
5663
                                    $exercices['id'],
5664
                                    $course_info['code'],
5665
                                    $session_id,
5666
                                    $user_list
5667
                                );
5668
5669
                                $graph = self::generate_exercise_result_thumbnail_graph(
5670
                                    $to_graph_exercise_result[$exercices['id']]
5671
                                );
5672
                                $normal_graph = self::generate_exercise_result_graph(
5673
                                    $to_graph_exercise_result[$exercices['id']]
5674
                                );
5675
                            }
5676
                        }
5677
                        $html .= Display::div(
5678
                            $normal_graph,
5679
                            [
5680
                                'id' => 'main_graph_'.$exercices['id'],
5681
                                'class' => 'dialog',
5682
                                'style' => 'display:none',
5683
                            ]
5684
                        );
5685
5686
                        if (empty($graph)) {
5687
                            $graph = '-';
5688
                        } else {
5689
                            $graph = Display::url(
5690
                                '<img src="'.$graph.'" >',
5691
                                $normal_graph,
5692
                                [
5693
                                    'id' => $exercices['id'],
5694
                                    'class' => 'expand-image',
5695
                                ]
5696
                            );
5697
                        }
5698
5699
                        $html .= Display::tag('td', $attempts);
5700
                        $html .= Display::tag('td', $percentage_score_result);
5701
                        $html .= Display::tag('td', $position);
5702
                        $html .= Display::tag('td', $best_score);
5703
                        $html .= Display::tag('td', $graph);
5704
                    } else {
5705
                        // Exercise configuration NO results
5706
                        $html .= Display::tag('td', $attempts);
5707
                        $html .= Display::tag('td', '-');
5708
                        $html .= Display::tag('td', '-');
5709
                        $html .= Display::tag('td', '-');
5710
                        $html .= Display::tag('td', '-');
5711
                    }
5712
                    $html .= '</tr>';
5713
                }
5714
            } else {
5715
                $html .= '<tr><td colspan="5">'.get_lang('There is no test for the moment').'</td></tr>';
5716
            }
5717
            $html .= '</tbody></table></div>';
5718
5719
            $columnHeaders = [
5720
                'lp' => get_lang('Learning paths'),
5721
                'time' => get_lang('Time spent'),
5722
                'progress' => get_lang('Progress'),
5723
                'score' => get_lang('Score'),
5724
                'best_score' => get_lang('Best score'),
5725
                'last_connection' => get_lang('Latest login'),
5726
            ];
5727
5728
            $headers = '';
5729
            $trackingColumns = api_get_configuration_value('tracking_columns');
5730
            if (isset($trackingColumns['my_progress_lp'])) {
5731
                foreach ($columnHeaders as $key => $value) {
5732
                    if (!isset($trackingColumns['my_progress_lp'][$key]) ||
5733
                        false == $trackingColumns['my_progress_lp'][$key]
5734
                    ) {
5735
                        unset($columnHeaders[$key]);
5736
                    }
5737
                }
5738
            }
5739
5740
            $columnHeadersKeys = array_keys($columnHeaders);
5741
            foreach ($columnHeaders as $key => $columnName) {
5742
                $headers .= Display::tag(
5743
                    'th',
5744
                    $columnName
5745
                );
5746
            }
5747
5748
            // LP table results
5749
            $html .= '<div class="table-responsive">';
5750
            $html .= '<table class="table table-striped table-hover">';
5751
            $html .= '<thead><tr>';
5752
            $html .= $headers;
5753
            $html .= '</tr></thead><tbody>';
5754
5755
            $list = new LearnpathList(
5756
                api_get_user_id(),
5757
                $course_info,
5758
                $session_id,
5759
                'lp.publicatedOn ASC',
5760
                true,
5761
                null,
5762
                true
5763
            );
5764
5765
            $lp_list = $list->get_flat_list();
5766
5767
            if (!empty($lp_list)) {
5768
                foreach ($lp_list as $lp_id => $learnpath) {
5769
                    if (!$learnpath['lp_visibility']) {
5770
                        continue;
5771
                    }
5772
5773
                    $progress = self::get_avg_student_progress(
5774
                        $user_id,
5775
                        $course,
5776
                        [$lp_id],
5777
                        $session_id
5778
                    );
5779
                    $last_connection_in_lp = self::get_last_connection_time_in_lp(
5780
                        $user_id,
5781
                        $course,
5782
                        $lp_id,
5783
                        $session_id
5784
                    );
5785
5786
                    $time_spent_in_lp = self::get_time_spent_in_lp(
5787
                        $user_id,
5788
                        $course,
5789
                        [$lp_id],
5790
                        $session_id
5791
                    );
5792
                    $percentage_score = self::get_avg_student_score(
5793
                        $user_id,
5794
                        $course,
5795
                        [$lp_id],
5796
                        $session_id
5797
                    );
5798
5799
                    $bestScore = self::get_avg_student_score(
5800
                        $user_id,
5801
                        $course,
5802
                        [$lp_id],
5803
                        $session_id,
5804
                        false,
5805
                        false,
5806
                        true
5807
                    );
5808
5809
                    if (is_numeric($progress)) {
5810
                        $progress = $progress.'%';
5811
                    }
5812
                    if (is_numeric($percentage_score)) {
5813
                        $percentage_score = $percentage_score.'%';
5814
                    } else {
5815
                        $percentage_score = '0%';
5816
                    }
5817
5818
                    if (is_numeric($bestScore)) {
5819
                        $bestScore = $bestScore.'%';
5820
                    } else {
5821
                        $bestScore = '-';
5822
                    }
5823
5824
                    $time_spent_in_lp = api_time_to_hms($time_spent_in_lp);
5825
                    $last_connection = '-';
5826
                    if (!empty($last_connection_in_lp)) {
5827
                        $last_connection = api_convert_and_format_date(
5828
                            $last_connection_in_lp,
5829
                            DATE_TIME_FORMAT_LONG
5830
                        );
5831
                    }
5832
5833
                    $url = api_get_path(WEB_CODE_PATH)."lp/lp_controller.php?cidReq={$course_code}&id_session=$session_id&lp_id=$lp_id&action=view";
5834
                    $html .= '<tr class="row_even">';
5835
5836
                    if (in_array('lp', $columnHeadersKeys)) {
5837
                        if (0 == $learnpath['lp_visibility']) {
5838
                            $html .= Display::tag('td', $learnpath['lp_name']);
5839
                        } else {
5840
                            $html .= Display::tag(
5841
                                'td',
5842
                                Display::url(
5843
                                    $learnpath['lp_name'],
5844
                                    $url,
5845
                                    ['target' => SESSION_LINK_TARGET]
5846
                                )
5847
                            );
5848
                        }
5849
                    }
5850
5851
                    if (in_array('time', $columnHeadersKeys)) {
5852
                        $html .= Display::tag(
5853
                            'td',
5854
                            $time_spent_in_lp
5855
                        );
5856
                    }
5857
5858
                    if (in_array('progress', $columnHeadersKeys)) {
5859
                        $html .= Display::tag(
5860
                            'td',
5861
                            $progress
5862
                        );
5863
                    }
5864
5865
                    if (in_array('score', $columnHeadersKeys)) {
5866
                        $html .= Display::tag('td', $percentage_score);
5867
                    }
5868
                    if (in_array('best_score', $columnHeadersKeys)) {
5869
                        $html .= Display::tag('td', $bestScore);
5870
                    }
5871
5872
                    if (in_array('last_connection', $columnHeadersKeys)) {
5873
                        $html .= Display::tag('td', $last_connection, ['width' => '180px']);
5874
                    }
5875
                    $html .= '</tr>';
5876
                }
5877
            } else {
5878
                $html .= '<tr>
5879
                        <td colspan="4" align="center">
5880
                            '.get_lang('No learning path').'
5881
                        </td>
5882
                      </tr>';
5883
            }
5884
            $html .= '</tbody></table></div>';
5885
5886
            $html .= self::displayUserSkills($user_id, $course_info['id'], $session_id);
5887
        }
5888
5889
        return $html;
5890
    }
5891
5892
    /**
5893
     * Generates an histogram.
5894
     *
5895
     * @param array $names      list of exercise names
5896
     * @param array $my_results my results 0 to 100
5897
     * @param array $average    average scores 0-100
5898
     *
5899
     * @return string
5900
     */
5901
    public static function generate_session_exercise_graph($names, $my_results, $average)
5902
    {
5903
        $html = api_get_js('chartjs/Chart.js');
5904
        $canvas = Display::tag('canvas', '', ['id' => 'session_graph_chart']);
5905
        $html .= Display::tag('div', $canvas, ['style' => 'width:100%']);
5906
        $jsStr = " var data = {
5907
                       labels:".json_encode($names).",
5908
                       datasets: [
5909
                       {
5910
                         label: '".get_lang('My results')."',
5911
                         backgroundColor: 'rgb(255, 99, 132)',
5912
                         stack: 'Stack1',
5913
                         data: ".json_encode($my_results).",
5914
                        },
5915
                        {
5916
                         label: '".get_lang('Average score')."',
5917
                         backgroundColor: 'rgb(75, 192, 192)',
5918
                         stack: 'Stack2',
5919
                         data: ".json_encode($average).",
5920
                        },
5921
                        ],
5922
                    };
5923
                    var ctx = document.getElementById('session_graph_chart').getContext('2d');
5924
                    var myBarChart = new Chart(ctx, {
5925
                    type: 'bar',
5926
                    data: data,
5927
                    options: {
5928
                            title: {
5929
                                    display: true,
5930
                                    text: '".get_lang('TestsInTimeProgressChart')."'
5931
                            },
5932
                            tooltips: {
5933
                                    mode: 'index',
5934
                                    intersect: false
5935
                            },
5936
                            responsive: true,
5937
                            scales: {
5938
                                yAxes: [{
5939
                                    ticks: {
5940
                                        // Include a dollar sign in the ticks
5941
                                        callback: function(value, index, values) {
5942
                                            return value + '%';
5943
                                        }
5944
                                    }
5945
                                }]
5946
                            }
5947
                    }
5948
                });";
5949
        $html .= Display::tag('script', $jsStr);
5950
5951
        return $html;
5952
    }
5953
5954
    /**
5955
     * Returns a thumbnail of the function generate_exercise_result_graph.
5956
     *
5957
     * @param array $attempts
5958
     */
5959
    public static function generate_exercise_result_thumbnail_graph($attempts)
5960
    {
5961
        //$exercise_title = $attempts['title'];
5962
        $attempts = $attempts['data'];
5963
        $my_exercise_result_array = $exercise_result = [];
5964
        if (empty($attempts)) {
5965
            return null;
5966
        }
5967
5968
        foreach ($attempts as $attempt) {
5969
            if (api_get_user_id() == $attempt['exe_user_id']) {
5970
                if (0 != $attempt['max_score']) {
5971
                    $my_exercise_result_array[] = $attempt['score'] / $attempt['max_score'];
5972
                }
5973
            } else {
5974
                if (0 != $attempt['max_score']) {
5975
                    $exercise_result[] = $attempt['score'] / $attempt['max_score'];
5976
                }
5977
            }
5978
        }
5979
5980
        // Getting best result
5981
        rsort($my_exercise_result_array);
5982
        $my_exercise_result = 0;
5983
        if (isset($my_exercise_result_array[0])) {
5984
            $my_exercise_result = $my_exercise_result_array[0] * 100;
5985
        }
5986
5987
        $max = 100;
5988
        $pieces = 5;
5989
        $part = round($max / $pieces);
5990
        $x_axis = [];
5991
        $final_array = [];
5992
        $my_final_array = [];
5993
5994
        for ($i = 1; $i <= $pieces; $i++) {
5995
            $sum = 1;
5996
            if (1 == $i) {
5997
                $sum = 0;
5998
            }
5999
            $min = ($i - 1) * $part + $sum;
6000
            $max = ($i) * $part;
6001
            $x_axis[] = $min." - ".$max;
6002
            $count = 0;
6003
            foreach ($exercise_result as $result) {
6004
                $percentage = $result * 100;
6005
                if ($percentage >= $min && $percentage <= $max) {
6006
                    //echo ' is > ';
6007
                    $count++;
6008
                }
6009
            }
6010
            //echo '<br />';
6011
            $final_array[] = $count;
6012
6013
            if ($my_exercise_result >= $min && $my_exercise_result <= $max) {
6014
                $my_final_array[] = 1;
6015
            } else {
6016
                $my_final_array[] = 0;
6017
            }
6018
        }
6019
6020
        // Fix to remove the data of the user with my data
6021
        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...
6022
            if (!empty($my_final_array[$i])) {
6023
                $my_final_array[$i] = $final_array[$i] + 1; //Add my result
6024
                $final_array[$i] = 0;
6025
            }
6026
        }
6027
6028
        // Dataset definition
6029
        $dataSet = new pData();
6030
        $dataSet->addPoints($final_array, 'Serie1');
6031
        $dataSet->addPoints($my_final_array, 'Serie2');
6032
        $dataSet->normalize(100, "%");
6033
        $dataSet->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
6034
6035
        // Cache definition
6036
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
6037
        $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]);
6038
        $chartHash = $myCache->getHash($dataSet);
6039
        if ($myCache->isInCache($chartHash)) {
6040
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
6041
            $myCache->saveFromCache($chartHash, $imgPath);
6042
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
6043
        } else {
6044
            /* Create the pChart object */
6045
            $widthSize = 80;
6046
            $heightSize = 35;
6047
            $fontSize = 2;
6048
6049
            $myPicture = new pImage($widthSize, $heightSize, $dataSet);
6050
6051
            /* Turn of Antialiasing */
6052
            $myPicture->Antialias = false;
6053
6054
            /* Add a border to the picture */
6055
            $myPicture->drawRectangle(
6056
                0,
6057
                0,
6058
                $widthSize - 1,
6059
                $heightSize - 1,
6060
                ['R' => 0, 'G' => 0, 'B' => 0]
6061
            );
6062
6063
            /* Set the default font */
6064
            $myPicture->setFontProperties(
6065
                [
6066
                    'FontName' => api_get_path(
6067
                            SYS_FONTS_PATH
6068
                        ).'opensans/OpenSans-Regular.ttf',
6069
                    'FontSize' => $fontSize,
6070
                ]
6071
            );
6072
6073
            /* Do not write the chart title */
6074
            /* Define the chart area */
6075
            $myPicture->setGraphArea(5, 5, $widthSize - 5, $heightSize - 5);
6076
6077
            /* Draw the scale */
6078
            $scaleSettings = [
6079
                'GridR' => 200,
6080
                'GridG' => 200,
6081
                'GridB' => 200,
6082
                'DrawSubTicks' => true,
6083
                'CycleBackground' => true,
6084
                'Mode' => SCALE_MODE_MANUAL,
6085
                'ManualScale' => [
6086
                    '0' => [
6087
                        'Min' => 0,
6088
                        'Max' => 100,
6089
                    ],
6090
                ],
6091
            ];
6092
            $myPicture->drawScale($scaleSettings);
6093
6094
            /* Turn on shadow computing */
6095
            $myPicture->setShadow(
6096
                true,
6097
                [
6098
                    'X' => 1,
6099
                    'Y' => 1,
6100
                    'R' => 0,
6101
                    'G' => 0,
6102
                    'B' => 0,
6103
                    'Alpha' => 10,
6104
                ]
6105
            );
6106
6107
            /* Draw the chart */
6108
            $myPicture->setShadow(
6109
                true,
6110
                [
6111
                    'X' => 1,
6112
                    'Y' => 1,
6113
                    'R' => 0,
6114
                    'G' => 0,
6115
                    'B' => 0,
6116
                    'Alpha' => 10,
6117
                ]
6118
            );
6119
            $settings = [
6120
                'DisplayValues' => true,
6121
                'DisplaySize' => $fontSize,
6122
                'DisplayR' => 0,
6123
                'DisplayG' => 0,
6124
                'DisplayB' => 0,
6125
                'DisplayOrientation' => ORIENTATION_HORIZONTAL,
6126
                'Gradient' => false,
6127
                'Surrounding' => 5,
6128
                'InnerSurrounding' => 5,
6129
            ];
6130
            $myPicture->drawStackedBarChart($settings);
6131
6132
            /* Save and write in cache */
6133
            $myCache->writeToCache($chartHash, $myPicture);
6134
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
6135
            $myCache->saveFromCache($chartHash, $imgPath);
6136
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
6137
        }
6138
6139
        return $imgPath;
6140
    }
6141
6142
    /**
6143
     * Generates a big graph with the number of best results.
6144
     *
6145
     * @param	array
6146
     */
6147
    public static function generate_exercise_result_graph($attempts)
6148
    {
6149
        $exercise_title = strip_tags($attempts['title']);
6150
        $attempts = $attempts['data'];
6151
        $my_exercise_result_array = $exercise_result = [];
6152
        if (empty($attempts)) {
6153
            return null;
6154
        }
6155
        foreach ($attempts as $attempt) {
6156
            if (api_get_user_id() == $attempt['exe_user_id']) {
6157
                if (0 != $attempt['max_score']) {
6158
                    $my_exercise_result_array[] = $attempt['score'] / $attempt['max_score'];
6159
                }
6160
            } else {
6161
                if (0 != $attempt['max_score']) {
6162
                    $exercise_result[] = $attempt['score'] / $attempt['max_score'];
6163
                }
6164
            }
6165
        }
6166
6167
        //Getting best result
6168
        rsort($my_exercise_result_array);
6169
        $my_exercise_result = 0;
6170
        if (isset($my_exercise_result_array[0])) {
6171
            $my_exercise_result = $my_exercise_result_array[0] * 100;
6172
        }
6173
6174
        $max = 100;
6175
        $pieces = 5;
6176
        $part = round($max / $pieces);
6177
        $x_axis = [];
6178
        $final_array = [];
6179
        $my_final_array = [];
6180
6181
        for ($i = 1; $i <= $pieces; $i++) {
6182
            $sum = 1;
6183
            if (1 == $i) {
6184
                $sum = 0;
6185
            }
6186
            $min = ($i - 1) * $part + $sum;
6187
            $max = ($i) * $part;
6188
            $x_axis[] = $min." - ".$max;
6189
            $count = 0;
6190
            foreach ($exercise_result as $result) {
6191
                $percentage = $result * 100;
6192
                if ($percentage >= $min && $percentage <= $max) {
6193
                    $count++;
6194
                }
6195
            }
6196
            $final_array[] = $count;
6197
6198
            if ($my_exercise_result >= $min && $my_exercise_result <= $max) {
6199
                $my_final_array[] = 1;
6200
            } else {
6201
                $my_final_array[] = 0;
6202
            }
6203
        }
6204
6205
        //Fix to remove the data of the user with my data
6206
6207
        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...
6208
            if (!empty($my_final_array[$i])) {
6209
                $my_final_array[$i] = $final_array[$i] + 1; //Add my result
6210
                $final_array[$i] = 0;
6211
            }
6212
        }
6213
6214
        // Dataset definition
6215
        $dataSet = new pData();
6216
        $dataSet->addPoints($final_array, 'Serie1');
6217
        $dataSet->addPoints($my_final_array, 'Serie2');
6218
        $dataSet->addPoints($x_axis, 'Serie3');
6219
6220
        $dataSet->setSerieDescription('Serie1', get_lang('Score'));
6221
        $dataSet->setSerieDescription('Serie2', get_lang('My results'));
6222
        $dataSet->setAbscissa('Serie3');
6223
6224
        $dataSet->setXAxisName(get_lang('Score'));
6225
        $dataSet->normalize(100, "%");
6226
6227
        $dataSet->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
6228
6229
        // Cache definition
6230
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
6231
        $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]);
6232
        $chartHash = $myCache->getHash($dataSet);
6233
6234
        if ($myCache->isInCache($chartHash)) {
6235
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
6236
            $myCache->saveFromCache($chartHash, $imgPath);
6237
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
6238
        } else {
6239
            /* Create the pChart object */
6240
            $widthSize = 480;
6241
            $heightSize = 250;
6242
            $fontSize = 8;
6243
            $myPicture = new pImage($widthSize, $heightSize, $dataSet);
6244
6245
            /* Turn of Antialiasing */
6246
            $myPicture->Antialias = false;
6247
6248
            /* Add a border to the picture */
6249
            $myPicture->drawRectangle(0, 0, $widthSize - 1, $heightSize - 1, ['R' => 0, 'G' => 0, 'B' => 0]);
6250
6251
            /* Set the default font */
6252
            $myPicture->setFontProperties(
6253
                [
6254
                    'FontName' => api_get_path(
6255
                            SYS_FONTS_PATH
6256
                        ).'opensans/OpenSans-Regular.ttf',
6257
                    'FontSize' => 10,
6258
                ]
6259
            );
6260
6261
            /* Write the chart title */
6262
            $myPicture->drawText(
6263
                250,
6264
                20,
6265
                $exercise_title,
6266
                [
6267
                    'FontSize' => 12,
6268
                    'Align' => TEXT_ALIGN_BOTTOMMIDDLE,
6269
                ]
6270
            );
6271
6272
            /* Define the chart area */
6273
            $myPicture->setGraphArea(50, 50, $widthSize - 20, $heightSize - 30);
6274
6275
            /* Draw the scale */
6276
            $scaleSettings = [
6277
                'GridR' => 200,
6278
                'GridG' => 200,
6279
                'GridB' => 200,
6280
                'DrawSubTicks' => true,
6281
                'CycleBackground' => true,
6282
                'Mode' => SCALE_MODE_MANUAL,
6283
                'ManualScale' => [
6284
                    '0' => [
6285
                        'Min' => 0,
6286
                        'Max' => 100,
6287
                    ],
6288
                ],
6289
            ];
6290
            $myPicture->drawScale($scaleSettings);
6291
6292
            /* Turn on shadow computing */
6293
            $myPicture->setShadow(true, ['X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10]);
6294
6295
            /* Draw the chart */
6296
            $myPicture->setShadow(true, ['X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10]);
6297
            $settings = [
6298
                'DisplayValues' => true,
6299
                'DisplaySize' => $fontSize,
6300
                'DisplayR' => 0,
6301
                'DisplayG' => 0,
6302
                'DisplayB' => 0,
6303
                'DisplayOrientation' => ORIENTATION_HORIZONTAL,
6304
                'Gradient' => false,
6305
                'Surrounding' => 30,
6306
                'InnerSurrounding' => 25,
6307
            ];
6308
            $myPicture->drawStackedBarChart($settings);
6309
6310
            $legendSettings = [
6311
                'Mode' => LEGEND_HORIZONTAL,
6312
                'Style' => LEGEND_NOBORDER,
6313
            ];
6314
            $myPicture->drawLegend($widthSize / 2, 30, $legendSettings);
6315
6316
            /* Write and save into cache */
6317
            $myCache->writeToCache($chartHash, $myPicture);
6318
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
6319
            $myCache->saveFromCache($chartHash, $imgPath);
6320
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
6321
        }
6322
6323
        return $imgPath;
6324
    }
6325
6326
    /**
6327
     * @param FormValidator $form
6328
     *
6329
     * @return mixed
6330
     */
6331
    public static function setUserSearchForm($form)
6332
    {
6333
        $form->addElement('text', 'keyword', get_lang('Keyword'));
6334
        $form->addElement(
6335
            'select',
6336
            'active',
6337
            get_lang('Status'),
6338
            [1 => get_lang('active'), 0 => get_lang('inactive')]
6339
        );
6340
6341
        $form->addElement(
6342
            'select',
6343
            'sleeping_days',
6344
            get_lang('Inactive days'),
6345
            [
6346
                '',
6347
                1 => 1,
6348
                5 => 5,
6349
                15 => 15,
6350
                30 => 30,
6351
                60 => 60,
6352
                90 => 90,
6353
                120 => 120,
6354
            ]
6355
        );
6356
6357
        $form->addButtonSearch(get_lang('Search'));
6358
6359
        return $form;
6360
    }
6361
6362
    /**
6363
     * Get the progress of a exercise.
6364
     *
6365
     * @param int    $sessionId  The session ID (session.id)
6366
     * @param int    $courseId   The course ID (course.id)
6367
     * @param int    $exerciseId The quiz ID (c_quiz.id)
6368
     * @param string $date_from
6369
     * @param string $date_to
6370
     * @param array  $options    An array of options you can pass to the query (limit, where and order)
6371
     *
6372
     * @return array An array with the data of exercise(s) progress
6373
     */
6374
    public static function get_exercise_progress(
6375
        $sessionId = 0,
6376
        $courseId = 0,
6377
        $exerciseId = 0,
6378
        $date_from = null,
6379
        $date_to = null,
6380
        $options = []
6381
    ) {
6382
        $sessionId = intval($sessionId);
6383
        $courseId = intval($courseId);
6384
        $exerciseId = intval($exerciseId);
6385
        $date_from = Database::escape_string($date_from);
6386
        $date_to = Database::escape_string($date_to);
6387
        /*
6388
         * This method gets the data by blocks, as previous attempts at one single
6389
         * query made it take ages. The logic of query division is described below
6390
         */
6391
        // Get tables names
6392
        $tuser = Database::get_main_table(TABLE_MAIN_USER);
6393
        $tquiz = Database::get_course_table(TABLE_QUIZ_TEST);
6394
        $tquiz_answer = Database::get_course_table(TABLE_QUIZ_ANSWER);
6395
        $tquiz_question = Database::get_course_table(TABLE_QUIZ_QUESTION);
6396
        $tquiz_rel_question = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
6397
        $ttrack_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
6398
        $ttrack_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
6399
6400
        $sessions = [];
6401
        $courses = [];
6402
        // if session ID is defined but course ID is empty, get all the courses
6403
        // from that session
6404
        if (!empty($sessionId) && empty($courseId)) {
6405
            // $courses is an array of course int id as index and course details hash as value
6406
            $courses = SessionManager::get_course_list_by_session_id($sessionId);
6407
            $sessions[$sessionId] = api_get_session_info($sessionId);
6408
        } elseif (empty($sessionId) && !empty($courseId)) {
6409
            // if, to the contrary, course is defined but not sessions, get the sessions that include this course
6410
            // $sessions is an array like: [0] => ('id' => 3, 'name' => 'Session 35'), [1] => () etc;
6411
            $course = api_get_course_info_by_id($courseId);
6412
            $sessionsTemp = SessionManager::get_session_by_course($courseId);
6413
            $courses[$courseId] = $course;
6414
            foreach ($sessionsTemp as $sessionItem) {
6415
                $sessions[$sessionItem['id']] = $sessionItem;
6416
            }
6417
        } elseif (!empty($courseId) && !empty($sessionId)) {
6418
            //none is empty
6419
            $course = api_get_course_info_by_id($courseId);
6420
            $courses[$courseId] = [$course['code']];
6421
            $courses[$courseId]['code'] = $course['code'];
6422
            $sessions[$sessionId] = api_get_session_info($sessionId);
6423
        } else {
6424
            //both are empty, not enough data, return an empty array
6425
            return [];
6426
        }
6427
        // Now we have two arrays of courses and sessions with enough data to proceed
6428
        // If no course could be found, we shouldn't return anything.
6429
        // Course sessions can be empty (then we only return the pure-course-context results)
6430
        if (count($courses) < 1) {
6431
            return [];
6432
        }
6433
6434
        $data = [];
6435
        // The following loop is less expensive than what it seems:
6436
        // - if a course was defined, then we only loop through sessions
6437
        // - if a session was defined, then we only loop through courses
6438
        // - if a session and a course were defined, then we only loop once
6439
        foreach ($courses as $courseIdx => $courseData) {
6440
            $where = '';
6441
            $whereParams = [];
6442
            $whereSessionParams = '';
6443
            if (count($sessions > 0)) {
6444
                foreach ($sessions as $sessionIdx => $sessionData) {
6445
                    if (!empty($sessionIdx)) {
6446
                        $whereSessionParams .= $sessionIdx.',';
6447
                    }
6448
                }
6449
                $whereSessionParams = substr($whereSessionParams, 0, -1);
6450
            }
6451
6452
            if (!empty($exerciseId)) {
6453
                $exerciseId = intval($exerciseId);
6454
                $where .= ' AND q.id = %d ';
6455
                $whereParams[] = $exerciseId;
6456
            }
6457
6458
            /*
6459
             * This feature has been disabled for now, to avoid having to
6460
             * join two very large tables
6461
            //2 = show all questions (wrong and correct answered)
6462
            if ($answer != 2) {
6463
                $answer = intval($answer);
6464
                //$where .= ' AND qa.correct = %d';
6465
                //$whereParams[] = $answer;
6466
            }
6467
            */
6468
6469
            $limit = '';
6470
            if (!empty($options['limit'])) {
6471
                $limit = " LIMIT ".$options['limit'];
6472
            }
6473
6474
            if (!empty($options['where'])) {
6475
                $where .= ' AND '.Database::escape_string($options['where']);
6476
            }
6477
6478
            $order = '';
6479
            if (!empty($options['order'])) {
6480
                $order = " ORDER BY ".$options['order'];
6481
            }
6482
6483
            if (!empty($date_to) && !empty($date_from)) {
6484
                $where .= sprintf(" AND (te.start_date BETWEEN '%s 00:00:00' AND '%s 23:59:59')", $date_from, $date_to);
6485
            }
6486
6487
            $sql = "SELECT
6488
                te.session_id,
6489
                ta.id as attempt_id,
6490
                te.exe_user_id as user_id,
6491
                te.exe_id as exercise_attempt_id,
6492
                ta.question_id,
6493
                ta.answer as answer_id,
6494
                ta.tms as time,
6495
                te.exe_exo_id as quiz_id,
6496
                CONCAT ('c', q.c_id, '_e', q.id) as exercise_id,
6497
                q.title as quiz_title,
6498
                qq.description as description
6499
                FROM $ttrack_exercises te
6500
                INNER JOIN $ttrack_attempt ta
6501
                ON ta.exe_id = te.exe_id
6502
                INNER JOIN $tquiz q
6503
                ON q.id = te.exe_exo_id
6504
                INNER JOIN $tquiz_rel_question rq
6505
                ON rq.exercice_id = q.id AND rq.c_id = q.c_id
6506
                INNER JOIN $tquiz_question qq
6507
                ON
6508
                    qq.id = rq.question_id AND
6509
                    qq.c_id = rq.c_id AND
6510
                    qq.position = rq.question_order AND
6511
                    ta.question_id = rq.question_id
6512
                WHERE
6513
                    te.c_id = $courseIdx ".(empty($whereSessionParams) ? '' : "AND te.session_id IN ($whereSessionParams)")."
6514
                    AND q.c_id = $courseIdx
6515
                    $where $order $limit";
6516
            $sql_query = vsprintf($sql, $whereParams);
6517
6518
            // Now browse through the results and get the data
6519
            $rs = Database::query($sql_query);
6520
            $userIds = [];
6521
            $questionIds = [];
6522
            $answerIds = [];
6523
            while ($row = Database::fetch_array($rs)) {
6524
                //only show if exercise is visible
6525
                if (api_get_item_visibility($courseData, 'quiz', $row['exercise_id'])) {
6526
                    $userIds[$row['user_id']] = $row['user_id'];
6527
                    $questionIds[$row['question_id']] = $row['question_id'];
6528
                    $answerIds[$row['question_id']][$row['answer_id']] = $row['answer_id'];
6529
                    $row['session'] = $sessions[$row['session_id']];
6530
                    $data[] = $row;
6531
                }
6532
            }
6533
            // Now fill questions data. Query all questions and answers for this test to avoid
6534
            $sqlQuestions = "SELECT tq.c_id, tq.id as question_id, tq.question, tqa.id_auto,
6535
                            tqa.answer, tqa.correct, tq.position, tqa.id_auto as answer_id
6536
                            FROM $tquiz_question tq, $tquiz_answer tqa
6537
                            WHERE
6538
                                tqa.question_id = tq.id AND
6539
                                tqa.c_id = tq.c_id AND
6540
                                tq.c_id = $courseIdx AND
6541
                                tq.id IN (".implode(',', $questionIds).")";
6542
6543
            $resQuestions = Database::query($sqlQuestions);
6544
            $answer = [];
6545
            $question = [];
6546
            while ($rowQuestion = Database::fetch_assoc($resQuestions)) {
6547
                $questionId = $rowQuestion['question_id'];
6548
                $answerId = $rowQuestion['answer_id'];
6549
                $answer[$questionId][$answerId] = [
6550
                    'position' => $rowQuestion['position'],
6551
                    'question' => $rowQuestion['question'],
6552
                    'answer' => $rowQuestion['answer'],
6553
                    'correct' => $rowQuestion['correct'],
6554
                ];
6555
                $question[$questionId]['question'] = $rowQuestion['question'];
6556
            }
6557
6558
            // Now fill users data
6559
            $sqlUsers = "SELECT id as user_id, username, lastname, firstname
6560
                         FROM $tuser
6561
                         WHERE id IN (".implode(',', $userIds).")";
6562
            $resUsers = Database::query($sqlUsers);
6563
            while ($rowUser = Database::fetch_assoc($resUsers)) {
6564
                $users[$rowUser['user_id']] = $rowUser;
6565
            }
6566
6567
            foreach ($data as $id => $row) {
6568
                $rowQuestId = $row['question_id'];
6569
                $rowAnsId = $row['answer_id'];
6570
                $data[$id]['session'] = $sessions[$row['session_id']]['name'];
6571
                $data[$id]['firstname'] = $users[$row['user_id']]['firstname'];
6572
                $data[$id]['lastname'] = $users[$row['user_id']]['lastname'];
6573
                $data[$id]['username'] = $users[$row['user_id']]['username'];
6574
                $data[$id]['answer'] = $answer[$rowQuestId][$rowAnsId]['answer'];
6575
                $data[$id]['correct'] = (0 == $answer[$rowQuestId][$rowAnsId]['correct'] ? get_lang('No') : get_lang('Yes'));
6576
                $data[$id]['question'] = $question[$rowQuestId]['question'];
6577
                $data[$id]['question_id'] = $rowQuestId;
6578
                $data[$id]['description'] = $row['description'];
6579
            }
6580
6581
            /*
6582
            The minimum expected array structure at the end is:
6583
            attempt_id,
6584
            session name,
6585
            exercise_id,
6586
            quiz_title,
6587
            username,
6588
            lastname,
6589
            firstname,
6590
            time,
6591
            question_id,
6592
            question,
6593
            answer,
6594
            */
6595
        }
6596
6597
        return $data;
6598
    }
6599
6600
    /**
6601
     * @param string              $tool
6602
     * @param sessionEntity |null $session Optional
6603
     *
6604
     * @throws \Doctrine\ORM\NonUniqueResultException
6605
     *
6606
     * @return \Chamilo\CourseBundle\Entity\CStudentPublication|null
6607
     */
6608
    public static function getLastStudentPublication(
6609
        User $user,
6610
        $tool,
6611
        Course $course,
6612
        SessionEntity $session = null
6613
    ) {
6614
        return Database::getManager()
6615
            ->createQuery("
6616
                SELECT csp
6617
                FROM ChamiloCourseBundle:CStudentPublication csp
6618
                INNER JOIN ChamiloCourseBundle:CItemProperty cip
6619
                    WITH (
6620
                        csp.iid = cip.ref AND
6621
                        csp.session = cip.session AND
6622
                        csp.cId = cip.course AND
6623
                        csp.userId = cip.lasteditUserId
6624
                    )
6625
                WHERE
6626
                    cip.session = :session AND cip.course = :course AND cip.lasteditUserId = :user AND cip.tool = :tool
6627
                ORDER BY csp.iid DESC
6628
            ")
6629
            ->setMaxResults(1)
6630
            ->setParameters([
6631
                'tool' => $tool,
6632
                'session' => $session,
6633
                'course' => $course,
6634
                'user' => $user,
6635
            ])
6636
            ->getOneOrNullResult();
6637
    }
6638
6639
    /**
6640
     * Get the HTML code for show a block with the achieved user skill on course/session.
6641
     *
6642
     * @param int  $userId
6643
     * @param int  $courseId
6644
     * @param int  $sessionId
6645
     * @param bool $forceView forces the view of the skills, not checking for deeper access
6646
     *
6647
     * @return string
6648
     */
6649
    public static function displayUserSkills($userId, $courseId = 0, $sessionId = 0, $forceView = false)
6650
    {
6651
        if (false === Skill::isAllowed($userId, false) && false == $forceView) {
6652
            return '';
6653
        }
6654
        $skillManager = new Skill();
6655
        $html = $skillManager->getUserSkillsTable($userId, $courseId, $sessionId)['table'];
6656
6657
        return $html;
6658
    }
6659
6660
    /**
6661
     * @param int $userId
6662
     * @param int $courseId
6663
     * @param int $sessionId
6664
     *
6665
     * @return array
6666
     */
6667
    public static function getCalculateTime($userId, $courseId, $sessionId)
6668
    {
6669
        $userId = (int) $userId;
6670
        $courseId = (int) $courseId;
6671
        $sessionId = (int) $sessionId;
6672
6673
        if (empty($userId) || empty($courseId)) {
6674
            return [];
6675
        }
6676
6677
        $sql = "SELECT MIN(date_reg) min, MAX(date_reg) max
6678
                FROM track_e_access_complete
6679
                WHERE
6680
                    user_id = $userId AND
6681
                    c_id = $courseId AND
6682
                    session_id = $sessionId AND
6683
                    login_as = 0
6684
                ORDER BY date_reg ASC
6685
                LIMIT 1";
6686
        $rs = Database::query($sql);
6687
6688
        $firstConnection = '';
6689
        $lastConnection = '';
6690
        if (Database::num_rows($rs) > 0) {
6691
            $value = Database::fetch_array($rs);
6692
            $firstConnection = $value['min'];
6693
            $lastConnection = $value['max'];
6694
        }
6695
6696
        $sql = "SELECT * FROM track_e_access_complete
6697
                WHERE
6698
                    user_id = $userId AND
6699
                    c_id = $courseId AND
6700
                    session_id = $sessionId AND
6701
                    login_as = 0 AND current_id <> 0";
6702
6703
        $res = Database::query($sql);
6704
        $reg = [];
6705
        while ($row = Database::fetch_assoc($res)) {
6706
            $reg[$row['id']] = $row;
6707
            $reg[$row['id']]['date_reg'] = strtotime($row['date_reg']);
6708
        }
6709
6710
        $sessions = [];
6711
        foreach ($reg as $key => $value) {
6712
            $sessions[$value['current_id']][$value['tool']][] = $value;
6713
        }
6714
6715
        $quizTime = 0;
6716
        $result = [];
6717
        $totalTime = 0;
6718
        $lpTime = [];
6719
        $lpDetailTime = [];
6720
        foreach ($sessions as $listPerTool) {
6721
            $min = 0;
6722
            $max = 0;
6723
            $sessionDiff = 0;
6724
            foreach ($listPerTool as $tool => $results) {
6725
                $beforeItem = [];
6726
                foreach ($results as $item) {
6727
                    if (empty($beforeItem)) {
6728
                        $beforeItem = $item;
6729
                        if (empty($min)) {
6730
                            $min = $item['date_reg'];
6731
                        }
6732
6733
                        if (empty($max)) {
6734
                            $max = $item['date_reg'];
6735
                        }
6736
                        continue;
6737
                    }
6738
6739
                    $partialTime = $item['date_reg'] - $beforeItem['date_reg'];
6740
                    if ($item['date_reg'] > $max) {
6741
                        $max = $item['date_reg'];
6742
                    }
6743
6744
                    if (empty($min)) {
6745
                        $min = $item['date_reg'];
6746
                    }
6747
6748
                    if ($item['date_reg'] < $min) {
6749
                        $min = $item['date_reg'];
6750
                    }
6751
6752
                    switch ($tool) {
6753
                        case TOOL_AGENDA:
6754
                        case TOOL_FORUM:
6755
                        case TOOL_ANNOUNCEMENT:
6756
                        case TOOL_COURSE_DESCRIPTION:
6757
                        case TOOL_SURVEY:
6758
                        case TOOL_NOTEBOOK:
6759
                        case TOOL_GRADEBOOK:
6760
                        case TOOL_DROPBOX:
6761
                        case 'Reports':
6762
                        case 'Videoconference':
6763
                        case TOOL_LINK:
6764
                        case TOOL_CHAT:
6765
                        case 'course-main':
6766
                            if (!isset($result[$tool])) {
6767
                                $result[$tool] = 0;
6768
                            }
6769
                            $result[$tool] += $partialTime;
6770
                            break;
6771
                        case TOOL_LEARNPATH:
6772
                            if ($item['tool_id'] != $beforeItem['tool_id']) {
6773
                                break;
6774
                            }
6775
                            if (!isset($lpTime[$item['tool_id']])) {
6776
                                $lpTime[$item['tool_id']] = 0;
6777
                            }
6778
6779
                            // Saving the attempt id "action_details"
6780
                            if (!empty($item['tool_id'])) {
6781
                                if (!empty($item['tool_id_detail'])) {
6782
                                    if (!isset($lpDetailTime[$item['tool_id']][$item['tool_id_detail']][$item['action_details']])) {
6783
                                        $lpDetailTime[$item['tool_id']][$item['tool_id_detail']][$item['action_details']] = 0;
6784
                                    }
6785
                                    $lpDetailTime[$item['tool_id']][$item['tool_id_detail']][$item['action_details']] += $partialTime;
6786
                                }
6787
                                $lpTime[$item['tool_id']] += $partialTime;
6788
                            }
6789
                            break;
6790
                        case TOOL_QUIZ:
6791
                            if (!isset($lpTime[$item['action_details']])) {
6792
                                $lpTime[$item['action_details']] = 0;
6793
                            }
6794
                            if ('learnpath_id' === $beforeItem['action']) {
6795
                                $lpTime[$item['action_details']] += $partialTime;
6796
                            } else {
6797
                                $quizTime += $partialTime;
6798
                            }
6799
                            break;
6800
                    }
6801
                    $beforeItem = $item;
6802
                }
6803
            }
6804
6805
            $sessionDiff += $max - $min;
6806
            if ($sessionDiff > 0) {
6807
                $totalTime += $sessionDiff;
6808
            }
6809
        }
6810
6811
        $totalLp = 0;
6812
        foreach ($lpTime as $value) {
6813
            $totalLp += $value;
6814
        }
6815
6816
        $result['learnpath_detailed'] = $lpDetailTime;
6817
        $result[TOOL_LEARNPATH] = $lpTime;
6818
        $result[TOOL_QUIZ] = $quizTime;
6819
        $result['total_learnpath'] = $totalLp;
6820
        $result['total_time'] = $totalTime;
6821
        $result['number_connections'] = count($sessions);
6822
        $result['first'] = $firstConnection;
6823
        $result['last'] = $lastConnection;
6824
6825
        return $result;
6826
    }
6827
6828
    /**
6829
     * Gets the IP of a given user, using the last login before the given date.
6830
     *
6831
     * @param int User ID
6832
     * @param string Datetime
6833
     * @param bool Whether to return the IP as a link or just as an IP
6834
     * @param string If defined and return_as_link if true, will be used as the text to be shown as the link
6835
     *
6836
     * @return string IP address (or false on error)
6837
     * @assert (0,0) === false
6838
     */
6839
    public static function get_ip_from_user_event(
6840
        $user_id,
6841
        $event_date,
6842
        $return_as_link = false,
6843
        $body_replace = null
6844
    ) {
6845
        if (empty($user_id) || empty($event_date)) {
6846
            return false;
6847
        }
6848
        $user_id = intval($user_id);
6849
        $event_date = Database::escape_string($event_date);
6850
        $table_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
6851
        $sql_ip = "SELECT login_date, user_ip
6852
                   FROM $table_login
6853
                   WHERE login_user_id = $user_id AND login_date < '$event_date'
6854
                   ORDER BY login_date DESC LIMIT 1";
6855
        $ip = '';
6856
        $res_ip = Database::query($sql_ip);
6857
        if (false !== $res_ip && Database::num_rows($res_ip) > 0) {
6858
            $row_ip = Database::fetch_row($res_ip);
6859
            if ($return_as_link) {
6860
                $ip = Display::url(
6861
                    (empty($body_replace) ? $row_ip[1] : $body_replace),
6862
                    'http://www.whatsmyip.org/ip-geo-location/?ip='.$row_ip[1],
6863
                    ['title' => get_lang('Trace IP'), 'target' => '_blank']
6864
                );
6865
            } else {
6866
                $ip = $row_ip[1];
6867
            }
6868
        }
6869
6870
        return $ip;
6871
    }
6872
6873
    /**
6874
     * @param int   $userId
6875
     * @param array $courseInfo
6876
     * @param int   $sessionId
6877
     *
6878
     * @return array
6879
     */
6880
    public static function getToolInformation(
6881
        $userId,
6882
        $courseInfo,
6883
        $sessionId = 0
6884
    ) {
6885
        $csvContent = [];
6886
        $courseToolInformation = '';
6887
        $headerTool = [
6888
            [get_lang('Title')],
6889
            [get_lang('Created at')],
6890
            [get_lang('Updated at')],
6891
        ];
6892
6893
        $headerListForCSV = [];
6894
        foreach ($headerTool as $item) {
6895
            $headerListForCSV[] = $item[0];
6896
        }
6897
6898
        $courseForumInformationArray = getForumCreatedByUser(
6899
            $userId,
6900
            $courseInfo,
6901
            $sessionId
6902
        );
6903
6904
        if (!empty($courseForumInformationArray)) {
6905
            $csvContent[] = [];
6906
            $csvContent[] = [get_lang('Forums')];
6907
            $csvContent[] = $headerListForCSV;
6908
            foreach ($courseForumInformationArray as $row) {
6909
                $csvContent[] = $row;
6910
            }
6911
6912
            $courseToolInformation .= Display::page_subheader2(
6913
                get_lang('Forums')
6914
            );
6915
            $courseToolInformation .= Display::return_sortable_table(
6916
                $headerTool,
6917
                $courseForumInformationArray
6918
            );
6919
        }
6920
6921
        $courseWorkInformationArray = getWorkCreatedByUser(
6922
            $userId,
6923
            $courseInfo['real_id'],
6924
            $sessionId
6925
        );
6926
6927
        if (!empty($courseWorkInformationArray)) {
6928
            $csvContent[] = null;
6929
            $csvContent[] = [get_lang('Assignments')];
6930
            $csvContent[] = $headerListForCSV;
6931
6932
            foreach ($courseWorkInformationArray as $row) {
6933
                $csvContent[] = $row;
6934
            }
6935
            $csvContent[] = null;
6936
6937
            $courseToolInformation .= Display::page_subheader2(
6938
                get_lang('Assignments')
6939
            );
6940
            $courseToolInformation .= Display::return_sortable_table(
6941
                $headerTool,
6942
                $courseWorkInformationArray
6943
            );
6944
        }
6945
6946
        $courseToolInformationTotal = null;
6947
        if (!empty($courseToolInformation)) {
6948
            $sessionTitle = null;
6949
            if (!empty($sessionId)) {
6950
                $sessionTitle = ' ('.api_get_session_name($sessionId).')';
6951
            }
6952
6953
            $courseToolInformationTotal .= Display::page_subheader(
6954
                $courseInfo['title'].$sessionTitle
6955
            );
6956
            $courseToolInformationTotal .= $courseToolInformation;
6957
        }
6958
6959
        return [
6960
            'array' => $csvContent,
6961
            'html' => $courseToolInformationTotal,
6962
        ];
6963
    }
6964
6965
    /**
6966
     * @param int $sessionId
6967
     *
6968
     * @return bool
6969
     */
6970
    public static function isAllowToTrack($sessionId)
6971
    {
6972
        return
6973
            api_is_platform_admin(true, true) ||
6974
            SessionManager::user_is_general_coach(api_get_user_id(), $sessionId) ||
6975
            api_is_allowed_to_create_course() ||
6976
            api_is_course_tutor() ||
6977
            api_is_course_admin();
6978
    }
6979
6980
    public static function getCourseLpProgress($userId, $sessionId)
6981
    {
6982
        $controller = new IndexManager(get_lang('MyCourses'));
6983
        $data = $controller->returnCoursesAndSessions($userId);
6984
        $courseList = $data['courses'];
6985
        $result = [];
6986
        if ($courseList) {
6987
            //$counter = 1;
6988
            foreach ($courseList as $course) {
6989
                $courseId = $course['course_id'];
6990
                $courseInfo = api_get_course_info_by_id($courseId);
6991
                if (empty($courseInfo)) {
6992
                    continue;
6993
                }
6994
                $courseCode = $courseInfo['code'];
6995
                $lpTimeList = self::getCalculateTime($userId, $courseId, $sessionId);
6996
6997
                // total progress
6998
                $list = new LearnpathList(
6999
                    $userId,
7000
                     $courseInfo,
7001
                    0,
7002
                    'lp.publicatedOn ASC',
7003
                    true,
7004
                    null,
7005
                    true
7006
                );
7007
7008
                $list = $list->get_flat_list();
7009
                $totalProgress = 0;
7010
                $totalTime = 0;
7011
                if (!empty($list)) {
7012
                    foreach ($list as $lp_id => $learnpath) {
7013
                        if (!$learnpath['lp_visibility']) {
7014
                            continue;
7015
                        }
7016
                        $lpProgress = self::get_avg_student_progress($userId, $courseCode, [$lp_id], $sessionId);
7017
                        $time = isset($lpTimeList[TOOL_LEARNPATH][$lp_id]) ? $lpTimeList[TOOL_LEARNPATH][$lp_id] : 0;
7018
                        if (100 == $lpProgress) {
7019
                            if (!empty($time)) {
7020
                                $timeInMinutes = $time / 60;
7021
                                $min = (int) learnpath::getAccumulateWorkTimePrerequisite($lp_id, $courseId);
7022
                                if ($timeInMinutes >= $min) {
7023
                                    $totalProgress++;
7024
                                }
7025
                            }
7026
                        }
7027
                        $totalTime += $time;
7028
                    }
7029
7030
                    if (!empty($totalProgress)) {
7031
                        $totalProgress = (float) api_number_format($totalProgress / count($list) * 100, 2);
7032
                    }
7033
                }
7034
7035
                $progress = self::get_avg_student_progress($userId, $courseCode, [], $sessionId);
7036
7037
                $result[] = [
7038
                    'module' => $courseInfo['name'],
7039
                    'progress' => $progress,
7040
                    'qualification' => $totalProgress,
7041
                    'activeTime' => $totalTime,
7042
                ];
7043
            }
7044
        }
7045
7046
        return $result;
7047
    }
7048
7049
    /**
7050
     * @param int $userId
7051
     * @param int $courseId
7052
     * @param int $sessionId
7053
     *
7054
     * @return int
7055
     */
7056
    public static function getNumberOfCourseAccessDates($userId, $courseId, $sessionId)
7057
    {
7058
        $tblTrackCourseAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
7059
        $sessionCondition = api_get_session_condition($sessionId);
7060
        $courseId = (int) $courseId;
7061
        $userId = (int) $userId;
7062
7063
        $sql = "SELECT COUNT(DISTINCT (DATE(login_course_date))) AS c
7064
            FROM $tblTrackCourseAccess
7065
            WHERE c_id = $courseId $sessionCondition AND user_id = $userId";
7066
7067
        $result = Database::fetch_assoc(Database::query($sql));
7068
7069
        return (int) $result['c'];
7070
    }
7071
7072
    public static function processUserDataMove(
7073
        $user_id,
7074
        $course_info,
7075
        $origin_session_id,
7076
        $new_session_id,
7077
        $update_database,
7078
        $debug = false
7079
    ) {
7080
        // Begin with the import process
7081
        $origin_course_code = $course_info['code'];
7082
        $course_id = $course_info['real_id'];
7083
        $user_id = (int) $user_id;
7084
        $origin_session_id = (int) $origin_session_id;
7085
        $new_session_id = (int) $new_session_id;
7086
        $session = api_get_session_entity($new_session_id);
7087
        $em = Database::getManager();
7088
7089
        $TABLETRACK_EXERCICES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
7090
        $TBL_TRACK_ATTEMPT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
7091
        $attemptRecording = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
7092
        $TBL_TRACK_E_COURSE_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
7093
        $TBL_TRACK_E_LAST_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
7094
        $TBL_LP_VIEW = Database::get_course_table(TABLE_LP_VIEW);
7095
        $TBL_NOTEBOOK = Database::get_course_table(TABLE_NOTEBOOK);
7096
        $TBL_STUDENT_PUBLICATION = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
7097
        $TBL_STUDENT_PUBLICATION_ASSIGNMENT = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
7098
        $TBL_ITEM_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
7099
7100
        $TBL_DROPBOX_FILE = Database::get_course_table(TABLE_DROPBOX_FILE);
7101
        $TBL_DROPBOX_POST = Database::get_course_table(TABLE_DROPBOX_POST);
7102
        $TBL_AGENDA = Database::get_course_table(TABLE_AGENDA);
7103
7104
        //1. track_e_exercises
7105
        //ORIGINAL COURSE
7106
        $sql = "SELECT * FROM $TABLETRACK_EXERCICES
7107
                WHERE c_id = $course_id AND  session_id = $origin_session_id AND exe_user_id = $user_id ";
7108
        $res = Database::query($sql);
7109
        $list = [];
7110
        while ($row = Database::fetch_array($res, 'ASSOC')) {
7111
            $list[$row['exe_id']] = $row;
7112
        }
7113
7114
        $result_message = [];
7115
        $result_message_compare = [];
7116
        if (!empty($list)) {
7117
            foreach ($list as $exe_id => $data) {
7118
                if ($update_database) {
7119
                    $sql = "UPDATE $TABLETRACK_EXERCICES SET session_id = '$new_session_id' WHERE exe_id = $exe_id";
7120
                    Database::query($sql);
7121
7122
                    $sql = "UPDATE $TBL_TRACK_ATTEMPT SET session_id = '$new_session_id' WHERE exe_id = $exe_id";
7123
                    Database::query($sql);
7124
7125
                    $sql = "UPDATE $attemptRecording SET session_id = '$new_session_id' WHERE exe_id = $exe_id";
7126
                    Database::query($sql);
7127
7128
                    if (!isset($result_message[$TABLETRACK_EXERCICES])) {
7129
                        $result_message[$TABLETRACK_EXERCICES] = 0;
7130
                    }
7131
                    $result_message[$TABLETRACK_EXERCICES]++;
7132
                } else {
7133
                    if (!empty($data['orig_lp_id']) && !empty($data['orig_lp_item_id'])) {
7134
                        $result_message['TRACK_E_EXERCISES'][$exe_id] = $data;
7135
                    } else {
7136
                        $result_message['TRACK_E_EXERCISES_IN_LP'][$exe_id] = $data;
7137
                    }
7138
                }
7139
            }
7140
        }
7141
7142
        // DESTINY COURSE
7143
        if (!$update_database) {
7144
            $sql = "SELECT * FROM $TABLETRACK_EXERCICES
7145
                    WHERE
7146
                        c_id = $course_id AND
7147
                        session_id = $new_session_id AND
7148
                        exe_user_id = $user_id ";
7149
            $res = Database::query($sql);
7150
            $list = [];
7151
            while ($row = Database::fetch_array($res, 'ASSOC')) {
7152
                $list[$row['exe_id']] = $row;
7153
            }
7154
7155
            if (!empty($list)) {
7156
                foreach ($list as $exe_id => $data) {
7157
                    if ($update_database) {
7158
                        $sql = "UPDATE $TABLETRACK_EXERCICES
7159
                                SET session_id = '$new_session_id'
7160
                                WHERE exe_id = $exe_id";
7161
                        Database::query($sql);
7162
                        $result_message[$TABLETRACK_EXERCICES]++;
7163
                    } else {
7164
                        if (!empty($data['orig_lp_id']) && !empty($data['orig_lp_item_id'])) {
7165
                            $result_message_compare['TRACK_E_EXERCISES'][$exe_id] = $data;
7166
                        } else {
7167
                            $result_message_compare['TRACK_E_EXERCISES_IN_LP'][$exe_id] = $data;
7168
                        }
7169
                    }
7170
                }
7171
            }
7172
        }
7173
7174
        // 2.track_e_attempt, track_e_attempt_recording, track_e_downloads
7175
        // Nothing to do because there are not relationship with a session
7176
        // 3. track_e_course_access
7177
        $sql = "SELECT * FROM $TBL_TRACK_E_COURSE_ACCESS
7178
                WHERE c_id = $course_id AND session_id = $origin_session_id  AND user_id = $user_id ";
7179
        $res = Database::query($sql);
7180
        $list = [];
7181
        while ($row = Database::fetch_array($res, 'ASSOC')) {
7182
            $list[$row['course_access_id']] = $row;
7183
        }
7184
7185
        if (!empty($list)) {
7186
            foreach ($list as $id => $data) {
7187
                if ($update_database) {
7188
                    $sql = "UPDATE $TBL_TRACK_E_COURSE_ACCESS
7189
                            SET session_id = $new_session_id
7190
                            WHERE course_access_id = $id";
7191
                    if ($debug) {
7192
                        echo $sql;
7193
                    }
7194
                    Database::query($sql);
7195
                    if (!isset($result_message[$TBL_TRACK_E_COURSE_ACCESS])) {
7196
                        $result_message[$TBL_TRACK_E_COURSE_ACCESS] = 0;
7197
                    }
7198
                    $result_message[$TBL_TRACK_E_COURSE_ACCESS]++;
7199
                }
7200
            }
7201
        }
7202
7203
        // 4. track_e_lastaccess
7204
        $sql = "SELECT access_id FROM $TBL_TRACK_E_LAST_ACCESS
7205
                WHERE
7206
                    c_id = $course_id AND
7207
                    access_session_id = $origin_session_id AND
7208
                    access_user_id = $user_id ";
7209
        $res = Database::query($sql);
7210
        $list = [];
7211
        while ($row = Database::fetch_array($res, 'ASSOC')) {
7212
            $list[] = $row['access_id'];
7213
        }
7214
7215
        if (!empty($list)) {
7216
            foreach ($list as $id) {
7217
                if ($update_database) {
7218
                    $sql = "UPDATE $TBL_TRACK_E_LAST_ACCESS
7219
                            SET access_session_id = $new_session_id
7220
                            WHERE access_id = $id";
7221
                    if ($debug) {
7222
                        echo $sql;
7223
                    }
7224
                    Database::query($sql);
7225
                    if (!isset($result_message[$TBL_TRACK_E_LAST_ACCESS])) {
7226
                        $result_message[$TBL_TRACK_E_LAST_ACCESS] = 0;
7227
                    }
7228
                    $result_message[$TBL_TRACK_E_LAST_ACCESS]++;
7229
                }
7230
            }
7231
        }
7232
7233
        // 5. lp_item_view
7234
        // CHECK ORIGIN
7235
        $sql = "SELECT * FROM $TBL_LP_VIEW
7236
                WHERE user_id = $user_id AND session_id = $origin_session_id AND c_id = $course_id ";
7237
        $res = Database::query($sql);
7238
7239
        // Getting the list of LPs in the new session
7240
        $lp_list = new LearnpathList($user_id, $course_info, $new_session_id);
7241
        $flat_list = $lp_list->get_flat_list();
7242
        $list = [];
7243
        while ($row = Database::fetch_array($res, 'ASSOC')) {
7244
            // Checking if the LP exist in the new session
7245
            //if (in_array($row['lp_id'], array_keys($flat_list))) {
7246
            $list[$row['id']] = $row;
7247
            //}
7248
        }
7249
7250
        if (!empty($list)) {
7251
            foreach ($list as $id => $data) {
7252
                if ($update_database) {
7253
                    $sql = "UPDATE $TBL_LP_VIEW
7254
                            SET session_id = $new_session_id
7255
                            WHERE c_id = $course_id AND iid = $id ";
7256
                    if ($debug) {
7257
                        var_dump($sql);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($sql) looks like debug code. Are you sure you do not want to remove it?
Loading history...
7258
                    }
7259
                    $res = Database::query($sql);
7260
                    if ($debug) {
7261
                        var_dump($res);
7262
                    }
7263
                    if (!isset($result_message[$TBL_LP_VIEW])) {
7264
                        $result_message[$TBL_LP_VIEW] = 0;
7265
                    }
7266
                    $result_message[$TBL_LP_VIEW]++;
7267
                } else {
7268
                    // Getting all information of that lp_item_id
7269
                    $score = self::get_avg_student_score(
7270
                        $user_id,
7271
                        $origin_course_code,
7272
                        [$data['lp_id']],
7273
                        $origin_session_id
7274
                    );
7275
                    $progress = self::get_avg_student_progress(
7276
                        $user_id,
7277
                        $origin_course_code,
7278
                        [$data['lp_id']],
7279
                        $origin_session_id
7280
                    );
7281
                    $result_message['LP_VIEW'][$data['lp_id']] = [
7282
                        'score' => $score,
7283
                        'progress' => $progress,
7284
                    ];
7285
                }
7286
            }
7287
        }
7288
7289
        // Check destination.
7290
        if (!$update_database) {
7291
            $sql = "SELECT * FROM $TBL_LP_VIEW
7292
                    WHERE user_id = $user_id AND session_id = $new_session_id AND c_id = $course_id";
7293
            $res = Database::query($sql);
7294
7295
            // Getting the list of LPs in the new session
7296
            $lp_list = new LearnpathList($user_id, $course_info, $new_session_id);
7297
            $flat_list = $lp_list->get_flat_list();
7298
7299
            $list = [];
7300
            while ($row = Database::fetch_array($res, 'ASSOC')) {
7301
                //Checking if the LP exist in the new session
7302
                //if (in_array($row['lp_id'], array_keys($flat_list))) {
7303
                $list[$row['id']] = $row;
7304
                //}
7305
            }
7306
7307
            if (!empty($list)) {
7308
                foreach ($list as $id => $data) {
7309
                    // Getting all information of that lp_item_id
7310
                    $score = self::get_avg_student_score(
7311
                        $user_id,
7312
                        $origin_course_code,
7313
                        [$data['lp_id']],
7314
                        $new_session_id
7315
                    );
7316
                    $progress = self::get_avg_student_progress(
7317
                        $user_id,
7318
                        $origin_course_code,
7319
                        [$data['lp_id']],
7320
                        $new_session_id
7321
                    );
7322
                    $result_message_compare['LP_VIEW'][$data['lp_id']] = [
7323
                        'score' => $score,
7324
                        'progress' => $progress,
7325
                    ];
7326
                }
7327
            }
7328
        }
7329
7330
        // 6. Agenda
7331
        // calendar_event_attachment no problems no session_id
7332
        $sql = "SELECT ref FROM $TBL_ITEM_PROPERTY
7333
                WHERE tool = 'calendar_event' AND insert_user_id = $user_id AND c_id = $course_id ";
7334
        $res = Database::query($sql);
7335
        while ($row = Database::fetch_array($res, 'ASSOC')) {
7336
            $id = $row['ref'];
7337
            if ($update_database) {
7338
                $sql = "UPDATE $TBL_AGENDA SET session_id = $new_session_id WHERE c_id = $course_id AND iid = $id ";
7339
                if ($debug) {
7340
                    var_dump($sql);
7341
                }
7342
                $res_update = Database::query($sql);
7343
                if ($debug) {
7344
                    var_dump($res_update);
7345
                }
7346
                if (!isset($result_message['agenda'])) {
7347
                    $result_message['agenda'] = 0;
7348
                }
7349
                $result_message['agenda']++;
7350
            }
7351
        }
7352
7353
        // 7. Forum ?? So much problems when trying to import data
7354
        // 8. Student publication - Works
7355
        $sql = "SELECT ref FROM $TBL_ITEM_PROPERTY
7356
                WHERE tool = 'work' AND insert_user_id = $user_id AND c_id = $course_id";
7357
        if ($debug) {
7358
            echo $sql;
7359
        }
7360
        $res = Database::query($sql);
7361
        while ($row = Database::fetch_array($res, 'ASSOC')) {
7362
            $id = $row['ref'];
7363
            $sql = "SELECT * FROM $TBL_STUDENT_PUBLICATION
7364
                    WHERE iid = $id AND session_id = $origin_session_id AND c_id = $course_id";
7365
            $sub_res = Database::query($sql);
7366
            if (Database::num_rows($sub_res) > 0) {
7367
                $data = Database::fetch_array($sub_res, 'ASSOC');
7368
                if ($debug) {
7369
                    var_dump($data);
7370
                }
7371
                $parent_id = $data['parent_id'];
7372
                if (isset($data['parent_id']) && !empty($data['parent_id'])) {
7373
                    $sql = "SELECT * FROM $TBL_STUDENT_PUBLICATION
7374
                            WHERE iid = $parent_id AND c_id = $course_id";
7375
                    $select_res = Database::query($sql);
7376
                    $parent_data = Database::fetch_array($select_res, 'ASSOC');
7377
                    if ($debug) {
7378
                        var_dump($parent_data);
7379
                    }
7380
7381
                    $sys_course_path = api_get_path(SYS_COURSE_PATH);
7382
                    $course_dir = $sys_course_path.$course_info['path'];
7383
                    $base_work_dir = $course_dir.'/work';
7384
7385
                    // Creating the parent folder in the session if does not exists already
7386
                    //@todo ugly fix
7387
                    $search_this = "folder_moved_from_session_id_$origin_session_id";
7388
                    $search_this2 = $parent_data['url'];
7389
                    $sql = "SELECT * FROM $TBL_STUDENT_PUBLICATION
7390
                            WHERE description like '%$search_this%' AND
7391
                                  url LIKE '%$search_this2%' AND
7392
                                  session_id = $new_session_id AND
7393
                                  c_id = $course_id
7394
                            ORDER BY id desc  LIMIT 1";
7395
                    if ($debug) {
7396
                        echo $sql;
7397
                    }
7398
                    $sub_res = Database::query($sql);
7399
                    $num_rows = Database::num_rows($sub_res);
7400
7401
                    $new_parent_id = 0;
7402
                    if ($num_rows > 0) {
7403
                        $new_result = Database::fetch_array($sub_res, 'ASSOC');
7404
                        $created_dir = $new_result['url'];
7405
                        $new_parent_id = $new_result['id'];
7406
                    } else {
7407
                        if ($update_database) {
7408
                            $dir_name = substr($parent_data['url'], 1);
7409
                            $created_dir = create_unexisting_work_directory($base_work_dir, $dir_name);
7410
                            $created_dir = '/'.$created_dir;
7411
                            $now = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
7412
                            //Creating directory
7413
                            $publication = new \Chamilo\CourseBundle\Entity\CStudentPublication();
7414
                            $publication
7415
                                ->setUrl($created_dir)
7416
                                ->setCId($course_id)
7417
                                ->setTitle($parent_data['title'])
7418
                                ->setDescription(
7419
                                    $parent_data['description']."folder_moved_from_session_id_$origin_session_id"
7420
                                )
7421
                                ->setActive(false)
7422
                                ->setAccepted(true)
7423
                                ->setPostGroupId(0)
7424
                                ->setHasProperties($parent_data['has_properties'])
7425
                                ->setWeight($parent_data['weight'])
7426
                                ->setContainsFile($parent_data['contains_file'])
7427
                                ->setFiletype('folder')
7428
                                ->setSentDate($now)
7429
                                ->setQualification($parent_data['qualification'])
7430
                                ->setParentId(0)
7431
                                ->setQualificatorId(0)
7432
                                ->setUserId($parent_data['user_id'])
7433
                                ->setAllowTextAssignment($parent_data['allow_text_assignment'])
7434
                                ->setSession($session);
7435
7436
                            $publication->setDocumentId($parent_data['document_id']);
7437
7438
                            Database::getManager()->persist($publication);
7439
                            Database::getManager()->flush();
7440
                            $id = $publication->getIid();
7441
                            //Folder created
7442
                            //api_item_property_update($course_info, 'work', $id, 'DirectoryCreated', api_get_user_id());
7443
                            $new_parent_id = $id;
7444
                            if (!isset($result_message[$TBL_STUDENT_PUBLICATION.' - new folder created called: '.$created_dir])) {
7445
                                $result_message[$TBL_STUDENT_PUBLICATION.' - new folder created called: '.$created_dir] = 0;
7446
                            }
7447
                            $result_message[$TBL_STUDENT_PUBLICATION.' - new folder created called: '.$created_dir]++;
7448
                        }
7449
                    }
7450
7451
                    //Creating student_publication_assignment if exists
7452
                    $sql = "SELECT * FROM $TBL_STUDENT_PUBLICATION_ASSIGNMENT
7453
                            WHERE publication_id = $parent_id AND c_id = $course_id";
7454
                    if ($debug) {
7455
                        var_dump($sql);
7456
                    }
7457
                    $rest_select = Database::query($sql);
7458
                    if (Database::num_rows($rest_select) > 0) {
7459
                        if ($update_database && $new_parent_id) {
7460
                            $assignment_data = Database::fetch_array($rest_select, 'ASSOC');
7461
                            $sql_add_publication = "INSERT INTO ".$TBL_STUDENT_PUBLICATION_ASSIGNMENT." SET
7462
                                    	c_id = '$course_id',
7463
                                       expires_on          = '".$assignment_data['expires_on']."',
7464
                                       ends_on              = '".$assignment_data['ends_on']."',
7465
                                       add_to_calendar      = '".$assignment_data['add_to_calendar']."',
7466
                                       enable_qualification = '".$assignment_data['enable_qualification']."',
7467
                                       publication_id       = '".$new_parent_id."'";
7468
                            if ($debug) {
7469
                                echo $sql_add_publication;
7470
                            }
7471
                            Database::query($sql_add_publication);
7472
                            $id = (int) Database::insert_id();
7473
                            if ($id) {
7474
7475
                            $sql_update = "UPDATE $TBL_STUDENT_PUBLICATION
7476
                                           SET  has_properties = '".$id."',
7477
                                                view_properties = '1'
7478
                                           WHERE iid = ".$new_parent_id;
7479
                            if ($debug) {
7480
                                echo $sql_update;
7481
                            }
7482
                            Database::query($sql_update);
7483
                            if ($debug) {
7484
                                var_dump($sql_update);
7485
                            }
7486
                            if (!isset($result_message[$TBL_STUDENT_PUBLICATION_ASSIGNMENT])) {
7487
                                $result_message[$TBL_STUDENT_PUBLICATION_ASSIGNMENT] = 0;
7488
                            }
7489
                            $result_message[$TBL_STUDENT_PUBLICATION_ASSIGNMENT]++;
7490
                        }
7491
                    }
7492
                    }
7493
7494
                    $doc_url = $data['url'];
7495
                    $new_url = str_replace($parent_data['url'], $created_dir, $doc_url);
7496
7497
                    if ($update_database) {
7498
                        // Creating a new work
7499
                        $data['sent_date'] = new DateTime($data['sent_date'], new DateTimeZone('UTC'));
7500
7501
                        $data['post_group_id']  = (int) $data['post_group_id'] ;
7502
                        $publication = new \Chamilo\CourseBundle\Entity\CStudentPublication();
7503
                        $publication
7504
                            ->setUrl($new_url)
7505
                            ->setCId($course_id)
7506
                            ->setTitle($data['title'])
7507
                            ->setDescription($data['description'].' file moved')
7508
                            ->setActive($data['active'])
7509
                            ->setAccepted($data['accepted'])
7510
                            ->setPostGroupId($data['post_group_id'])
7511
                            ->setSentDate($data['sent_date'])
7512
                            ->setParentId($new_parent_id)
7513
                            ->setWeight($data['weight'])
7514
                            ->setHasProperties(0)
7515
                            ->setWeight($data['weight'])
7516
                            ->setContainsFile($data['contains_file'])
7517
                            ->setSession($session)
7518
                            ->setUserId($data['user_id'])
7519
                            ->setFiletype('file')
7520
                            ->setDocumentId(0)
7521
                        ;
7522
7523
                        $em->persist($publication);
7524
                        $em->flush();
7525
7526
                        $id = $publication->getIid();
7527
                        /*api_item_property_update(
7528
                            $course_info,
7529
                            'work',
7530
                            $id,
7531
                            'DocumentAdded',
7532
                            $user_id,
7533
                            null,
7534
                            null,
7535
                            null,
7536
                            null,
7537
                            $new_session_id
7538
                        );*/
7539
                        if (!isset($result_message[$TBL_STUDENT_PUBLICATION])) {
7540
                            $result_message[$TBL_STUDENT_PUBLICATION] = 0;
7541
                        }
7542
                        $result_message[$TBL_STUDENT_PUBLICATION]++;
7543
                        $full_file_name = $course_dir.'/'.$doc_url;
7544
                        $new_file = $course_dir.'/'.$new_url;
7545
7546
                        if (file_exists($full_file_name)) {
7547
                            // deleting old assignment
7548
                            $result = copy($full_file_name, $new_file);
7549
                            if ($result) {
7550
                                unlink($full_file_name);
7551
                                if (isset($data['id'])) {
7552
                                $sql = "DELETE FROM $TBL_STUDENT_PUBLICATION WHERE id= ".$data['id'];
7553
                                if ($debug) {
7554
                                    var_dump($sql);
7555
                                }
7556
                                Database::query($sql);
7557
                                }
7558
                                api_item_property_update(
7559
                                    $course_info,
7560
                                    'work',
7561
                                    $data['id'],
7562
                                    'DocumentDeleted',
7563
                                    api_get_user_id()
7564
                                );
7565
                            }
7566
                        }
7567
                    }
7568
                }
7569
            }
7570
        }
7571
7572
        //9. Survey   Pending
7573
        //10. Dropbox - not neccesary to move categories (no presence of session_id)
7574
        $sql = "SELECT id FROM $TBL_DROPBOX_FILE
7575
                WHERE uploader_id = $user_id AND session_id = $origin_session_id AND c_id = $course_id";
7576
        if ($debug) {
7577
            var_dump($sql);
7578
        }
7579
        $res = Database::query($sql);
7580
        while ($row = Database::fetch_array($res, 'ASSOC')) {
7581
            $id = (int) $row['id'];
7582
            if ($update_database) {
7583
                $sql = "UPDATE $TBL_DROPBOX_FILE SET session_id = $new_session_id WHERE c_id = $course_id AND iid = $id";
7584
                if ($debug) {
7585
                    var_dump($sql);
7586
                }
7587
                Database::query($sql);
7588
                if ($debug) {
7589
                    var_dump($res);
7590
                }
7591
7592
                $sql = "UPDATE $TBL_DROPBOX_POST SET session_id = $new_session_id WHERE file_id = $id";
7593
                if ($debug) {
7594
                    var_dump($sql);
7595
                }
7596
                Database::query($sql);
7597
                if ($debug) {
7598
                    var_dump($res);
7599
                }
7600
                if (!isset($result_message[$TBL_DROPBOX_FILE])) {
7601
                    $result_message[$TBL_DROPBOX_FILE] = 0;
7602
                }
7603
                $result_message[$TBL_DROPBOX_FILE]++;
7604
            }
7605
        }
7606
7607
        // 11. Notebook
7608
        /*$sql = "SELECT notebook_id FROM $TBL_NOTEBOOK
7609
                WHERE
7610
                    user_id = $user_id AND
7611
                    session_id = $origin_session_id AND
7612
                    course = '$origin_course_code' AND
7613
                    c_id = $course_id";
7614
        if ($debug) {
7615
            var_dump($sql);
7616
        }
7617
        $res = Database::query($sql);
7618
        while ($row = Database::fetch_array($res, 'ASSOC')) {
7619
            $id = $row['notebook_id'];
7620
            if ($update_database) {
7621
                $sql = "UPDATE $TBL_NOTEBOOK
7622
                        SET session_id = $new_session_id
7623
                        WHERE c_id = $course_id AND notebook_id = $id";
7624
                if ($debug) {
7625
                    var_dump($sql);
7626
                }
7627
                $res = Database::query($sql);
7628
                if ($debug) {
7629
                    var_dump($res);
7630
                }
7631
            }
7632
        }*/
7633
7634
        if ($update_database) {
7635
            echo Display::return_message(get_lang('StatsMoved'));
7636
            if (is_array($result_message)) {
7637
                foreach ($result_message as $table => $times) {
7638
                    echo 'Table '.$table.' - '.$times.' records updated <br />';
7639
                }
7640
            }
7641
        } else {
7642
            echo '<h4>'.get_lang('UserInformationOfThisCourse').'</h4>';
7643
            echo '<br />';
7644
            echo '<table class="table" width="100%">';
7645
            echo '<tr>';
7646
            echo '<td width="50%" valign="top">';
7647
7648
            if ($origin_session_id == 0) {
7649
                echo '<h5>'.get_lang('OriginCourse').'</h5>';
7650
            } else {
7651
                echo '<h5>'.get_lang('OriginSession').' #'.$origin_session_id.'</h5>';
7652
            }
7653
            self::compareUserData($result_message);
7654
            echo '</td>';
7655
            echo '<td width="50%" valign="top">';
7656
            if ($new_session_id == 0) {
7657
                echo '<h5>'.get_lang('DestinyCourse').'</h5>';
7658
            } else {
7659
                echo '<h5>'.get_lang('DestinySession').' #'.$new_session_id.'</h5>';
7660
            }
7661
            self::compareUserData($result_message_compare);
7662
            echo '</td>';
7663
            echo '</tr>';
7664
            echo '</table>';
7665
        }
7666
    }
7667
7668
    public static function compareUserData($result_message)
7669
    {
7670
        foreach ($result_message as $table => $data) {
7671
            $title = $table;
7672
            if ($table === 'TRACK_E_EXERCISES') {
7673
                $title = get_lang('Exercises');
7674
            } elseif ($table === 'TRACK_E_EXERCISES_IN_LP') {
7675
                $title = get_lang('ExercisesInLp');
7676
            } elseif ($table === 'LP_VIEW') {
7677
                $title = get_lang('LearningPaths');
7678
            }
7679
            echo '<br / ><h3>'.get_lang($title).' </h3><hr />';
7680
7681
            if (is_array($data)) {
7682
                foreach ($data as $id => $item) {
7683
                    if ($table === 'TRACK_E_EXERCISES' || $table === 'TRACK_E_EXERCISES_IN_LP') {
7684
                        echo "<br /><h3>".get_lang('Attempt')." #$id</h3>";
7685
                        echo '<h3>';
7686
                        echo get_lang('Exercise').' #'.$item['exe_exo_id'];
7687
                        echo '</h3>';
7688
                        if (!empty($item['orig_lp_id'])) {
7689
                            echo '<h3>';
7690
                            echo get_lang('LearningPath').' #'.$item['orig_lp_id'];
7691
                            echo '</h3>';
7692
                        }
7693
                        // Process data.
7694
                        $array = [
7695
                            'exe_date' => get_lang('Date'),
7696
                            'exe_result' => get_lang('Score'),
7697
                            'exe_weighting' => get_lang('Weighting'),
7698
                        ];
7699
                        foreach ($item as $key => $value) {
7700
                            if (in_array($key, array_keys($array))) {
7701
                                $key = $array[$key];
7702
                                echo "$key =  $value <br />";
7703
                            }
7704
                        }
7705
                    } else {
7706
                        echo "<br /><h3>".get_lang('Id')." #$id</h3>";
7707
                        // process data
7708
                        foreach ($item as $key => $value) {
7709
                            echo "$key =  $value <br />";
7710
                        }
7711
                    }
7712
                }
7713
            } else {
7714
                echo get_lang('NoResults');
7715
            }
7716
        }
7717
    }
7718
}
7719
7720
/**
7721
 * @todo move into a proper file
7722
 */
7723
class TrackingCourseLog
7724
{
7725
    /**
7726
     * @return mixed
7727
     */
7728
    public static function count_item_resources()
7729
    {
7730
        $session_id = api_get_session_id();
7731
        $course_id = api_get_course_int_id();
7732
7733
        $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
7734
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
7735
7736
        $sql = "SELECT count(tool) AS total_number_of_items
7737
                FROM $table_item_property track_resource, $table_user user
7738
                WHERE
7739
                    track_resource.c_id = $course_id AND
7740
                    track_resource.insert_user_id = user.id user_id AND
7741
                    session_id ".(empty($session_id) ? ' IS NULL ' : " = $session_id ");
7742
7743
        if (isset($_GET['keyword'])) {
7744
            $keyword = Database::escape_string(trim($_GET['keyword']));
7745
            $sql .= " AND (
7746
                        user.username LIKE '%".$keyword."%' OR
7747
                        lastedit_type LIKE '%".$keyword."%' OR
7748
                        tool LIKE '%".$keyword."%'
7749
                    )";
7750
        }
7751
7752
        $sql .= " AND tool IN (
7753
                    'document',
7754
                    'learnpath',
7755
                    'quiz',
7756
                    'glossary',
7757
                    'link',
7758
                    'course_description',
7759
                    'announcement',
7760
                    'thematic',
7761
                    'thematic_advance',
7762
                    'thematic_plan'
7763
                )";
7764
        $res = Database::query($sql);
7765
        $obj = Database::fetch_object($res);
7766
7767
        return $obj->total_number_of_items;
7768
    }
7769
7770
    /**
7771
     * @param $from
7772
     * @param $number_of_items
7773
     * @param $column
7774
     * @param $direction
7775
     *
7776
     * @return array
7777
     */
7778
    public static function get_item_resources_data($from, $number_of_items, $column, $direction)
7779
    {
7780
        $session_id = api_get_session_id();
7781
        $course_id = api_get_course_int_id();
7782
7783
        $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
7784
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
7785
        $table_session = Database::get_main_table(TABLE_MAIN_SESSION);
7786
        $session_id = intval($session_id);
7787
7788
        $sql = "SELECT
7789
                    tool as col0,
7790
                    lastedit_type as col1,
7791
                    ref as ref,
7792
                    user.username as col3,
7793
                    insert_date as col6,
7794
                    visibility as col7,
7795
                    user.user_id as user_id
7796
                FROM $table_item_property track_resource, $table_user user
7797
                WHERE
7798
                  track_resource.c_id = $course_id AND
7799
                  track_resource.insert_user_id = user.user_id AND
7800
                  session_id ".(empty($session_id) ? ' IS NULL ' : " = $session_id ");
7801
7802
        if (isset($_GET['keyword'])) {
7803
            $keyword = Database::escape_string(trim($_GET['keyword']));
7804
            $sql .= " AND (
7805
                        user.username LIKE '%".$keyword."%' OR
7806
                        lastedit_type LIKE '%".$keyword."%' OR
7807
                        tool LIKE '%".$keyword."%'
7808
                     ) ";
7809
        }
7810
7811
        $sql .= " AND tool IN (
7812
                    'document',
7813
                    'learnpath',
7814
                    'quiz',
7815
                    'glossary',
7816
                    'link',
7817
                    'course_description',
7818
                    'announcement',
7819
                    'thematic',
7820
                    'thematic_advance',
7821
                    'thematic_plan'
7822
                )";
7823
7824
        if (0 == $column) {
7825
            $column = '0';
7826
        }
7827
        if ('' != $column && '' != $direction) {
7828
            if (2 != $column && 4 != $column) {
7829
                $sql .= " ORDER BY col$column $direction";
7830
            }
7831
        } else {
7832
            $sql .= " ORDER BY col6 DESC ";
7833
        }
7834
7835
        $from = intval($from);
7836
        if ($from) {
7837
            $number_of_items = intval($number_of_items);
7838
            $sql .= " LIMIT $from, $number_of_items ";
7839
        }
7840
7841
        $res = Database::query($sql);
7842
        $resources = [];
7843
        $thematic_tools = ['thematic', 'thematic_advance', 'thematic_plan'];
7844
        while ($row = Database::fetch_array($res)) {
7845
            $ref = $row['ref'];
7846
            $table_name = self::get_tool_name_table($row['col0']);
7847
            $table_tool = Database::get_course_table($table_name['table_name']);
7848
7849
            $id = $table_name['id_tool'];
7850
            $recorset = false;
7851
7852
            if (in_array($row['col0'], ['thematic_plan', 'thematic_advance'])) {
7853
                $tbl_thematic = Database::get_course_table(TABLE_THEMATIC);
7854
                $sql = "SELECT thematic_id FROM $table_tool
7855
                        WHERE c_id = $course_id AND iid = $ref";
7856
                $rs_thematic = Database::query($sql);
7857
                if (Database::num_rows($rs_thematic)) {
7858
                    $row_thematic = Database::fetch_array($rs_thematic);
7859
                    $thematic_id = $row_thematic['thematic_id'];
7860
7861
                    $sql = "SELECT session.id, session.name, user.username
7862
                            FROM $tbl_thematic t, $table_session session, $table_user user
7863
                            WHERE
7864
                              t.c_id = $course_id AND
7865
                              t.session_id = session.id AND
7866
                              session.id_coach = user.user_id AND
7867
                              t.id = $thematic_id";
7868
                    $recorset = Database::query($sql);
7869
                }
7870
            } else {
7871
                $sql = "SELECT session.id, session.name, user.username
7872
                          FROM $table_tool tool, $table_session session, $table_user user
7873
                          WHERE
7874
                              tool.c_id = $course_id AND
7875
                              tool.session_id = session.id AND
7876
                              session.id_coach = user.user_id AND
7877
                              tool.$id = $ref";
7878
                $recorset = Database::query($sql);
7879
            }
7880
7881
            if (!empty($recorset)) {
7882
                $obj = Database::fetch_object($recorset);
7883
7884
                $name_session = '';
7885
                $coach_name = '';
7886
                if (!empty($obj)) {
7887
                    $name_session = $obj->name;
7888
                    $coach_name = $obj->username;
7889
                }
7890
7891
                $url_tool = api_get_path(WEB_CODE_PATH).$table_name['link_tool'];
7892
                $row[0] = '';
7893
                if (2 != $row['col6']) {
7894
                    if (in_array($row['col0'], $thematic_tools)) {
7895
                        $exp_thematic_tool = explode('_', $row['col0']);
7896
                        $thematic_tool_title = '';
7897
                        if (is_array($exp_thematic_tool)) {
7898
                            foreach ($exp_thematic_tool as $exp) {
7899
                                $thematic_tool_title .= api_ucfirst($exp);
7900
                            }
7901
                        } else {
7902
                            $thematic_tool_title = api_ucfirst($row['col0']);
7903
                        }
7904
7905
                        $row[0] = '<a href="'.$url_tool.'?'.api_get_cidreq().'&action=thematic_details">'.get_lang($thematic_tool_title).'</a>';
7906
                    } else {
7907
                        $row[0] = '<a href="'.$url_tool.'?'.api_get_cidreq().'">'.get_lang('Tool'.api_ucfirst($row['col0'])).'</a>';
7908
                    }
7909
                } else {
7910
                    $row[0] = api_ucfirst($row['col0']);
7911
                }
7912
                $row[1] = get_lang($row[1]);
7913
                $row[6] = api_convert_and_format_date($row['col6'], null, date_default_timezone_get());
7914
                $row[5] = '';
7915
                //@todo Improve this code please
7916
                switch ($table_name['table_name']) {
7917
                    case 'document':
7918
                        $sql = "SELECT tool.title as title FROM $table_tool tool
7919
                                WHERE c_id = $course_id AND iid = $ref";
7920
                        $rs_document = Database::query($sql);
7921
                        $obj_document = Database::fetch_object($rs_document);
7922
                        if ($obj_document) {
7923
                            $row[5] = $obj_document->title;
7924
                        }
7925
                        break;
7926
                    case 'announcement':
7927
                        $sql = "SELECT title FROM $table_tool
7928
                                WHERE c_id = $course_id AND id = $ref";
7929
                        $rs_document = Database::query($sql);
7930
                        $obj_document = Database::fetch_object($rs_document);
7931
                        if ($obj_document) {
7932
                            $row[5] = $obj_document->title;
7933
                        }
7934
                        break;
7935
                    case 'glossary':
7936
                        $sql = "SELECT name FROM $table_tool
7937
                                WHERE c_id = $course_id AND glossary_id = $ref";
7938
                        $rs_document = Database::query($sql);
7939
                        $obj_document = Database::fetch_object($rs_document);
7940
                        if ($obj_document) {
7941
                            $row[5] = $obj_document->name;
7942
                        }
7943
                        break;
7944
                    case 'lp':
7945
                        $sql = "SELECT name
7946
                                FROM $table_tool WHERE c_id = $course_id AND id = $ref";
7947
                        $rs_document = Database::query($sql);
7948
                        $obj_document = Database::fetch_object($rs_document);
7949
                        $row[5] = $obj_document->name;
7950
                        break;
7951
                    case 'quiz':
7952
                        $sql = "SELECT title FROM $table_tool
7953
                                WHERE c_id = $course_id AND id = $ref";
7954
                        $rs_document = Database::query($sql);
7955
                        $obj_document = Database::fetch_object($rs_document);
7956
                        if ($obj_document) {
7957
                            $row[5] = $obj_document->title;
7958
                        }
7959
                        break;
7960
                    case 'course_description':
7961
                        $sql = "SELECT title FROM $table_tool
7962
                                WHERE c_id = $course_id AND id = $ref";
7963
                        $rs_document = Database::query($sql);
7964
                        $obj_document = Database::fetch_object($rs_document);
7965
                        if ($obj_document) {
7966
                            $row[5] = $obj_document->title;
7967
                        }
7968
                        break;
7969
                    case 'thematic':
7970
                        $rs = Database::query("SELECT title FROM $table_tool WHERE c_id = $course_id AND id = $ref");
7971
                        if (Database::num_rows($rs) > 0) {
7972
                            $obj = Database::fetch_object($rs);
7973
                            if ($obj) {
7974
                                $row[5] = $obj->title;
7975
                            }
7976
                        }
7977
                        break;
7978
                    case 'thematic_advance':
7979
                        $rs = Database::query("SELECT content FROM $table_tool WHERE c_id = $course_id AND id = $ref");
7980
                        if (Database::num_rows($rs) > 0) {
7981
                            $obj = Database::fetch_object($rs);
7982
                            if ($obj) {
7983
                                $row[5] = $obj->content;
7984
                            }
7985
                        }
7986
                        break;
7987
                    case 'thematic_plan':
7988
                        $rs = Database::query("SELECT title FROM $table_tool WHERE c_id = $course_id AND id = $ref");
7989
                        if (Database::num_rows($rs) > 0) {
7990
                            $obj = Database::fetch_object($rs);
7991
                            if ($obj) {
7992
                                $row[5] = $obj->title;
7993
                            }
7994
                        }
7995
                        break;
7996
                    default:
7997
                        break;
7998
                }
7999
8000
                $row2 = $name_session;
8001
                if (!empty($coach_name)) {
8002
                    $row2 .= '<br />'.get_lang('Coach').': '.$coach_name;
8003
                }
8004
                $row[2] = $row2;
8005
                if (!empty($row['col3'])) {
8006
                    $userInfo = api_get_user_info($row['user_id']);
8007
                    $row['col3'] = Display::url(
8008
                        $row['col3'],
8009
                        $userInfo['profile_url']
8010
                    );
8011
                    $row[3] = $row['col3'];
8012
8013
                    $ip = Tracking::get_ip_from_user_event(
8014
                        $row['user_id'],
8015
                        $row['col6'],
8016
                        true
8017
                    );
8018
                    if (empty($ip)) {
8019
                        $ip = get_lang('Unknown');
8020
                    }
8021
                    $row[4] = $ip;
8022
                }
8023
8024
                $resources[] = $row;
8025
            }
8026
        }
8027
8028
        return $resources;
8029
    }
8030
8031
    /**
8032
     * @param string $tool
8033
     *
8034
     * @return array
8035
     */
8036
    public static function get_tool_name_table($tool)
8037
    {
8038
        switch ($tool) {
8039
            case 'document':
8040
                $table_name = TABLE_DOCUMENT;
8041
                $link_tool = 'document/document.php';
8042
                $id_tool = 'id';
8043
                break;
8044
            case 'learnpath':
8045
                $table_name = TABLE_LP_MAIN;
8046
                $link_tool = 'lp/lp_controller.php';
8047
                $id_tool = 'id';
8048
                break;
8049
            case 'quiz':
8050
                $table_name = TABLE_QUIZ_TEST;
8051
                $link_tool = 'exercise/exercise.php';
8052
                $id_tool = 'id';
8053
                break;
8054
            case 'glossary':
8055
                $table_name = TABLE_GLOSSARY;
8056
                $link_tool = 'glossary/index.php';
8057
                $id_tool = 'glossary_id';
8058
                break;
8059
            case 'link':
8060
                $table_name = TABLE_LINK;
8061
                $link_tool = 'link/link.php';
8062
                $id_tool = 'id';
8063
                break;
8064
            case 'course_description':
8065
                $table_name = TABLE_COURSE_DESCRIPTION;
8066
                $link_tool = 'course_description/';
8067
                $id_tool = 'id';
8068
                break;
8069
            case 'announcement':
8070
                $table_name = TABLE_ANNOUNCEMENT;
8071
                $link_tool = 'announcements/announcements.php';
8072
                $id_tool = 'id';
8073
                break;
8074
            case 'thematic':
8075
                $table_name = TABLE_THEMATIC;
8076
                $link_tool = 'course_progress/index.php';
8077
                $id_tool = 'id';
8078
                break;
8079
            case 'thematic_advance':
8080
                $table_name = TABLE_THEMATIC_ADVANCE;
8081
                $link_tool = 'course_progress/index.php';
8082
                $id_tool = 'id';
8083
                break;
8084
            case 'thematic_plan':
8085
                $table_name = TABLE_THEMATIC_PLAN;
8086
                $link_tool = 'course_progress/index.php';
8087
                $id_tool = 'id';
8088
                break;
8089
            default:
8090
                $table_name = $tool;
8091
            break;
8092
        }
8093
8094
        return [
8095
            'table_name' => $table_name,
8096
            'link_tool' => $link_tool,
8097
            'id_tool' => $id_tool,
8098
        ];
8099
    }
8100
8101
    /**
8102
     * @return string
8103
     */
8104
    public static function display_additional_profile_fields()
8105
    {
8106
        // getting all the extra profile fields that are defined by the platform administrator
8107
        $extra_fields = UserManager::get_extra_fields(0, 50, 5, 'ASC');
8108
8109
        // creating the form
8110
        $return = '<form action="courseLog.php" method="get" name="additional_profile_field_form" id="additional_profile_field_form">';
8111
8112
        // the select field with the additional user profile fields (= this is where we select the field of which we want to see
8113
        // the information the users have entered or selected.
8114
        $return .= '<select class="chzn-select" name="additional_profile_field[]" multiple>';
8115
        $return .= '<option value="-">'.get_lang('Select user profile field to add').'</option>';
8116
        $extra_fields_to_show = 0;
8117
        foreach ($extra_fields as $key => $field) {
8118
            // show only extra fields that are visible + and can be filtered, added by J.Montoya
8119
            if (1 == $field[6] && 1 == $field[8]) {
8120
                if (isset($_GET['additional_profile_field']) && $field[0] == $_GET['additional_profile_field']) {
8121
                    $selected = 'selected="selected"';
8122
                } else {
8123
                    $selected = '';
8124
                }
8125
                $extra_fields_to_show++;
8126
                $return .= '<option value="'.$field[0].'" '.$selected.'>'.$field[3].'</option>';
8127
            }
8128
        }
8129
        $return .= '</select>';
8130
8131
        // the form elements for the $_GET parameters (because the form is passed through GET
8132
        foreach ($_GET as $key => $value) {
8133
            if ('additional_profile_field' != $key) {
8134
                $return .= '<input type="hidden" name="'.Security::remove_XSS($key).'" value="'.Security::remove_XSS($value).'" />';
8135
            }
8136
        }
8137
        // the submit button
8138
        $return .= '<button class="save" type="submit">'.get_lang('Add user profile field').'</button>';
8139
        $return .= '</form>';
8140
        if ($extra_fields_to_show > 0) {
8141
            return $return;
8142
        } else {
8143
            return '';
8144
        }
8145
    }
8146
8147
    /**
8148
     * This function gets all the information of a certrain ($field_id)
8149
     * additional profile field for a specific list of users is more efficent
8150
     * than get_addtional_profile_information_of_field() function
8151
     * It gets the information of all the users so that it can be displayed
8152
     * in the sortable table or in the csv or xls export.
8153
     *
8154
     * @author    Julio Montoya <[email protected]>
8155
     *
8156
     * @param    int field id
8157
     * @param    array list of user ids
8158
     *
8159
     * @return array
8160
     *
8161
     * @since    Nov 2009
8162
     *
8163
     * @version    1.8.6.2
8164
     */
8165
    public static function getAdditionalProfileInformationOfFieldByUser($field_id, $users)
8166
    {
8167
        // Database table definition
8168
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
8169
        $table_user_field_values = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
8170
        $extraField = Database::get_main_table(TABLE_EXTRA_FIELD);
8171
        $result_extra_field = UserManager::get_extra_field_information($field_id);
8172
        $return = [];
8173
        if (!empty($users)) {
8174
            if (UserManager::USER_FIELD_TYPE_TAG == $result_extra_field['field_type']) {
8175
                foreach ($users as $user_id) {
8176
                    $user_result = UserManager::get_user_tags($user_id, $field_id);
8177
                    $tag_list = [];
8178
                    foreach ($user_result as $item) {
8179
                        $tag_list[] = $item['tag'];
8180
                    }
8181
                    $return[$user_id][] = implode(', ', $tag_list);
8182
                }
8183
            } else {
8184
                $new_user_array = [];
8185
                foreach ($users as $user_id) {
8186
                    $new_user_array[] = "'".$user_id."'";
8187
                }
8188
                $users = implode(',', $new_user_array);
8189
                $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
8190
                // Selecting only the necessary information NOT ALL the user list
8191
                $sql = "SELECT user.user_id, v.value
8192
                        FROM $table_user user
8193
                        INNER JOIN $table_user_field_values v
8194
                        ON (user.user_id = v.item_id)
8195
                        INNER JOIN $extraField f
8196
                        ON (f.id = v.field_id)
8197
                        WHERE
8198
                            f.extra_field_type = $extraFieldType AND
8199
                            v.field_id=".intval($field_id)." AND
8200
                            user.user_id IN ($users)";
8201
8202
                $result = Database::query($sql);
8203
                while ($row = Database::fetch_array($result)) {
8204
                    // get option value for field type double select by id
8205
                    if (!empty($row['value'])) {
8206
                        if (ExtraField::FIELD_TYPE_DOUBLE_SELECT ==
8207
                            $result_extra_field['field_type']
8208
                        ) {
8209
                            $id_double_select = explode(';', $row['value']);
8210
                            if (is_array($id_double_select)) {
8211
                                $value1 = $result_extra_field['options'][$id_double_select[0]]['option_value'];
8212
                                $value2 = $result_extra_field['options'][$id_double_select[1]]['option_value'];
8213
                                $row['value'] = ($value1.';'.$value2);
8214
                            }
8215
                        }
8216
8217
                        if (ExtraField::FIELD_TYPE_SELECT_WITH_TEXT_FIELD == $result_extra_field['field_type']) {
8218
                            $parsedValue = explode('::', $row['value']);
8219
8220
                            if ($parsedValue) {
8221
                                $value1 = $result_extra_field['options'][$parsedValue[0]]['display_text'];
8222
                                $value2 = $parsedValue[1];
8223
8224
                                $row['value'] = "$value1: $value2";
8225
                            }
8226
                        }
8227
8228
                        if (ExtraField::FIELD_TYPE_TRIPLE_SELECT == $result_extra_field['field_type']) {
8229
                            list($level1, $level2, $level3) = explode(';', $row['value']);
8230
8231
                            $row['value'] = $result_extra_field['options'][$level1]['display_text'].' / ';
8232
                            $row['value'] .= $result_extra_field['options'][$level2]['display_text'].' / ';
8233
                            $row['value'] .= $result_extra_field['options'][$level3]['display_text'];
8234
                        }
8235
                    }
8236
                    // get other value from extra field
8237
                    $return[$row['user_id']][] = $row['value'];
8238
                }
8239
            }
8240
        }
8241
8242
        return $return;
8243
    }
8244
8245
    /**
8246
     * count the number of students in this course (used for SortableTable)
8247
     * Deprecated.
8248
     */
8249
    public function count_student_in_course()
8250
    {
8251
        global $nbStudents;
8252
8253
        return $nbStudents;
8254
    }
8255
8256
    public function sort_users($a, $b)
8257
    {
8258
        $tracking = Session::read('tracking_column');
8259
8260
        return strcmp(
8261
            trim(api_strtolower($a[$tracking])),
8262
            trim(api_strtolower($b[$tracking]))
8263
        );
8264
    }
8265
8266
    public function sort_users_desc($a, $b)
8267
    {
8268
        $tracking = Session::read('tracking_column');
8269
8270
        return strcmp(
8271
            trim(api_strtolower($b[$tracking])),
8272
            trim(api_strtolower($a[$tracking]))
8273
        );
8274
    }
8275
8276
    /**
8277
     * Get number of users for sortable with pagination.
8278
     *
8279
     * @return int
8280
     */
8281
    public static function get_number_of_users($conditions)
8282
    {
8283
        $conditions['get_count'] = true;
8284
8285
        return self::get_user_data(null, null, null, null, $conditions);
8286
    }
8287
8288
    /**
8289
     * Get data for users list in sortable with pagination.
8290
     *
8291
     * @param int $from
8292
     * @param int $number_of_items
8293
     * @param $column
8294
     * @param $direction
8295
     * @param $conditions
8296
     *
8297
     * @return array
8298
     */
8299
    public static function get_user_data(
8300
        $from,
8301
        $number_of_items,
8302
        $column,
8303
        $direction,
8304
        $conditions = []
8305
    ) {
8306
        global $user_ids, $course_code, $export_csv, $session_id;
8307
        $includeInvitedUsers = $conditions['include_invited_users']; // include the invited users
8308
        $getCount = isset($conditions['get_count']) ? $conditions['get_count'] : false;
8309
8310
        $csv_content = [];
8311
        $course_code = Database::escape_string($course_code);
8312
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
8313
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
8314
        $access_url_id = api_get_current_access_url_id();
8315
8316
        // get all users data from a course for sortable with limit
8317
        if (is_array($user_ids)) {
8318
            $user_ids = array_map('intval', $user_ids);
8319
            $condition_user = " WHERE user.id IN (".implode(',', $user_ids).") ";
8320
        } else {
8321
            $user_ids = (int) $user_ids;
8322
            $condition_user = " WHERE user.id = $user_ids ";
8323
        }
8324
8325
        if (!empty($_GET['user_keyword'])) {
8326
            $keyword = trim(Database::escape_string($_GET['user_keyword']));
8327
            $condition_user .= " AND (
8328
                user.firstname LIKE '%".$keyword."%' OR
8329
                user.lastname LIKE '%".$keyword."%'  OR
8330
                user.username LIKE '%".$keyword."%'  OR
8331
                user.email LIKE '%".$keyword."%'
8332
             ) ";
8333
        }
8334
8335
        $url_table = '';
8336
        $url_condition = '';
8337
        if (api_is_multiple_url_enabled()) {
8338
            $url_table = " INNER JOIN $tbl_url_rel_user as url_users ON (user.id = url_users.user_id)";
8339
            $url_condition = " AND access_url_id = '$access_url_id'";
8340
        }
8341
8342
        $invitedUsersCondition = '';
8343
        if (!$includeInvitedUsers) {
8344
            $invitedUsersCondition = " AND user.status != ".INVITEE;
8345
        }
8346
8347
        $select = '
8348
                SELECT user.id as user_id,
8349
                    user.official_code  as col0,
8350
                    user.lastname       as col1,
8351
                    user.firstname      as col2,
8352
                    user.username       as col3,
8353
                    user.email          as col4';
8354
        if ($getCount) {
8355
            $select = ' SELECT COUNT(distinct(user.id)) as count ';
8356
        }
8357
8358
        $sqlInjectJoins = '';
8359
        $where = 'AND 1 = 1 ';
8360
        $sqlInjectWhere = '';
8361
        if (!empty($conditions)) {
8362
            if (isset($conditions['inject_joins'])) {
8363
                $sqlInjectJoins = $conditions['inject_joins'];
8364
            }
8365
            if (isset($conditions['where'])) {
8366
                $where = $conditions['where'];
8367
            }
8368
            if (isset($conditions['inject_where'])) {
8369
                $sqlInjectWhere = $conditions['inject_where'];
8370
            }
8371
            $injectExtraFields = !empty($conditions['inject_extra_fields']) ? $conditions['inject_extra_fields'] : 1;
8372
            $injectExtraFields = rtrim($injectExtraFields, ', ');
8373
            if (false === $getCount) {
8374
                $select .= " , $injectExtraFields";
8375
            }
8376
        }
8377
8378
        $sql = "$select
8379
                FROM $tbl_user as user
8380
                $url_table
8381
                $sqlInjectJoins
8382
                $condition_user
8383
                $url_condition
8384
                $invitedUsersCondition
8385
                $where
8386
                $sqlInjectWhere
8387
                ";
8388
8389
        if (!in_array($direction, ['ASC', 'DESC'])) {
8390
            $direction = 'ASC';
8391
        }
8392
8393
        $column = (int) $column;
8394
        $from = (int) $from;
8395
        $number_of_items = (int) $number_of_items;
8396
8397
        if ($getCount) {
8398
            $res = Database::query($sql);
8399
            $row = Database::fetch_array($res);
8400
8401
            return $row['count'];
8402
        }
8403
8404
        $sql .= " ORDER BY col$column $direction ";
8405
        $sql .= " LIMIT $from, $number_of_items";
8406
8407
        $res = Database::query($sql);
8408
        $users = [];
8409
8410
        $courseInfo = api_get_course_info($course_code);
8411
        $courseId = $courseInfo['real_id'];
8412
        $courseCode = $courseInfo['code'];
8413
8414
        $total_surveys = 0;
8415
        $total_exercises = ExerciseLib::get_all_exercises(
8416
            $courseInfo,
8417
            $session_id,
8418
            false,
8419
            null,
8420
            false,
8421
            3
8422
        );
8423
8424
        if (empty($session_id)) {
8425
            $survey_user_list = [];
8426
            $surveyList = SurveyManager::get_surveys($course_code, $session_id);
8427
            if ($surveyList) {
8428
                $total_surveys = count($surveyList);
8429
                foreach ($surveyList as $survey) {
8430
                    $user_list = SurveyManager::get_people_who_filled_survey(
8431
                    $survey['survey_id'],
8432
                    false,
8433
                        $courseId
8434
                );
8435
8436
                    foreach ($user_list as $user_id) {
8437
                        isset($survey_user_list[$user_id]) ? $survey_user_list[$user_id]++ : $survey_user_list[$user_id] = 1;
8438
                    }
8439
                }
8440
            }
8441
        }
8442
8443
        $urlBase = api_get_path(WEB_CODE_PATH).'mySpace/myStudents.php?details=true&cidReq='.$courseCode.
8444
            '&course='.$course_code.'&origin=tracking_course&id_session='.$session_id;
8445
8446
        $sortByFirstName = api_sort_by_first_name();
8447
        Session::write('user_id_list', []);
8448
        $userIdList = [];
8449
        $addExerciseOption = api_get_configuration_value('add_exercise_best_attempt_in_report');
8450
        $exerciseResultsToCheck = [];
8451
        if (!empty($addExerciseOption) && isset($addExerciseOption['courses']) &&
8452
            isset($addExerciseOption['courses'][$courseCode])
8453
        ) {
8454
            foreach ($addExerciseOption['courses'][$courseCode] as $exerciseId) {
8455
                $exercise = new Exercise();
8456
                $exercise->read($exerciseId);
8457
                if ($exercise->iId) {
8458
                    $exerciseResultsToCheck[] = $exercise;
8459
                }
8460
            }
8461
        }
8462
        while ($user = Database::fetch_array($res, 'ASSOC')) {
8463
            $userIdList[] = $user['user_id'];
8464
            $user['official_code'] = $user['col0'];
8465
            $user['username'] = $user['col3'];
8466
            $user['time'] = api_time_to_hms(
8467
                Tracking::get_time_spent_on_the_course(
8468
                    $user['user_id'],
8469
                    $courseId,
8470
                    $session_id
8471
                )
8472
            );
8473
8474
            $avg_student_score = Tracking::get_avg_student_score(
8475
                $user['user_id'],
8476
                $course_code,
8477
                [],
8478
                $session_id
8479
            );
8480
8481
            $averageBestScore = Tracking::get_avg_student_score(
8482
                $user['user_id'],
8483
                $course_code,
8484
                [],
8485
                $session_id,
8486
                false,
8487
                false,
8488
                true
8489
            );
8490
8491
            $avg_student_progress = Tracking::get_avg_student_progress(
8492
                $user['user_id'],
8493
                $course_code,
8494
                [],
8495
                $session_id
8496
            );
8497
8498
            if (empty($avg_student_progress)) {
8499
                $avg_student_progress = 0;
8500
            }
8501
            $user['average_progress'] = $avg_student_progress.'%';
8502
8503
            $total_user_exercise = Tracking::get_exercise_student_progress(
8504
                $total_exercises,
8505
                $user['user_id'],
8506
                $courseId,
8507
                $session_id
8508
            );
8509
8510
            $user['exercise_progress'] = $total_user_exercise;
8511
8512
            $total_user_exercise = Tracking::get_exercise_student_average_best_attempt(
8513
                $total_exercises,
8514
                $user['user_id'],
8515
                $courseId,
8516
                $session_id
8517
            );
8518
8519
            $user['exercise_average_best_attempt'] = $total_user_exercise;
8520
8521
            if (is_numeric($avg_student_score)) {
8522
                $user['student_score'] = $avg_student_score.'%';
8523
            } else {
8524
                $user['student_score'] = $avg_student_score;
8525
            }
8526
8527
            if (is_numeric($averageBestScore)) {
8528
                $user['student_score_best'] = $averageBestScore.'%';
8529
            } else {
8530
                $user['student_score_best'] = $averageBestScore;
8531
            }
8532
8533
            $exerciseResults = [];
8534
            if (!empty($exerciseResultsToCheck)) {
8535
                foreach ($exerciseResultsToCheck as $exercise) {
8536
                    $bestExerciseResult = Event::get_best_attempt_exercise_results_per_user(
8537
                        $user['user_id'],
8538
                        $exercise->iId,
8539
                        $courseId,
8540
                        $session_id,
8541
                        false
8542
                    );
8543
8544
                    $best = null;
8545
                    if ($bestExerciseResult) {
8546
                        $best = $bestExerciseResult['exe_result'] / $bestExerciseResult['exe_weighting'];
8547
                        $best = round($best, 2) * 100;
8548
                        $best .= '%';
8549
                    }
8550
                    $exerciseResults['exercise_'.$exercise->iId] = $best;
8551
                }
8552
            }
8553
            $user['count_assignments'] = Tracking::count_student_assignments(
8554
                $user['user_id'],
8555
                $course_code,
8556
                $session_id
8557
            );
8558
            $user['count_messages'] = Tracking::count_student_messages(
8559
                $user['user_id'],
8560
                $course_code,
8561
                $session_id
8562
            );
8563
            $user['first_connection'] = Tracking::get_first_connection_date_on_the_course(
8564
                $user['user_id'],
8565
                $courseId,
8566
                $session_id,
8567
                false === $export_csv
8568
            );
8569
8570
            $user['last_connection'] = Tracking::get_last_connection_date_on_the_course(
8571
                $user['user_id'],
8572
                $courseInfo,
8573
                $session_id,
8574
                false === $export_csv
8575
            );
8576
8577
            if ($export_csv) {
8578
                if (!empty($user['first_connection'])) {
8579
                    $user['first_connection'] = api_get_local_time($user['first_connection']);
8580
                } else {
8581
                    $user['first_connection'] = '-';
8582
                }
8583
                if (!empty($user['last_connection'])) {
8584
                    $user['last_connection'] = api_get_local_time($user['last_connection']);
8585
                } else {
8586
                    $user['last_connection'] = '-';
8587
                }
8588
            }
8589
8590
            if (empty($session_id)) {
8591
                $user['survey'] = (isset($survey_user_list[$user['user_id']]) ? $survey_user_list[$user['user_id']] : 0).' / '.$total_surveys;
8592
            }
8593
8594
            $url = $urlBase.'&student='.$user['user_id'];
8595
8596
            $user['link'] = '<center><a href="'.$url.'">
8597
                            '.Display::return_icon('2rightarrow.png', get_lang('Details')).'
8598
                             </a></center>';
8599
8600
            // store columns in array $users
8601
            $user_row = [];
8602
            $user_row['official_code'] = $user['official_code']; //0
8603
            if ($sortByFirstName) {
8604
                $user_row['firstname'] = $user['col2'];
8605
                $user_row['lastname'] = $user['col1'];
8606
            } else {
8607
                $user_row['lastname'] = $user['col1'];
8608
                $user_row['firstname'] = $user['col2'];
8609
            }
8610
            $user_row['username'] = $user['username'];
8611
            $user_row['time'] = $user['time'];
8612
            $user_row['average_progress'] = $user['average_progress'];
8613
            $user_row['exercise_progress'] = $user['exercise_progress'];
8614
            $user_row['exercise_average_best_attempt'] = $user['exercise_average_best_attempt'];
8615
            $user_row['student_score'] = $user['student_score'];
8616
            $user_row['student_score_best'] = $user['student_score_best'];
8617
            if (!empty($exerciseResults)) {
8618
                foreach ($exerciseResults as $exerciseId => $bestResult) {
8619
                    $user_row[$exerciseId] = $bestResult;
8620
                }
8621
            }
8622
            $user_row['count_assignments'] = $user['count_assignments'];
8623
            $user_row['count_messages'] = $user['count_messages'];
8624
8625
            $userGroupManager = new UserGroup();
8626
            $user_row['classes'] = $userGroupManager->getLabelsFromNameList($user['user_id'], UserGroup::NORMAL_CLASS);
8627
8628
            if (empty($session_id)) {
8629
                $user_row['survey'] = $user['survey'];
8630
            } else {
8631
                $userSession = SessionManager::getUserSession($user['user_id'], $session_id);
8632
                $user_row['registered_at'] = '';
8633
                if ($userSession) {
8634
                    $user_row['registered_at'] = api_get_local_time($userSession['registered_at']);
8635
                }
8636
            }
8637
8638
            $user_row['first_connection'] = $user['first_connection'];
8639
            $user_row['last_connection'] = $user['last_connection'];
8640
8641
            // we need to display an additional profile field
8642
            if (isset($_GET['additional_profile_field'])) {
8643
                $data = Session::read('additional_user_profile_info');
8644
8645
                $extraFieldInfo = Session::read('extra_field_info');
8646
                foreach ($_GET['additional_profile_field'] as $fieldId) {
8647
                    if (isset($data[$fieldId]) && isset($data[$fieldId][$user['user_id']])) {
8648
                        if (is_array($data[$fieldId][$user['user_id']])) {
8649
                            $user_row[$extraFieldInfo[$fieldId]['variable']] = implode(
8650
                                ', ',
8651
                                $data[$fieldId][$user['user_id']]
8652
                            );
8653
                        } else {
8654
                            $user_row[$extraFieldInfo[$fieldId]['variable']] = $data[$fieldId][$user['user_id']];
8655
                        }
8656
                    } else {
8657
                        $user_row[$extraFieldInfo[$fieldId]['variable']] = '';
8658
                    }
8659
                }
8660
            }
8661
8662
            if ('true' === api_get_setting('show_email_addresses')) {
8663
                $user_row['email'] = $user['col4'];
8664
            }
8665
8666
            $user_row['link'] = $user['link'];
8667
8668
            if ($export_csv) {
8669
                if (empty($session_id)) {
8670
                    unset($user_row['classes']);
8671
                    unset($user_row['link']);
8672
                } else {
8673
                    unset($user_row['classes']);
8674
                    unset($user_row['link']);
8675
                }
8676
8677
                $csv_content[] = $user_row;
8678
            }
8679
            $users[] = array_values($user_row);
8680
        }
8681
8682
        if ($export_csv) {
8683
            Session::write('csv_content', $csv_content);
8684
        }
8685
8686
        Session::erase('additional_user_profile_info');
8687
        Session::erase('extra_field_info');
8688
        Session::write('user_id_list', $userIdList);
8689
8690
        return $users;
8691
    }
8692
8693
    /**
8694
     * Get data for users list in sortable with pagination.
8695
     *
8696
     * @param $from
8697
     * @param $number_of_items
8698
     * @param $column
8699
     * @param $direction
8700
     * @param $includeInvitedUsers boolean Whether include the invited users
8701
     *
8702
     * @return array
8703
     */
8704
    public static function getTotalTimeReport(
8705
        $from,
8706
        $number_of_items,
8707
        $column,
8708
        $direction,
8709
        $includeInvitedUsers = false
8710
    ) {
8711
        global $user_ids, $course_code, $export_csv, $csv_content, $session_id;
8712
8713
        $course_code = Database::escape_string($course_code);
8714
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
8715
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
8716
        $access_url_id = api_get_current_access_url_id();
8717
8718
        // get all users data from a course for sortable with limit
8719
        if (is_array($user_ids)) {
8720
            $user_ids = array_map('intval', $user_ids);
8721
            $condition_user = " WHERE user.user_id IN (".implode(',', $user_ids).") ";
8722
        } else {
8723
            $user_ids = intval($user_ids);
8724
            $condition_user = " WHERE user.user_id = $user_ids ";
8725
        }
8726
8727
        $url_table = null;
8728
        $url_condition = null;
8729
        if (api_is_multiple_url_enabled()) {
8730
            $url_table = ", ".$tbl_url_rel_user." as url_users";
8731
            $url_condition = " AND user.user_id = url_users.user_id AND access_url_id='$access_url_id'";
8732
        }
8733
8734
        $invitedUsersCondition = '';
8735
        if (!$includeInvitedUsers) {
8736
            $invitedUsersCondition = " AND user.status != ".INVITEE;
8737
        }
8738
8739
        $sql = "SELECT  user.user_id as user_id,
8740
                    user.official_code  as col0,
8741
                    user.lastname       as col1,
8742
                    user.firstname      as col2,
8743
                    user.username       as col3
8744
                FROM $tbl_user as user $url_table
8745
                $condition_user $url_condition $invitedUsersCondition";
8746
8747
        if (!in_array($direction, ['ASC', 'DESC'])) {
8748
            $direction = 'ASC';
8749
        }
8750
8751
        $column = (int) $column;
8752
        $from = (int) $from;
8753
        $number_of_items = (int) $number_of_items;
8754
8755
        $sql .= " ORDER BY col$column $direction ";
8756
        $sql .= " LIMIT $from,$number_of_items";
8757
8758
        $res = Database::query($sql);
8759
        $users = [];
8760
8761
        $sortByFirstName = api_sort_by_first_name();
8762
        $courseInfo = api_get_course_info($course_code);
8763
        $courseId = $courseInfo['real_id'];
8764
8765
        while ($user = Database::fetch_array($res, 'ASSOC')) {
8766
            $user['official_code'] = $user['col0'];
8767
            $user['lastname'] = $user['col1'];
8768
            $user['firstname'] = $user['col2'];
8769
            $user['username'] = $user['col3'];
8770
8771
            $totalCourseTime = Tracking::get_time_spent_on_the_course(
8772
                $user['user_id'],
8773
                $courseId,
8774
                $session_id
8775
            );
8776
8777
            $user['time'] = api_time_to_hms($totalCourseTime);
8778
            $totalLpTime = Tracking::get_time_spent_in_lp(
8779
                $user['user_id'],
8780
                $course_code,
8781
                [],
8782
                $session_id
8783
            );
8784
8785
            $user['total_lp_time'] = $totalLpTime;
8786
            $warning = '';
8787
            if ($totalLpTime > $totalCourseTime) {
8788
                $warning = '&nbsp;'.Display::label(get_lang('Time difference'), 'danger');
8789
            }
8790
8791
            $user['total_lp_time'] = api_time_to_hms($totalLpTime).$warning;
8792
8793
            $user['first_connection'] = Tracking::get_first_connection_date_on_the_course(
8794
                $user['user_id'],
8795
                $courseId,
8796
                $session_id
8797
            );
8798
            $user['last_connection'] = Tracking::get_last_connection_date_on_the_course(
8799
                $user['user_id'],
8800
                $courseInfo,
8801
                $session_id,
8802
                false === $export_csv
8803
            );
8804
8805
            $user['link'] = '<center>
8806
                             <a href="../mySpace/myStudents.php?student='.$user['user_id'].'&details=true&course='.$course_code.'&origin=tracking_course&id_session='.$session_id.'">
8807
                             '.Display::return_icon('2rightarrow.png', get_lang('Details')).'
8808
                             </a>
8809
                         </center>';
8810
8811
            // store columns in array $users
8812
            $user_row = [];
8813
            $user_row['official_code'] = $user['official_code']; //0
8814
            if ($sortByFirstName) {
8815
                $user_row['firstname'] = $user['firstname'];
8816
                $user_row['lastname'] = $user['lastname'];
8817
            } else {
8818
                $user_row['lastname'] = $user['lastname'];
8819
                $user_row['firstname'] = $user['firstname'];
8820
            }
8821
            $user_row['username'] = $user['username'];
8822
            $user_row['time'] = $user['time'];
8823
            $user_row['total_lp_time'] = $user['total_lp_time'];
8824
            $user_row['first_connection'] = $user['first_connection'];
8825
            $user_row['last_connection'] = $user['last_connection'];
8826
8827
            $user_row['link'] = $user['link'];
8828
            $users[] = array_values($user_row);
8829
        }
8830
8831
        return $users;
8832
    }
8833
8834
    /**
8835
     * @param string $current
8836
     */
8837
    public static function actionsLeft($current, $sessionId = 0)
8838
    {
8839
        $usersLink = Display::url(
8840
            Display::return_icon('user.png', get_lang('Report on learners'), [], ICON_SIZE_MEDIUM),
8841
            'courseLog.php?'.api_get_cidreq(true, false)
8842
        );
8843
8844
        $groupsLink = Display::url(
8845
            Display::return_icon('group.png', get_lang('Group reporting'), [], ICON_SIZE_MEDIUM),
8846
            'course_log_groups.php?'.api_get_cidreq()
8847
        );
8848
8849
        $resourcesLink = Display::url(
8850
            Display::return_icon('tools.png', get_lang('Report on resource'), [], ICON_SIZE_MEDIUM),
8851
            'course_log_resources.php?'.api_get_cidreq(true, false)
8852
        );
8853
8854
        $courseLink = Display::url(
8855
            Display::return_icon('course.png', get_lang('Course report'), [], ICON_SIZE_MEDIUM),
8856
            'course_log_tools.php?'.api_get_cidreq(true, false)
8857
        );
8858
8859
        $examLink = Display::url(
8860
            Display::return_icon('quiz.png', get_lang('Exam tracking'), [], ICON_SIZE_MEDIUM),
8861
            api_get_path(WEB_CODE_PATH).'tracking/exams.php?'.api_get_cidreq()
8862
        );
8863
8864
        $eventsLink = Display::url(
8865
            Display::return_icon('security.png', get_lang('Audit report'), [], ICON_SIZE_MEDIUM),
8866
            api_get_path(WEB_CODE_PATH).'tracking/course_log_events.php?'.api_get_cidreq()
8867
        );
8868
8869
        $lpLink = Display::url(
8870
            Display::return_icon('scorms.png', get_lang('CourseLPsGenericStats'), [], ICON_SIZE_MEDIUM),
8871
            api_get_path(WEB_CODE_PATH).'tracking/lp_report.php?'.api_get_cidreq()
8872
        );
8873
8874
        $attendanceLink = '';
8875
        if (!empty($sessionId)) {
8876
            $attendanceLink = Display::url(
8877
                Display::return_icon('attendance_list.png', get_lang('Logins'), '', ICON_SIZE_MEDIUM),
8878
                api_get_path(WEB_CODE_PATH).'attendance/index.php?'.api_get_cidreq().'&action=calendar_logins'
8879
            );
8880
        }
8881
8882
        switch ($current) {
8883
            case 'users':
8884
                $usersLink = Display::url(
8885
                        Display::return_icon(
8886
                        'user_na.png',
8887
                        get_lang('Report on learners'),
8888
                        [],
8889
                        ICON_SIZE_MEDIUM
8890
                    ),
8891
                    '#'
8892
                );
8893
                break;
8894
            case 'groups':
8895
                $groupsLink = Display::url(
8896
                    Display::return_icon('group_na.png', get_lang('Group reporting'), [], ICON_SIZE_MEDIUM),
8897
                    '#'
8898
                );
8899
                break;
8900
            case 'courses':
8901
                $courseLink = Display::url(
8902
                    Display::return_icon('course_na.png', get_lang('Course report'), [], ICON_SIZE_MEDIUM),
8903
                    '#'
8904
                );
8905
                break;
8906
            case 'resources':
8907
                $resourcesLink = Display::url(
8908
                    Display::return_icon(
8909
                    'tools_na.png',
8910
                    get_lang('Report on resource'),
8911
                    [],
8912
                    ICON_SIZE_MEDIUM
8913
                    ),
8914
                    '#'
8915
                );
8916
                break;
8917
            case 'exams':
8918
                $examLink = Display::url(
8919
                    Display::return_icon('quiz_na.png', get_lang('Exam tracking'), [], ICON_SIZE_MEDIUM),
8920
                    '#'
8921
                );
8922
                break;
8923
            case 'logs':
8924
                $eventsLink = Display::url(
8925
                    Display::return_icon('security_na.png', get_lang('Audit report'), [], ICON_SIZE_MEDIUM),
8926
                    '#'
8927
                );
8928
                break;
8929
            case 'attendance':
8930
                if (!empty($sessionId)) {
8931
                    $attendanceLink = Display::url(
8932
                        Display::return_icon('attendance_list.png', get_lang('Logins'), '', ICON_SIZE_MEDIUM),
8933
                        '#'
8934
                    );
8935
                }
8936
                break;
8937
            case 'lp':
8938
                $lpLink = Display::url(
8939
                    Display::return_icon('scorms_na.png', get_lang('CourseLPsGenericStats'), [], ICON_SIZE_MEDIUM),
8940
                    '#'
8941
                );
8942
                break;
8943
        }
8944
8945
        $items = [
8946
            $usersLink,
8947
            $groupsLink,
8948
            $courseLink,
8949
            $resourcesLink,
8950
            $examLink,
8951
            $eventsLink,
8952
            $lpLink,
8953
            $attendanceLink,
8954
        ];
8955
8956
        return implode('', $items).'&nbsp;';
8957
    }
8958
}
8959