Passed
Push — 1.11.x ( cd7ea3...4f89e2 )
by Julito
11:36
created

Tracking::minimumTimeAvailable()   B

Complexity

Conditions 10
Paths 6

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 14
nc 6
nop 2
dl 0
loc 24
rs 7.6666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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