Passed
Push — master ( 668bf0...77aaf8 )
by Julito
11:36 queued 12s
created

Tracking::get_time_spent_on_the_course()   B

Complexity

Conditions 8
Paths 9

Size

Total Lines 47
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

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

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

Loading history...
1320
        }
1321
1322
        return $output;
1323
    }
1324
1325
    /**
1326
     * @param int  $userId
1327
     * @param bool $getCount
1328
     *
1329
     * @return array
1330
     */
1331
    public static function getStats($userId, $getCount = false)
1332
    {
1333
        $courses = [];
1334
        $assignedCourses = [];
1335
        $drhCount = 0;
1336
        $teachersCount = 0;
1337
        $studentsCount = 0;
1338
        $studentBossCount = 0;
1339
        $courseCount = 0;
1340
        $sessionCount = 0;
1341
        $assignedCourseCount = 0;
1342
1343
        if (api_is_drh() && api_drh_can_access_all_session_content()) {
1344
            $studentList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1345
                'drh_all',
1346
                $userId,
1347
                false,
1348
                null,
1349
                null,
1350
                null,
1351
                null,
1352
                null,
1353
                null,
1354
                null,
1355
                [],
1356
                [],
1357
                STUDENT
1358
            );
1359
1360
            $students = [];
1361
            if (is_array($studentList)) {
1362
                foreach ($studentList as $studentData) {
1363
                    $students[] = $studentData['user_id'];
1364
                }
1365
            }
1366
1367
            $studentBossesList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1368
                'drh_all',
1369
                $userId,
1370
                $getCount,
1371
                null,
1372
                null,
1373
                null,
1374
                null,
1375
                null,
1376
                null,
1377
                null,
1378
                [],
1379
                [],
1380
                STUDENT_BOSS
1381
            );
1382
1383
            if ($getCount) {
1384
                $studentBossCount = $studentBossesList;
1385
            } else {
1386
                $studentBosses = [];
1387
                if (is_array($studentBossesList)) {
1388
                    foreach ($studentBossesList as $studentBossData) {
1389
                        $studentBosses[] = $studentBossData['user_id'];
1390
                    }
1391
                }
1392
            }
1393
1394
            $teacherList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1395
                'drh_all',
1396
                $userId,
1397
                $getCount,
1398
                null,
1399
                null,
1400
                null,
1401
                null,
1402
                null,
1403
                null,
1404
                null,
1405
                [],
1406
                [],
1407
                COURSEMANAGER
1408
            );
1409
1410
            if ($getCount) {
1411
                $teachersCount = $teacherList;
1412
            } else {
1413
                $teachers = [];
1414
                foreach ($teacherList as $teacherData) {
1415
                    $teachers[] = $teacherData['user_id'];
1416
                }
1417
            }
1418
1419
            $humanResources = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1420
                'drh_all',
1421
                $userId,
1422
                $getCount,
1423
                null,
1424
                null,
1425
                null,
1426
                null,
1427
                null,
1428
                null,
1429
                null,
1430
                [],
1431
                [],
1432
                DRH
1433
            );
1434
1435
            if ($getCount) {
1436
                $drhCount = $humanResources;
1437
            } else {
1438
                $humanResourcesList = [];
1439
                if (is_array($humanResources)) {
1440
                    foreach ($humanResources as $item) {
1441
                        $humanResourcesList[] = $item['user_id'];
1442
                    }
1443
                }
1444
            }
1445
1446
            $platformCourses = SessionManager::getAllCoursesFollowedByUser(
1447
                $userId,
1448
                null,
1449
                null,
1450
                null,
1451
                null,
1452
                null,
1453
                $getCount
1454
            );
1455
1456
            if ($getCount) {
1457
                $courseCount = $platformCourses;
1458
            } else {
1459
                foreach ($platformCourses as $course) {
1460
                    $courses[$course['code']] = $course['code'];
1461
                }
1462
            }
1463
1464
            $sessions = SessionManager::get_sessions_followed_by_drh(
1465
                $userId,
1466
                null,
1467
                null,
1468
                false
1469
            );
1470
        } else {
1471
            $studentList = UserManager::getUsersFollowedByUser(
1472
                $userId,
1473
                STUDENT,
1474
                false,
1475
                false,
1476
                false,
1477
                null,
1478
                null,
1479
                null,
1480
                null,
1481
                null,
1482
                null,
1483
                COURSEMANAGER
1484
            );
1485
1486
            $students = [];
1487
            if (is_array($studentList)) {
1488
                foreach ($studentList as $studentData) {
1489
                    $students[] = $studentData['user_id'];
1490
                }
1491
            }
1492
1493
            $studentBossesList = UserManager::getUsersFollowedByUser(
1494
                $userId,
1495
                STUDENT_BOSS,
1496
                false,
1497
                false,
1498
                $getCount,
1499
                null,
1500
                null,
1501
                null,
1502
                null,
1503
                null,
1504
                null,
1505
                COURSEMANAGER
1506
            );
1507
1508
            if ($getCount) {
1509
                $studentBossCount = $studentBossesList;
1510
            } else {
1511
                $studentBosses = [];
1512
                if (is_array($studentBossesList)) {
1513
                    foreach ($studentBossesList as $studentBossData) {
1514
                        $studentBosses[] = $studentBossData['user_id'];
1515
                    }
1516
                }
1517
            }
1518
1519
            $teacherList = UserManager::getUsersFollowedByUser(
1520
                $userId,
1521
                COURSEMANAGER,
1522
                false,
1523
                false,
1524
                $getCount,
1525
                null,
1526
                null,
1527
                null,
1528
                null,
1529
                null,
1530
                null,
1531
                COURSEMANAGER
1532
            );
1533
1534
            if ($getCount) {
1535
                $teachersCount = $teacherList;
1536
            } else {
1537
                $teachers = [];
1538
                foreach ($teacherList as $teacherData) {
1539
                    $teachers[] = $teacherData['user_id'];
1540
                }
1541
            }
1542
1543
            $humanResources = UserManager::getUsersFollowedByUser(
1544
                $userId,
1545
                DRH,
1546
                false,
1547
                false,
1548
                $getCount,
1549
                null,
1550
                null,
1551
                null,
1552
                null,
1553
                null,
1554
                null,
1555
                COURSEMANAGER
1556
            );
1557
1558
            if ($getCount) {
1559
                $drhCount = $humanResources;
1560
            } else {
1561
                $humanResourcesList = [];
1562
                foreach ($humanResources as $item) {
1563
                    $humanResourcesList[] = $item['user_id'];
1564
                }
1565
            }
1566
1567
            $platformCourses = CourseManager::getCoursesFollowedByUser(
1568
                $userId,
1569
                COURSEMANAGER,
1570
                null,
1571
                null,
1572
                null,
1573
                null,
1574
                $getCount,
1575
                null,
1576
                null,
1577
                true
1578
            );
1579
1580
            if ($getCount) {
1581
                $assignedCourseCount = $platformCourses;
1582
            } else {
1583
                foreach ($platformCourses as $course) {
1584
                    $assignedCourses[$course['code']] = $course['code'];
1585
                }
1586
            }
1587
1588
            $platformCourses = CourseManager::getCoursesFollowedByUser(
1589
                $userId,
1590
                COURSEMANAGER,
1591
                null,
1592
                null,
1593
                null,
1594
                null,
1595
                $getCount
1596
            );
1597
1598
            if ($getCount) {
1599
                $courseCount = $platformCourses;
1600
            } else {
1601
                foreach ($platformCourses as $course) {
1602
                    $courses[$course['code']] = $course['code'];
1603
                }
1604
            }
1605
1606
            $sessions = SessionManager::getSessionsFollowedByUser(
1607
                $userId,
1608
                COURSEMANAGER,
1609
                null,
1610
                null,
1611
                false
1612
            );
1613
        }
1614
1615
        if ($getCount) {
1616
            return [
1617
                'drh' => $drhCount,
1618
                'teachers' => $teachersCount,
1619
                'student_count' => count($students),
1620
                'student_list' => $students,
1621
                'student_bosses' => $studentBossCount,
1622
                'courses' => $courseCount,
1623
                'session_count' => count($sessions),
1624
                'session_list' => $sessions,
1625
                'assigned_courses' => $assignedCourseCount,
1626
            ];
1627
        }
1628
1629
        return [
1630
            'drh' => $humanResourcesList,
1631
            'teachers' => $teachers,
1632
            'student_list' => $students,
1633
            'student_bosses' => $studentBosses,
1634
            'courses' => $courses,
1635
            'sessions' => $sessions,
1636
            'assigned_courses' => $assignedCourses,
1637
        ];
1638
    }
1639
1640
    /**
1641
     * Calculates the time spent on the platform by a user.
1642
     *
1643
     * @param int|array $userId
1644
     * @param string    $timeFilter       type of time filter: 'last_week' or 'custom'
1645
     * @param string    $start_date       start date date('Y-m-d H:i:s')
1646
     * @param string    $end_date         end date date('Y-m-d H:i:s')
1647
     * @param bool      $returnAllRecords
1648
     *
1649
     * @return int
1650
     */
1651
    public static function get_time_spent_on_the_platform(
1652
        $userId,
1653
        $timeFilter = 'last_7_days',
1654
        $start_date = null,
1655
        $end_date = null,
1656
        $returnAllRecords = false
1657
    ) {
1658
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1659
        $condition_time = '';
1660
1661
        if (is_array($userId)) {
1662
            $userList = array_map('intval', $userId);
1663
            $userCondition = " login_user_id IN ('".implode("','", $userList)."')";
1664
        } else {
1665
            $userId = (int) $userId;
1666
            $userCondition = " login_user_id = $userId ";
1667
        }
1668
1669
        $url_condition = null;
1670
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1671
        $url_table = null;
1672
        if (api_is_multiple_url_enabled()) {
1673
            $access_url_id = api_get_current_access_url_id();
1674
            $url_table = ", $tbl_url_rel_user as url_users";
1675
            $url_condition = " AND u.login_user_id = url_users.user_id AND access_url_id='$access_url_id'";
1676
        }
1677
1678
        if (empty($timeFilter)) {
1679
            $timeFilter = 'last_week';
1680
        }
1681
1682
        $today = new DateTime('now', new DateTimeZone('UTC'));
1683
1684
        switch ($timeFilter) {
1685
            case 'last_7_days':
1686
                $newDate = new DateTime('-7 day', new DateTimeZone('UTC'));
1687
                $condition_time = " AND (login_date >= '{$newDate->format('Y-m-d H:i:s')}'";
1688
                $condition_time .= " AND logout_date <= '{$today->format('Y-m-d H:i:s')}') ";
1689
                break;
1690
            case 'last_30_days':
1691
                $newDate = new DateTime('-30 days', new DateTimeZone('UTC'));
1692
                $condition_time = " AND (login_date >= '{$newDate->format('Y-m-d H:i:s')}'";
1693
                $condition_time .= "AND logout_date <= '{$today->format('Y-m-d H:i:s')}') ";
1694
                break;
1695
            case 'wide':
1696
                if (!empty($start_date) && !empty($end_date)) {
1697
                    $start_date = Database::escape_string($start_date);
1698
                    $end_date = Database::escape_string($end_date);
1699
                    $condition_time = ' AND (
1700
                        (login_date >= "'.$start_date.'" AND login_date <= "'.$end_date.'") OR
1701
                        (logout_date >= "'.$start_date.'" AND logout_date <= "'.$end_date.'") OR
1702
                        (login_date <= "'.$start_date.'" AND logout_date >= "'.$end_date.'")
1703
                    ) ';
1704
                }
1705
                break;
1706
            case 'custom':
1707
                if (!empty($start_date) && !empty($end_date)) {
1708
                    $start_date = Database::escape_string($start_date);
1709
                    $end_date = Database::escape_string($end_date);
1710
                    $condition_time = ' AND (login_date >= "'.$start_date.'" AND logout_date <= "'.$end_date.'" ) ';
1711
                }
1712
                break;
1713
        }
1714
1715
        if ($returnAllRecords) {
1716
            $sql = "SELECT login_date, logout_date, TIMESTAMPDIFF(SECOND, login_date, logout_date) diff
1717
                    FROM $tbl_track_login u $url_table
1718
                    WHERE $userCondition $condition_time $url_condition
1719
                    ORDER BY login_date";
1720
            $rs = Database::query($sql);
1721
1722
            return Database::store_result($rs, 'ASSOC');
1723
        }
1724
1725
        $sql = "SELECT SUM(TIMESTAMPDIFF(SECOND, login_date, logout_date)) diff
1726
    	        FROM $tbl_track_login u $url_table
1727
                WHERE $userCondition $condition_time $url_condition";
1728
        $rs = Database::query($sql);
1729
        $row = Database::fetch_array($rs, 'ASSOC');
1730
        $diff = $row['diff'];
1731
1732
        if ($diff >= 0) {
1733
            return $diff;
1734
        }
1735
1736
        return -1;
1737
    }
1738
1739
    /**
1740
     * @param string $startDate
1741
     * @param string $endDate
1742
     *
1743
     * @return int
1744
     */
1745
    public static function getTotalTimeSpentOnThePlatform(
1746
        $startDate = '',
1747
        $endDate = ''
1748
    ) {
1749
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1750
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1751
1752
        $url_table = null;
1753
        $url_condition = null;
1754
        if (api_is_multiple_url_enabled()) {
1755
            $access_url_id = api_get_current_access_url_id();
1756
            $url_table = ", ".$tbl_url_rel_user." as url_users";
1757
            $url_condition = " AND u.login_user_id = url_users.user_id AND access_url_id='$access_url_id'";
1758
        }
1759
1760
        if (!empty($startDate) && !empty($endDate)) {
1761
            $startDate = Database::escape_string($startDate);
1762
            $endDate = Database::escape_string($endDate);
1763
            $condition_time = ' (login_date >= "'.$startDate.'" AND logout_date <= "'.$endDate.'" ) ';
1764
        }
1765
        $sql = "SELECT SUM(TIMESTAMPDIFF(SECOND, login_date, logout_date)) diff
1766
    	        FROM $tbl_track_login u $url_table
1767
                WHERE $condition_time $url_condition";
1768
        $rs = Database::query($sql);
1769
        $row = Database::fetch_array($rs, 'ASSOC');
1770
        $diff = $row['diff'];
1771
1772
        if ($diff >= 0) {
1773
            return $diff;
1774
        }
1775
1776
        return -1;
1777
    }
1778
1779
    /**
1780
     * Checks if the "lp_minimum_time" feature is available for the course.
1781
     *
1782
     * @param int $sessionId
1783
     * @param int $courseId
1784
     *
1785
     * @return bool
1786
     */
1787
    public static function minimumTimeAvailable($sessionId, $courseId)
1788
    {
1789
        if (!api_get_configuration_value('lp_minimum_time')) {
1790
            return false;
1791
        }
1792
1793
        if (!empty($sessionId)) {
1794
            $extraFieldValue = new ExtraFieldValue('session');
1795
            $value = $extraFieldValue->get_values_by_handler_and_field_variable($sessionId, 'new_tracking_system');
1796
1797
            if ($value && isset($value['value']) && 1 == $value['value']) {
1798
                return true;
1799
            }
1800
        } else {
1801
            if ($courseId) {
1802
                $extraFieldValue = new ExtraFieldValue('course');
1803
                $value = $extraFieldValue->get_values_by_handler_and_field_variable($courseId, 'new_tracking_system');
1804
                if ($value && isset($value['value']) && 1 == $value['value']) {
1805
                    return true;
1806
                }
1807
            }
1808
        }
1809
1810
        return false;
1811
    }
1812
1813
    /**
1814
     * Calculates the time spent on the course.
1815
     *
1816
     * @param int $user_id
1817
     * @param int $courseId
1818
     * @param int $session_id
1819
     *
1820
     * @return int Time in seconds
1821
     */
1822
    public static function get_time_spent_on_the_course(
1823
        $user_id,
1824
        $courseId,
1825
        $session_id = 0
1826
    ) {
1827
        $courseId = (int) $courseId;
1828
1829
        if (empty($courseId) || empty($user_id)) {
1830
            return 0;
1831
        }
1832
1833
        if (self::minimumTimeAvailable($session_id, $courseId)) {
1834
            $courseTime = self::getCalculateTime($user_id, $courseId, $session_id);
1835
1836
            return isset($courseTime['total_time']) ? $courseTime['total_time'] : 0;
1837
        }
1838
1839
        $conditionUser = '';
1840
        $session_id = (int) $session_id;
1841
        if (is_array($user_id)) {
1842
            $user_id = array_map('intval', $user_id);
1843
            $conditionUser = " AND user_id IN (".implode(',', $user_id).") ";
1844
        } else {
1845
            if (!empty($user_id)) {
1846
                $user_id = (int) $user_id;
1847
                $conditionUser = " AND user_id = $user_id ";
1848
            }
1849
        }
1850
1851
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1852
        $sql = "SELECT
1853
                SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as nb_seconds
1854
                FROM $table
1855
                WHERE
1856
                    UNIX_TIMESTAMP(logout_course_date) > UNIX_TIMESTAMP(login_course_date) AND
1857
                    c_id = '$courseId' ";
1858
1859
        if (-1 != $session_id) {
1860
            $sql .= "AND session_id = '$session_id' ";
1861
        }
1862
1863
        $sql .= $conditionUser;
1864
1865
        $rs = Database::query($sql);
1866
        $row = Database::fetch_array($rs);
1867
1868
        return $row['nb_seconds'];
1869
    }
1870
1871
    /**
1872
     * Get first connection date for a student.
1873
     *
1874
     * @param int $student_id
1875
     *
1876
     * @return string|bool Date format long without day or false if there are no connections
1877
     */
1878
    public static function get_first_connection_date($student_id)
1879
    {
1880
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1881
        $sql = 'SELECT login_date
1882
                FROM '.$table.'
1883
                WHERE login_user_id = '.intval($student_id).'
1884
                ORDER BY login_date ASC
1885
                LIMIT 0,1';
1886
1887
        $rs = Database::query($sql);
1888
        if (Database::num_rows($rs) > 0) {
1889
            if ($first_login_date = Database::result($rs, 0, 0)) {
1890
                return api_convert_and_format_date(
1891
                    $first_login_date,
1892
                    DATE_FORMAT_SHORT
1893
                );
1894
            }
1895
        }
1896
1897
        return false;
1898
    }
1899
1900
    /**
1901
     * Get las connection date for a student.
1902
     *
1903
     * @param int  $student_id
1904
     * @param bool $warning_message  Show a warning message (optional)
1905
     * @param bool $return_timestamp True for returning results in timestamp (optional)
1906
     *
1907
     * @return string|int|bool Date format long without day, false if there are no connections or
1908
     *                         timestamp if parameter $return_timestamp is true
1909
     */
1910
    public static function get_last_connection_date(
1911
        $student_id,
1912
        $warning_message = false,
1913
        $return_timestamp = false
1914
    ) {
1915
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1916
        $sql = 'SELECT login_date
1917
                FROM '.$table.'
1918
                WHERE login_user_id = '.intval($student_id).'
1919
                ORDER BY login_date
1920
                DESC LIMIT 0,1';
1921
1922
        $rs = Database::query($sql);
1923
        if (Database::num_rows($rs) > 0) {
1924
            if ($last_login_date = Database::result($rs, 0, 0)) {
1925
                $last_login_date = api_get_local_time($last_login_date);
1926
                if ($return_timestamp) {
1927
                    return api_strtotime($last_login_date, 'UTC');
1928
                } else {
1929
                    if (!$warning_message) {
1930
                        return api_format_date($last_login_date, DATE_FORMAT_SHORT);
1931
                    } else {
1932
                        $timestamp = api_strtotime($last_login_date, 'UTC');
1933
                        $currentTimestamp = time();
1934
1935
                        //If the last connection is > than 7 days, the text is red
1936
                        //345600 = 7 days in seconds
1937
                        if ($currentTimestamp - $timestamp > 604800) {
1938
                            return '<span style="color: #F00;">'.api_format_date($last_login_date, DATE_FORMAT_SHORT).'</span>';
1939
                        } else {
1940
                            return api_format_date($last_login_date, DATE_FORMAT_SHORT);
1941
                        }
1942
                    }
1943
                }
1944
            }
1945
        }
1946
1947
        return false;
1948
    }
1949
1950
    /**
1951
     * Get first user's connection date on the course.
1952
     *
1953
     * @param int User id
1954
     * @param int $courseId
1955
     * @param int Session id (optional, default=0)
1956
     * @param bool $convert_date
1957
     *
1958
     * @return string|bool Date with format long without day or false if there is no date
1959
     */
1960
    public static function get_first_connection_date_on_the_course(
1961
        $student_id,
1962
        $courseId,
1963
        $session_id = 0,
1964
        $convert_date = true
1965
    ) {
1966
        $student_id = (int) $student_id;
1967
        $courseId = (int) $courseId;
1968
        $session_id = (int) $session_id;
1969
1970
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1971
        $sql = 'SELECT login_course_date
1972
                FROM '.$table.'
1973
                WHERE
1974
                    user_id = '.$student_id.' AND
1975
                    c_id = '.$courseId.' AND
1976
                    session_id = '.$session_id.'
1977
                ORDER BY login_course_date ASC
1978
                LIMIT 0,1';
1979
        $rs = Database::query($sql);
1980
        if (Database::num_rows($rs) > 0) {
1981
            if ($first_login_date = Database::result($rs, 0, 0)) {
1982
                if (empty($first_login_date)) {
1983
                    return false;
1984
                }
1985
1986
                if ($convert_date) {
1987
                    return api_convert_and_format_date(
1988
                        $first_login_date,
1989
                        DATE_FORMAT_SHORT
1990
                    );
1991
                }
1992
1993
                return $first_login_date;
1994
            }
1995
        }
1996
1997
        return false;
1998
    }
1999
2000
    /**
2001
     * Get last user's connection date on the course.
2002
     *
2003
     * @param     int         User id
2004
     * @param array $courseInfo real_id and code are used
2005
     * @param    int            Session id (optional, default=0)
2006
     * @param bool $convert_date
2007
     *
2008
     * @return string|bool Date with format long without day or false if there is no date
2009
     */
2010
    public static function get_last_connection_date_on_the_course(
2011
        $student_id,
2012
        $courseInfo,
2013
        $session_id = 0,
2014
        $convert_date = true
2015
    ) {
2016
        // protect data
2017
        $student_id = (int) $student_id;
2018
        $session_id = (int) $session_id;
2019
2020
        if (empty($courseInfo) || empty($student_id)) {
2021
            return false;
2022
        }
2023
2024
        $courseId = $courseInfo['real_id'];
2025
2026
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2027
2028
        if (self::minimumTimeAvailable($session_id, $courseId)) {
2029
            // Show the last date on which the user acceed the session when it was active
2030
            $where_condition = '';
2031
            $userInfo = api_get_user_info($student_id);
2032
            if (STUDENT == $userInfo['status'] && !empty($session_id)) {
2033
                // fin de acceso a la sesión
2034
                $sessionInfo = SessionManager::fetch($session_id);
2035
                $last_access = $sessionInfo['access_end_date'];
2036
                if (!empty($last_access)) {
2037
                    $where_condition = ' AND logout_course_date < "'.$last_access.'" ';
2038
                }
2039
            }
2040
            $sql = "SELECT logout_course_date
2041
                    FROM $table
2042
                    WHERE   user_id = $student_id AND
2043
                            c_id = $courseId AND
2044
                            session_id = $session_id $where_condition
2045
                    ORDER BY logout_course_date DESC
2046
                    LIMIT 0,1";
2047
2048
            $rs = Database::query($sql);
2049
            if (Database::num_rows($rs) > 0) {
2050
                if ($last_login_date = Database::result($rs, 0, 0)) {
2051
                    if (empty($last_login_date)) {
2052
                        return false;
2053
                    }
2054
                    if ($convert_date) {
2055
                        return api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
2056
                    }
2057
2058
                    return $last_login_date;
2059
                }
2060
            }
2061
        } else {
2062
            $sql = "SELECT logout_course_date
2063
                    FROM $table
2064
                    WHERE   user_id = $student_id AND
2065
                            c_id = $courseId AND
2066
                            session_id = $session_id
2067
                    ORDER BY logout_course_date DESC
2068
                    LIMIT 0,1";
2069
2070
            $rs = Database::query($sql);
2071
            if (Database::num_rows($rs) > 0) {
2072
                if ($last_login_date = Database::result($rs, 0, 0)) {
2073
                    if (empty($last_login_date)) {
2074
                        return false;
2075
                    }
2076
                    //see #5736
2077
                    $last_login_date_timestamp = api_strtotime($last_login_date);
2078
                    $now = time();
2079
                    //If the last connection is > than 7 days, the text is red
2080
                    //345600 = 7 days in seconds
2081
                    if ($now - $last_login_date_timestamp > 604800) {
2082
                        if ($convert_date) {
2083
                            $last_login_date = api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
2084
                            $icon = null;
2085
                            if (api_is_allowed_to_edit()) {
2086
                                $url = api_get_path(WEB_CODE_PATH).
2087
                                    'announcements/announcements.php?action=add&remind_inactive='.$student_id.'&cidReq='.$courseInfo['code'];
2088
                                $icon = '<a href="'.$url.'" title="'.get_lang('Remind inactive user').'">
2089
                                  '.Display::return_icon('messagebox_warning.gif').'
2090
                                 </a>';
2091
                            }
2092
2093
                            return $icon.Display::label($last_login_date, 'warning');
2094
                        }
2095
2096
                        return $last_login_date;
2097
                    } else {
2098
                        if ($convert_date) {
2099
                            return api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
2100
                        }
2101
2102
                        return $last_login_date;
2103
                    }
2104
                }
2105
            }
2106
        }
2107
2108
        return false;
2109
    }
2110
2111
    /**
2112
     * Get last course access by course/session.
2113
     */
2114
    public static function getLastConnectionDateByCourse($courseId, $sessionId = 0)
2115
    {
2116
        $courseId = (int) $courseId;
2117
        $sessionId = (int) $sessionId;
2118
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2119
2120
        $sql = "SELECT logout_course_date
2121
                FROM $table
2122
                WHERE
2123
                        c_id = $courseId AND
2124
                        session_id = $sessionId
2125
                ORDER BY logout_course_date DESC
2126
                LIMIT 0,1";
2127
2128
        $result = Database::query($sql);
2129
        if (Database::num_rows($result)) {
2130
            $row = Database::fetch_array($result);
2131
            if ($row) {
2132
                return $row['logout_course_date'];
2133
            }
2134
        }
2135
2136
        return '';
2137
    }
2138
2139
    /**
2140
     * Get count of the connections to the course during a specified period.
2141
     *
2142
     * @param int $courseId
2143
     * @param   int     Session id (optional)
2144
     * @param   int     Datetime from which to collect data (defaults to 0)
2145
     * @param   int     Datetime to which to collect data (defaults to now)
2146
     *
2147
     * @return int count connections
2148
     */
2149
    public static function get_course_connections_count(
2150
        $courseId,
2151
        $session_id = 0,
2152
        $start = 0,
2153
        $stop = null
2154
    ) {
2155
        if ($start < 0) {
2156
            $start = 0;
2157
        }
2158
        if (!isset($stop) || $stop < 0) {
2159
            $stop = api_get_utc_datetime();
2160
        }
2161
2162
        // Given we're storing in cache, round the start and end times
2163
        // to the lower minute
2164
        $roundedStart = substr($start, 0, -2).'00';
2165
        $roundedStop = substr($stop, 0, -2).'00';
2166
        $roundedStart = Database::escape_string($roundedStart);
2167
        $roundedStop = Database::escape_string($roundedStop);
2168
        $month_filter = " AND login_course_date > '$roundedStart' AND login_course_date < '$roundedStop' ";
2169
        $courseId = (int) $courseId;
2170
        $session_id = (int) $session_id;
2171
        $count = 0;
2172
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2173
        $sql = "SELECT count(*) as count_connections
2174
                FROM $table
2175
                WHERE
2176
                    c_id = $courseId AND
2177
                    session_id = $session_id
2178
                    $month_filter";
2179
2180
        //This query can be very slow (several seconds on an indexed table
2181
        // with 14M rows). As such, we'll try to use APCu if it is
2182
        // available to store the resulting value for a few seconds
2183
        $cacheAvailable = api_get_configuration_value('apc');
2184
        if (true === $cacheAvailable) {
2185
            $apc = apcu_cache_info(true);
2186
            $apc_end = $apc['start_time'] + $apc['ttl'];
2187
            $apc_var = api_get_configuration_value('apc_prefix').'course_access_'.$courseId.'_'.$session_id.'_'.strtotime($roundedStart).'_'.strtotime($roundedStop);
2188
            if (apcu_exists($apc_var) && (time() < $apc_end) &&
2189
                apcu_fetch($apc_var) > 0
2190
            ) {
2191
                $count = apcu_fetch($apc_var);
2192
            } else {
2193
                $rs = Database::query($sql);
2194
                if (Database::num_rows($rs) > 0) {
2195
                    $row = Database::fetch_object($rs);
2196
                    $count = $row->count_connections;
2197
                }
2198
                apcu_clear_cache();
2199
                apcu_store($apc_var, $count, 60);
2200
            }
2201
        } else {
2202
            $rs = Database::query($sql);
2203
            if (Database::num_rows($rs) > 0) {
2204
                $row = Database::fetch_object($rs);
2205
                $count = $row->count_connections;
2206
            }
2207
        }
2208
2209
        return $count;
2210
    }
2211
2212
    /**
2213
     * Get count courses per student.
2214
     *
2215
     * @param int  $user_id          Student id
2216
     * @param bool $include_sessions Include sessions (optional)
2217
     *
2218
     * @return int count courses
2219
     */
2220
    public static function count_course_per_student($user_id, $include_sessions = true)
2221
    {
2222
        $user_id = (int) $user_id;
2223
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2224
        $tbl_session_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2225
2226
        $sql = 'SELECT DISTINCT c_id
2227
                FROM '.$tbl_course_rel_user.'
2228
                WHERE user_id = '.$user_id.' AND relation_type<>'.COURSE_RELATION_TYPE_RRHH;
2229
        $rs = Database::query($sql);
2230
        $nb_courses = Database::num_rows($rs);
2231
2232
        if ($include_sessions) {
2233
            $sql = 'SELECT DISTINCT c_id
2234
                    FROM '.$tbl_session_course_rel_user.'
2235
                    WHERE user_id = '.$user_id;
2236
            $rs = Database::query($sql);
2237
            $nb_courses += Database::num_rows($rs);
2238
        }
2239
2240
        return $nb_courses;
2241
    }
2242
2243
    /**
2244
     * Gets the score average from all tests in a course by student.
2245
     *
2246
     * @param $student_id
2247
     * @param $course_code
2248
     * @param int  $exercise_id
2249
     * @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...
2250
     * @param int  $active_filter 2 for consider all tests
2251
     *                            1 for active <> -1
2252
     *                            0 for active <> 0
2253
     * @param int  $into_lp       1 for all exercises
2254
     *                            0 for without LP
2255
     * @param mixed id
2256
     * @param string code
2257
     * @param int id (optional), filtered by exercise
2258
     * @param int id (optional), if param $session_id is null
2259
     *                                                it'll return results including sessions, 0 = session is not filtered
2260
     *
2261
     * @return string value (number %) Which represents a round integer about the score average
2262
     */
2263
    public static function get_avg_student_exercise_score(
2264
        $student_id,
2265
        $course_code,
2266
        $exercise_id = 0,
2267
        $session_id = null,
2268
        $active_filter = 1,
2269
        $into_lp = 0
2270
    ) {
2271
        $course_code = Database::escape_string($course_code);
2272
        $course_info = api_get_course_info($course_code);
2273
        if (!empty($course_info)) {
2274
            // table definition
2275
            $tbl_course_quiz = Database::get_course_table(TABLE_QUIZ_TEST);
2276
            $tbl_stats_exercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2277
2278
            // Compose a filter based on optional exercise given
2279
            $condition_quiz = '';
2280
            if (!empty($exercise_id)) {
2281
                $exercise_id = (int) $exercise_id;
2282
                $condition_quiz = " AND iid = $exercise_id ";
2283
            }
2284
2285
            // Compose a filter based on optional session id given
2286
            $condition_session = '';
2287
            if (isset($session_id)) {
2288
                $session_id = (int) $session_id;
2289
                $condition_session = " AND session_id = $session_id ";
2290
            }
2291
            if (1 == $active_filter) {
2292
                $condition_active = 'AND active <> -1';
2293
            } elseif (0 == $active_filter) {
2294
                $condition_active = 'AND active <> 0';
2295
            } else {
2296
                $condition_active = '';
2297
            }
2298
            $condition_into_lp = '';
2299
            $select_lp_id = '';
2300
            if (0 == $into_lp) {
2301
                $condition_into_lp = 'AND orig_lp_id = 0 AND orig_lp_item_id = 0';
2302
            } else {
2303
                $select_lp_id = ', orig_lp_id as lp_id ';
2304
            }
2305
2306
            $sql = "SELECT count(iid)
2307
    		        FROM $tbl_course_quiz
2308
    				WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz ";
2309
            $count_quiz = 0;
2310
2311
            $countQuizResult = Database::query($sql);
2312
            if (!empty($countQuizResult)) {
2313
                $count_quiz = Database::fetch_row($countQuizResult);
2314
            }
2315
2316
            if (!empty($count_quiz[0]) && !empty($student_id)) {
2317
                if (is_array($student_id)) {
2318
                    $student_id = array_map('intval', $student_id);
2319
                    $condition_user = " AND exe_user_id IN (".implode(',', $student_id).") ";
2320
                } else {
2321
                    $student_id = (int) $student_id;
2322
                    $condition_user = " AND exe_user_id = '$student_id' ";
2323
                }
2324
2325
                if (empty($exercise_id)) {
2326
                    $sql = "SELECT iid FROM $tbl_course_quiz
2327
                            WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz";
2328
                    $result = Database::query($sql);
2329
                    $exercise_list = [];
2330
                    $exercise_id = null;
2331
                    if (!empty($result) && Database::num_rows($result)) {
2332
                        while ($row = Database::fetch_array($result)) {
2333
                            $exercise_list[] = $row['iid'];
2334
                        }
2335
                    }
2336
                    if (!empty($exercise_list)) {
2337
                        $exercise_id = implode("','", $exercise_list);
2338
                    }
2339
                }
2340
2341
                $count_quiz = Database::fetch_row(Database::query($sql));
2342
                $sql = "SELECT
2343
                        SUM(score/max_score*100) as avg_score,
2344
                        COUNT(*) as num_attempts
2345
                        $select_lp_id
2346
                        FROM $tbl_stats_exercise
2347
                        WHERE
2348
                            exe_exo_id IN ('".$exercise_id."')
2349
                            $condition_user AND
2350
                            status = '' AND
2351
                            c_id = {$course_info['real_id']}
2352
                            $condition_session
2353
                            $condition_into_lp
2354
                        ORDER BY exe_date DESC";
2355
2356
                $res = Database::query($sql);
2357
                $row = Database::fetch_array($res);
2358
                $quiz_avg_score = null;
2359
2360
                if (!empty($row['avg_score'])) {
2361
                    $quiz_avg_score = round($row['avg_score'], 2);
2362
                }
2363
2364
                if (!empty($row['num_attempts'])) {
2365
                    $quiz_avg_score = round($quiz_avg_score / $row['num_attempts'], 2);
2366
                }
2367
                if (is_array($student_id)) {
2368
                    $quiz_avg_score = round($quiz_avg_score / count($student_id), 2);
2369
                }
2370
                if (0 == $into_lp) {
2371
                    return $quiz_avg_score;
2372
                } else {
2373
                    if (!empty($row['lp_id'])) {
2374
                        $tbl_lp = Database::get_course_table(TABLE_LP_MAIN);
2375
                        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2376
                        $sql = "SELECT lp.name
2377
                                FROM $tbl_lp as lp, $tbl_course as c
2378
                                WHERE
2379
                                    c.code = '$course_code' AND
2380
                                    lp.iid = ".$row['lp_id']." AND
2381
                                    lp.c_id = c.id
2382
                                LIMIT 1;
2383
                        ";
2384
                        $result = Database::query($sql);
2385
                        $row_lp = Database::fetch_row($result);
2386
                        $lp_name = $row_lp[0];
2387
2388
                        return [$quiz_avg_score, $lp_name];
2389
                    }
2390
2391
                    return [$quiz_avg_score, null];
2392
                }
2393
            }
2394
        }
2395
2396
        return null;
2397
    }
2398
2399
    /**
2400
     * Get count student's exercise COMPLETED attempts.
2401
     *
2402
     * @param int $student_id
2403
     * @param int $courseId
2404
     * @param int $exercise_id
2405
     * @param int $lp_id
2406
     * @param int $lp_item_id
2407
     * @param int $session_id
2408
     * @param int $find_all_lp 0 = just LP specified
2409
     *                         1 = LP specified or whitout LP,
2410
     *                         2 = all rows
2411
     *
2412
     * @internal param \Student $int id
2413
     * @internal param \Course $string code
2414
     * @internal param \Exercise $int id
2415
     * @internal param \Learning $int path id (optional),
2416
     * for showing attempts inside a learning path $lp_id and $lp_item_id params are required
2417
     * @internal param \Learning $int path item id (optional),
2418
     * for showing attempts inside a learning path $lp_id and $lp_item_id params are required
2419
     *
2420
     * @return int count of attempts
2421
     */
2422
    public static function count_student_exercise_attempts(
2423
        $student_id,
2424
        $courseId,
2425
        $exercise_id,
2426
        $lp_id = 0,
2427
        $lp_item_id = 0,
2428
        $session_id = 0,
2429
        $find_all_lp = 0
2430
    ) {
2431
        $courseId = intval($courseId);
2432
        $student_id = intval($student_id);
2433
        $exercise_id = intval($exercise_id);
2434
        $session_id = intval($session_id);
2435
2436
        $lp_id = intval($lp_id);
2437
        $lp_item_id = intval($lp_item_id);
2438
        $tbl_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2439
2440
        $sql = "SELECT COUNT(ex.exe_id) as essais
2441
                FROM $tbl_stats_exercises AS ex
2442
                WHERE
2443
                    ex.c_id = $courseId AND
2444
                    ex.exe_exo_id = $exercise_id AND
2445
                    status = '' AND
2446
                    exe_user_id= $student_id AND
2447
                    session_id = $session_id ";
2448
2449
        if (1 == $find_all_lp) {
2450
            $sql .= "AND (orig_lp_id = $lp_id OR orig_lp_id = 0)
2451
                AND (orig_lp_item_id = $lp_item_id OR orig_lp_item_id = 0)";
2452
        } elseif (0 == $find_all_lp) {
2453
            $sql .= "AND orig_lp_id = $lp_id
2454
                AND orig_lp_item_id = $lp_item_id";
2455
        }
2456
2457
        $rs = Database::query($sql);
2458
        $row = Database::fetch_row($rs);
2459
        $count_attempts = $row[0];
2460
2461
        return $count_attempts;
2462
    }
2463
2464
    /**
2465
     * Get count student's exercise progress.
2466
     *
2467
     * @param array $exercise_list
2468
     * @param int   $user_id
2469
     * @param int   $courseId
2470
     * @param int   $session_id
2471
     *
2472
     * @return string
2473
     */
2474
    public static function get_exercise_student_progress(
2475
        $exercise_list,
2476
        $user_id,
2477
        $courseId,
2478
        $session_id
2479
    ) {
2480
        $courseId = (int) $courseId;
2481
        $user_id = (int) $user_id;
2482
        $session_id = (int) $session_id;
2483
2484
        if (empty($exercise_list)) {
2485
            return '0%';
2486
        }
2487
        $tbl_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2488
        $exercise_list = array_keys($exercise_list);
2489
        $exercise_list = array_map('intval', $exercise_list);
2490
2491
        $exercise_list_imploded = implode("' ,'", $exercise_list);
2492
2493
        $sql = "SELECT COUNT(DISTINCT ex.exe_exo_id)
2494
                FROM $tbl_stats_exercises AS ex
2495
                WHERE
2496
                    ex.c_id = $courseId AND
2497
                    ex.session_id  = $session_id AND
2498
                    ex.exe_user_id = $user_id AND
2499
                    ex.status = '' AND
2500
                    ex.exe_exo_id IN ('$exercise_list_imploded') ";
2501
2502
        $rs = Database::query($sql);
2503
        $count = 0;
2504
        if ($rs) {
2505
            $row = Database::fetch_row($rs);
2506
            $count = $row[0];
2507
        }
2508
        $count = (0 != $count) ? 100 * round(intval($count) / count($exercise_list), 2).'%' : '0%';
2509
2510
        return $count;
2511
    }
2512
2513
    /**
2514
     * @param array $exercise_list
2515
     * @param int   $user_id
2516
     * @param int   $courseId
2517
     * @param int   $session_id
2518
     *
2519
     * @return string
2520
     */
2521
    public static function get_exercise_student_average_best_attempt(
2522
        $exercise_list,
2523
        $user_id,
2524
        $courseId,
2525
        $session_id
2526
    ) {
2527
        $result = 0;
2528
        if (!empty($exercise_list)) {
2529
            foreach ($exercise_list as $exercise_data) {
2530
                $exercise_id = $exercise_data['id'];
2531
                $best_attempt = Event::get_best_attempt_exercise_results_per_user(
2532
                    $user_id,
2533
                    $exercise_id,
2534
                    $courseId,
2535
                    $session_id
2536
                );
2537
2538
                if (!empty($best_attempt) && !empty($best_attempt['max_score'])) {
2539
                    $result += $best_attempt['score'] / $best_attempt['max_score'];
2540
                }
2541
            }
2542
            $result = $result / count($exercise_list);
2543
            $result = round($result, 2) * 100;
2544
        }
2545
2546
        return $result.'%';
2547
    }
2548
2549
    /**
2550
     * Returns the average student progress in the learning paths of the given
2551
     * course, it will take into account the progress that were not started.
2552
     *
2553
     * @param int|array $studentId
2554
     * @param string    $courseCode
2555
     * @param array     $lpIdList        Limit average to listed lp ids
2556
     * @param int       $sessionId       Session id (optional),
2557
     *                                   if parameter $session_id is null(default) it'll return results including
2558
     *                                   sessions, 0 = session is not filtered
2559
     * @param bool      $returnArray     Will return an array of the type:
2560
     *                                   [sum_of_progresses, number] if it is set to true
2561
     * @param bool      $onlySeriousGame Optional. Limit average to lp on seriousgame mode
2562
     *
2563
     * @return float Average progress of the user in this course from 0 to 100
2564
     */
2565
    public static function get_avg_student_progress(
2566
        $studentId,
2567
        $courseCode = null,
2568
        $lpIdList = [],
2569
        $sessionId = null,
2570
        $returnArray = false,
2571
        $onlySeriousGame = false
2572
    ) {
2573
        // If there is at least one learning path and one student.
2574
        if (empty($studentId)) {
2575
            return false;
2576
        }
2577
2578
        $sessionId = (int) $sessionId;
2579
        $courseInfo = api_get_course_info($courseCode);
2580
2581
        if (empty($courseInfo)) {
2582
            return false;
2583
        }
2584
2585
        $lPTable = Database::get_course_table(TABLE_LP_MAIN);
2586
        $lpViewTable = Database::get_course_table(TABLE_LP_VIEW);
2587
        $lpConditions = [];
2588
        $lpConditions['c_id = ? '] = $courseInfo['real_id'];
2589
2590
        if ($sessionId > 0) {
2591
            $lpConditions['AND (session_id = ? OR session_id = 0 OR session_id IS NULL)'] = $sessionId;
2592
        } else {
2593
            $lpConditions['AND session_id = ?'] = $sessionId;
2594
        }
2595
2596
        if (is_array($lpIdList) && count($lpIdList) > 0) {
2597
            $placeHolders = [];
2598
            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...
2599
                $placeHolders[] = '?';
2600
            }
2601
            $lpConditions['AND iid IN('.implode(', ', $placeHolders).') '] = $lpIdList;
2602
        }
2603
2604
        if ($onlySeriousGame) {
2605
            $lpConditions['AND seriousgame_mode = ? '] = true;
2606
        }
2607
2608
        $resultLP = Database::select(
2609
            'iid',
2610
            $lPTable,
2611
            ['where' => $lpConditions]
2612
        );
2613
        $filteredLP = array_keys($resultLP);
2614
2615
        if (empty($filteredLP)) {
2616
            return false;
2617
        }
2618
2619
        $conditions = [
2620
            " c_id = {$courseInfo['real_id']} ",
2621
            " lp_view.lp_id IN (".implode(', ', $filteredLP).") ",
2622
        ];
2623
2624
        $groupBy = 'GROUP BY lp_id';
2625
2626
        if (is_array($studentId)) {
2627
            $studentId = array_map('intval', $studentId);
2628
            $conditions[] = " lp_view.user_id IN (".implode(',', $studentId).")  ";
2629
        } else {
2630
            $studentId = (int) $studentId;
2631
            $conditions[] = " lp_view.user_id = '$studentId' ";
2632
2633
            if (empty($lpIdList)) {
2634
                $lpList = new LearnpathList(
2635
                    $studentId,
2636
                    $courseInfo,
2637
                    $sessionId,
2638
                    null,
2639
                    false,
2640
                    null,
2641
                    true
2642
                );
2643
                $lpList = $lpList->get_flat_list();
2644
                if (!empty($lpList)) {
2645
                    /** @var $lp */
2646
                    foreach ($lpList as $lpId => $lp) {
2647
                        $lpIdList[] = $lp['lp_old_id'];
2648
                    }
2649
                }
2650
            }
2651
        }
2652
2653
        if (!empty($sessionId)) {
2654
            $conditions[] = " session_id = $sessionId ";
2655
        } else {
2656
            $conditions[] = ' (session_id = 0 OR session_id IS NULL) ';
2657
        }
2658
2659
        $conditionToString = implode('AND', $conditions);
2660
        $sql = "SELECT lp_id, view_count, progress
2661
                FROM $lpViewTable lp_view
2662
                WHERE
2663
                    $conditionToString
2664
                    $groupBy
2665
                ORDER BY view_count DESC";
2666
2667
        $result = Database::query($sql);
2668
2669
        $progress = [];
2670
        $viewCount = [];
2671
        while ($row = Database::fetch_array($result, 'ASSOC')) {
2672
            if (!isset($viewCount[$row['lp_id']])) {
2673
                $progress[$row['lp_id']] = $row['progress'];
2674
            }
2675
            $viewCount[$row['lp_id']] = $row['view_count'];
2676
        }
2677
2678
        // Fill with lp ids
2679
        $newProgress = [];
2680
        if (!empty($lpIdList)) {
2681
            foreach ($lpIdList as $lpId) {
2682
                if (isset($progress[$lpId])) {
2683
                    $newProgress[] = $progress[$lpId];
2684
                }
2685
            }
2686
            $total = count($lpIdList);
2687
        } else {
2688
            $newProgress = $progress;
2689
            $total = count($newProgress);
2690
        }
2691
2692
        $average = 0;
2693
        $sum = 0;
2694
        if (!empty($newProgress)) {
2695
            $sum = array_sum($newProgress);
2696
            $average = $sum / $total;
2697
        }
2698
2699
        if ($returnArray) {
2700
            return [
2701
                $sum,
2702
                $total,
2703
            ];
2704
        }
2705
2706
        return round($average, 1);
2707
    }
2708
2709
    /**
2710
     * This function gets:
2711
     * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores.
2712
     * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores.
2713
     * 3. And finally it will return the average between 1. and 2.
2714
     *
2715
     * @todo improve performance, when loading 1500 users with 20 lps the script dies
2716
     * This function does not take the results of a Test out of a LP
2717
     *
2718
     * @param mixed  $student_id                      Array of user ids or an user id
2719
     * @param string $course_code
2720
     * @param array  $lp_ids                          List of LP ids
2721
     * @param int    $session_id                      Session id (optional),
2722
     *                                                if param $session_id is null(default) it'll return results
2723
     *                                                including sessions, 0 = session is not filtered
2724
     * @param bool   $return_array                    Returns an array of the
2725
     *                                                type [sum_score, num_score] if set to true
2726
     * @param bool   $get_only_latest_attempt_results get only the latest attempts or ALL attempts
2727
     * @param bool   $getOnlyBestAttempt
2728
     *
2729
     * @return string value (number %) Which represents a round integer explain in got in 3
2730
     */
2731
    public static function get_avg_student_score(
2732
        $student_id,
2733
        $course_code,
2734
        $lp_ids = [],
2735
        $session_id = null,
2736
        $return_array = false,
2737
        $get_only_latest_attempt_results = false,
2738
        $getOnlyBestAttempt = false
2739
    ) {
2740
        $debug = false;
2741
        if ($debug) {
2742
            echo '<h1>Tracking::get_avg_student_score</h1>';
2743
        }
2744
        $tbl_stats_exercices = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2745
        $tbl_stats_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
2746
        $course = api_get_course_info($course_code);
2747
2748
        if (empty($course)) {
2749
            return null;
2750
        }
2751
2752
        // Get course tables names
2753
        $tbl_quiz_questions = Database::get_course_table(TABLE_QUIZ_QUESTION);
2754
        $lp_table = Database::get_course_table(TABLE_LP_MAIN);
2755
        $lp_item_table = Database::get_course_table(TABLE_LP_ITEM);
2756
        $lp_view_table = Database::get_course_table(TABLE_LP_VIEW);
2757
        $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW);
2758
        $course_id = $course['real_id'];
2759
2760
        // Compose a filter based on optional learning paths list given
2761
        $condition_lp = '';
2762
        if (count($lp_ids) > 0) {
2763
            $condition_lp = " AND iid IN(".implode(',', $lp_ids).") ";
2764
        }
2765
2766
        // Compose a filter based on optional session id
2767
        $session_id = (int) $session_id;
2768
        if (count($lp_ids) > 0) {
2769
            $condition_session = " AND session_id = $session_id ";
2770
        } else {
2771
            $condition_session = " WHERE session_id = $session_id ";
2772
        }
2773
2774
        // Check the real number of LPs corresponding to the filter in the
2775
        // database (and if no list was given, get them all)
2776
        if (empty($session_id)) {
2777
            $sql = "SELECT DISTINCT(iid), use_max_score
2778
                    FROM $lp_table
2779
                    WHERE
2780
                        c_id = $course_id AND
2781
                        (session_id = 0 OR session_id IS NULL) $condition_lp ";
2782
        } else {
2783
            $sql = "SELECT DISTINCT(iid), use_max_score
2784
                    FROM $lp_table
2785
                    WHERE c_id = $course_id $condition_lp ";
2786
        }
2787
2788
        $res_row_lp = Database::query($sql);
2789
        $count_row_lp = Database::num_rows($res_row_lp);
2790
2791
        $lp_list = $use_max_score = [];
2792
        while ($row_lp = Database::fetch_array($res_row_lp)) {
2793
            $lp_list[] = $row_lp['iid'];
2794
            $use_max_score[$row_lp['iid']] = $row_lp['use_max_score'];
2795
        }
2796
2797
        // prepare filter on users
2798
        if (is_array($student_id)) {
2799
            array_walk($student_id, 'intval');
2800
            $condition_user1 = " AND user_id IN (".implode(',', $student_id).") ";
2801
        } else {
2802
            $condition_user1 = " AND user_id = $student_id ";
2803
        }
2804
2805
        if (empty($count_row_lp) || empty($student_id)) {
2806
            return null;
2807
        }
2808
2809
        // Getting latest LP result for a student
2810
        //@todo problem when a  course have more than 1500 users
2811
        $sql = "SELECT MAX(view_count) as vc, iid, progress, lp_id, user_id
2812
                FROM $lp_view_table
2813
                WHERE
2814
                    c_id = $course_id AND
2815
                    lp_id IN (".implode(',', $lp_list).")
2816
                    $condition_user1 AND
2817
                    session_id = $session_id
2818
                GROUP BY lp_id, user_id";
2819
2820
        $rs_last_lp_view_id = Database::query($sql);
2821
        $global_result = 0;
2822
2823
        if (Database::num_rows($rs_last_lp_view_id) > 0) {
2824
            // Cycle through each line of the results (grouped by lp_id, user_id)
2825
            while ($row_lp_view = Database::fetch_array($rs_last_lp_view_id)) {
2826
                $count_items = 0;
2827
                $lpPartialTotal = 0;
2828
                $list = [];
2829
                $lp_view_id = $row_lp_view['iid'];
2830
                $lp_id = $row_lp_view['lp_id'];
2831
                $user_id = $row_lp_view['user_id'];
2832
2833
                if ($debug) {
2834
                    echo '<h2>LP id '.$lp_id.'</h2>';
2835
                    echo "get_only_latest_attempt_results: $get_only_latest_attempt_results <br />";
2836
                    echo "getOnlyBestAttempt: $getOnlyBestAttempt <br />";
2837
                }
2838
2839
                if ($get_only_latest_attempt_results || $getOnlyBestAttempt) {
2840
                    // Getting lp_items done by the user
2841
                    $sql = "SELECT DISTINCT lp_item_id
2842
                            FROM $lp_item_view_table
2843
                            WHERE
2844
                                c_id = $course_id AND
2845
                                lp_view_id = $lp_view_id
2846
                            ORDER BY lp_item_id";
2847
                    $res_lp_item = Database::query($sql);
2848
2849
                    while ($row_lp_item = Database::fetch_array($res_lp_item, 'ASSOC')) {
2850
                        $my_lp_item_id = $row_lp_item['lp_item_id'];
2851
                        $order = ' view_count DESC';
2852
                        if ($getOnlyBestAttempt) {
2853
                            $order = ' lp_iv.score DESC';
2854
                        }
2855
2856
                        // Getting the most recent attempt
2857
                        $sql = "SELECT
2858
                                    lp_iv.id as lp_item_view_id,
2859
                                    lp_iv.score as score,
2860
                                    lp_i.max_score,
2861
                                    lp_iv.max_score as max_score_item_view,
2862
                                    lp_i.path,
2863
                                    lp_i.item_type,
2864
                                    lp_i.iid
2865
                                FROM $lp_item_view_table as lp_iv
2866
                                INNER JOIN $lp_item_table as lp_i
2867
                                ON (
2868
                                    lp_i.id = lp_iv.lp_item_id AND
2869
                                    lp_iv.c_id = lp_i.c_id
2870
                                )
2871
                                WHERE
2872
                                    lp_iv.c_id = $course_id AND
2873
                                    lp_i.c_id  = $course_id AND
2874
                                    lp_item_id = $my_lp_item_id AND
2875
                                    lp_view_id = $lp_view_id AND
2876
                                    (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."')
2877
                                ORDER BY $order
2878
                                LIMIT 1";
2879
2880
                        $res_lp_item_result = Database::query($sql);
2881
                        while ($row_max_score = Database::fetch_array($res_lp_item_result, 'ASSOC')) {
2882
                            $list[] = $row_max_score;
2883
                        }
2884
                    }
2885
                } else {
2886
                    // For the currently analysed view, get the score and
2887
                    // max_score of each item if it is a sco or a TOOL_QUIZ
2888
                    $sql = "SELECT
2889
                                lp_iv.id as lp_item_view_id,
2890
                                lp_iv.score as score,
2891
                                lp_i.max_score,
2892
                                lp_iv.max_score as max_score_item_view,
2893
                                lp_i.path,
2894
                                lp_i.item_type,
2895
                                lp_i.id as iid
2896
                              FROM $lp_item_view_table as lp_iv
2897
                              INNER JOIN $lp_item_table as lp_i
2898
                              ON lp_i.id = lp_iv.lp_item_id AND
2899
                                 lp_iv.c_id = lp_i.c_id
2900
                              WHERE
2901
                                lp_iv.c_id = $course_id AND
2902
                                lp_i.c_id  = $course_id AND
2903
                                lp_view_id = $lp_view_id AND
2904
                                (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."')
2905
                            ";
2906
                    $res_max_score = Database::query($sql);
2907
                    while ($row_max_score = Database::fetch_array($res_max_score, 'ASSOC')) {
2908
                        $list[] = $row_max_score;
2909
                    }
2910
                }
2911
2912
                // Go through each scorable element of this view
2913
                $score_of_scorm_calculate = 0;
2914
                foreach ($list as $row_max_score) {
2915
                    // Came from the original lp_item
2916
                    $max_score = $row_max_score['max_score'];
2917
                    // Came from the lp_item_view
2918
                    $max_score_item_view = $row_max_score['max_score_item_view'];
2919
                    $score = $row_max_score['score'];
2920
                    if ($debug) {
2921
                        echo '<h3>Item Type: '.$row_max_score['item_type'].'</h3>';
2922
                    }
2923
2924
                    if ('sco' == $row_max_score['item_type']) {
2925
                        /* Check if it is sco (easier to get max_score)
2926
                           when there's no max score, we assume 100 as the max score,
2927
                           as the SCORM 1.2 says that the value should always be between 0 and 100.
2928
                        */
2929
                        if (0 == $max_score || is_null($max_score) || '' == $max_score) {
2930
                            // Chamilo style
2931
                            if ($use_max_score[$lp_id]) {
2932
                                $max_score = 100;
2933
                            } else {
2934
                                // Overwrites max score = 100 to use the one that came in the lp_item_view see BT#1613
2935
                                $max_score = $max_score_item_view;
2936
                            }
2937
                        }
2938
                        // Avoid division by zero errors
2939
                        if (!empty($max_score)) {
2940
                            $lpPartialTotal += $score / $max_score;
2941
                        }
2942
                        if ($debug) {
2943
                            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...
2944
                            var_dump("score: $score");
2945
                            var_dump("max_score: $max_score");
2946
                        }
2947
                    } else {
2948
                        // Case of a TOOL_QUIZ element
2949
                        $item_id = $row_max_score['iid'];
2950
                        $item_path = $row_max_score['path'];
2951
                        $lp_item_view_id = (int) $row_max_score['lp_item_view_id'];
2952
2953
                        if (empty($lp_item_view_id)) {
2954
                            $lpItemCondition = ' (orig_lp_item_view_id = 0 OR orig_lp_item_view_id IS NULL) ';
2955
                        } else {
2956
                            $lpItemCondition = " orig_lp_item_view_id = $lp_item_view_id ";
2957
                        }
2958
2959
                        // Get last attempt to this exercise through
2960
                        // the current lp for the current user
2961
                        $order = 'exe_date DESC';
2962
                        if ($getOnlyBestAttempt) {
2963
                            $order = 'score DESC';
2964
                        }
2965
                        $sql = "SELECT exe_id, score
2966
                                FROM $tbl_stats_exercices
2967
                                WHERE
2968
                                    exe_exo_id = '$item_path' AND
2969
                                    exe_user_id = $user_id AND
2970
                                    orig_lp_item_id = $item_id AND
2971
                                    $lpItemCondition AND
2972
                                    c_id = $course_id AND
2973
                                    session_id = $session_id AND
2974
                                    status = ''
2975
                                ORDER BY $order
2976
                                LIMIT 1";
2977
2978
                        $result_last_attempt = Database::query($sql);
2979
                        $num = Database::num_rows($result_last_attempt);
2980
                        if ($num > 0) {
2981
                            $attemptResult = Database::fetch_array($result_last_attempt, 'ASSOC');
2982
                            $id_last_attempt = $attemptResult['exe_id'];
2983
                            // We overwrite the score with the best one not the one saved in the LP (latest)
2984
                            if ($getOnlyBestAttempt && false == $get_only_latest_attempt_results) {
2985
                                if ($debug) {
2986
                                    echo "Following score comes from the track_exercise table not in the LP because the score is the best<br />";
2987
                                }
2988
                                $score = $attemptResult['score'];
2989
                            }
2990
2991
                            if ($debug) {
2992
                                echo "Attempt id: $id_last_attempt with score $score<br />";
2993
                            }
2994
                            // Within the last attempt number tracking, get the sum of
2995
                            // the max_scores of all questions that it was
2996
                            // made of (we need to make this call dynamic because of random questions selection)
2997
                            $sql = "SELECT SUM(t.ponderation) as maxscore FROM
2998
                                            (
2999
                                                SELECT DISTINCT
3000
                                                    question_id,
3001
                                                    marks,
3002
                                                    ponderation
3003
                                                FROM $tbl_stats_attempts AS at
3004
                                                INNER JOIN $tbl_quiz_questions AS q
3005
                                                ON (q.id = at.question_id AND q.c_id = q.c_id)
3006
                                                WHERE
3007
                                                    exe_id ='$id_last_attempt' AND
3008
                                                    q.c_id = $course_id
3009
                                            )
3010
                                            AS t";
3011
3012
                            $res_max_score_bis = Database::query($sql);
3013
                            $row_max_score_bis = Database::fetch_array($res_max_score_bis);
3014
3015
                            if (!empty($row_max_score_bis['maxscore'])) {
3016
                                $max_score = $row_max_score_bis['maxscore'];
3017
                            }
3018
                            if (!empty($max_score) && floatval($max_score) > 0) {
3019
                                $lpPartialTotal += $score / $max_score;
3020
                            }
3021
                            if ($debug) {
3022
                                var_dump("score: $score");
3023
                                var_dump("max_score: $max_score");
3024
                                var_dump("lpPartialTotal: $lpPartialTotal");
3025
                            }
3026
                        }
3027
                    }
3028
3029
                    if (in_array($row_max_score['item_type'], ['quiz', 'sco'])) {
3030
                        // Normal way
3031
                        if ($use_max_score[$lp_id]) {
3032
                            $count_items++;
3033
                        } else {
3034
                            if ('' != $max_score) {
3035
                                $count_items++;
3036
                            }
3037
                        }
3038
                        if ($debug) {
3039
                            echo '$count_items: '.$count_items;
3040
                        }
3041
                    }
3042
                } //end for
3043
3044
                $score_of_scorm_calculate += $count_items ? (($lpPartialTotal / $count_items) * 100) : 0;
3045
                $global_result += $score_of_scorm_calculate;
3046
3047
                if ($debug) {
3048
                    var_dump("count_items: $count_items");
3049
                    var_dump("score_of_scorm_calculate: $score_of_scorm_calculate");
3050
                    var_dump("global_result: $global_result");
3051
                }
3052
            } // end while
3053
        }
3054
3055
        $lp_with_quiz = 0;
3056
        foreach ($lp_list as $lp_id) {
3057
            // Check if LP have a score we assume that all SCO have an score
3058
            $sql = "SELECT count(iid) as count
3059
                    FROM $lp_item_table
3060
                    WHERE
3061
                        c_id = $course_id AND
3062
                        (item_type = 'quiz' OR item_type = 'sco') AND
3063
                        lp_id = ".$lp_id;
3064
            $result_have_quiz = Database::query($sql);
3065
            if (Database::num_rows($result_have_quiz) > 0) {
3066
                $row = Database::fetch_array($result_have_quiz, 'ASSOC');
3067
                if (is_numeric($row['count']) && 0 != $row['count']) {
3068
                    $lp_with_quiz++;
3069
                }
3070
            }
3071
        }
3072
3073
        if ($debug) {
3074
            echo '<h3>$lp_with_quiz '.$lp_with_quiz.' </h3>';
3075
        }
3076
        if ($debug) {
3077
            echo '<h3>Final return</h3>';
3078
        }
3079
3080
        if (0 != $lp_with_quiz) {
3081
            if (!$return_array) {
3082
                $score_of_scorm_calculate = round(($global_result / $lp_with_quiz), 2);
3083
                if ($debug) {
3084
                    var_dump($score_of_scorm_calculate);
3085
                }
3086
                if (empty($lp_ids)) {
3087
                    if ($debug) {
3088
                        echo '<h2>All lps fix: '.$score_of_scorm_calculate.'</h2>';
3089
                    }
3090
                }
3091
3092
                return $score_of_scorm_calculate;
3093
            }
3094
3095
            if ($debug) {
3096
                var_dump($global_result, $lp_with_quiz);
3097
            }
3098
3099
            return [$global_result, $lp_with_quiz];
3100
        }
3101
3102
        return '-';
3103
    }
3104
3105
    /**
3106
     * This function gets:
3107
     * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores.
3108
     * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores.
3109
     * 3. And finally it will return the average between 1. and 2.
3110
     * This function does not take the results of a Test out of a LP.
3111
     *
3112
     * @param int|array $student_id  Array of user ids or an user id
3113
     * @param string    $course_code Course code
3114
     * @param array     $lp_ids      List of LP ids
3115
     * @param int       $session_id  Session id (optional), if param $session_id is 0(default)
3116
     *                               it'll return results including sessions, 0 = session is not filtered
3117
     *
3118
     * @return string value (number %) Which represents a round integer explain in got in 3
3119
     */
3120
    public static function getAverageStudentScore(
3121
        $student_id,
3122
        $course_code = '',
3123
        $lp_ids = [],
3124
        $session_id = 0
3125
    ) {
3126
        if (empty($student_id)) {
3127
            return 0;
3128
        }
3129
3130
        $conditions = [];
3131
        if (!empty($course_code)) {
3132
            $course = api_get_course_info($course_code);
3133
            $courseId = $course['real_id'];
3134
            $conditions[] = " lp.c_id = $courseId";
3135
        }
3136
3137
        // Get course tables names
3138
        $lp_table = Database::get_course_table(TABLE_LP_MAIN);
3139
        $lp_item_table = Database::get_course_table(TABLE_LP_ITEM);
3140
        $lp_view_table = Database::get_course_table(TABLE_LP_VIEW);
3141
        $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3142
3143
        // Compose a filter based on optional learning paths list given
3144
        if (!empty($lp_ids) && count($lp_ids) > 0) {
3145
            $conditions[] = ' lp.iid IN ('.implode(',', $lp_ids).') ';
3146
        }
3147
3148
        // Compose a filter based on optional session id
3149
        $session_id = (int) $session_id;
3150
        if (!empty($session_id)) {
3151
            $conditions[] = " lp_view.session_id = $session_id ";
3152
        }
3153
3154
        if (is_array($student_id)) {
3155
            array_walk($student_id, 'intval');
3156
            $conditions[] = " lp_view.user_id IN (".implode(',', $student_id).") ";
3157
        } else {
3158
            $student_id = (int) $student_id;
3159
            $conditions[] = " lp_view.user_id = $student_id ";
3160
        }
3161
3162
        $conditionsToString = implode(' AND ', $conditions);
3163
        $sql = "SELECT
3164
                    SUM(lp_iv.score) sum_score,
3165
                    SUM(lp_i.max_score) sum_max_score
3166
                FROM $lp_table as lp
3167
                INNER JOIN $lp_item_table as lp_i
3168
                ON lp.iid = lp_id AND lp.c_id = lp_i.c_id
3169
                INNER JOIN $lp_view_table as lp_view
3170
                ON lp_view.lp_id = lp_i.lp_id AND lp_view.c_id = lp_i.c_id
3171
                INNER JOIN $lp_item_view_table as lp_iv
3172
                ON
3173
                    lp_i.iid = lp_iv.lp_item_id AND
3174
                    lp_view.c_id = lp_iv.c_id AND
3175
                    lp_iv.lp_view_id = lp_view.iid
3176
                WHERE (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."') AND
3177
                $conditionsToString
3178
        ";
3179
        $result = Database::query($sql);
3180
        $row = Database::fetch_array($result, 'ASSOC');
3181
3182
        if (empty($row['sum_max_score'])) {
3183
            return 0;
3184
        }
3185
3186
        return ($row['sum_score'] / $row['sum_max_score']) * 100;
3187
    }
3188
3189
    /**
3190
     * This function gets time spent in learning path for a student inside a course.
3191
     *
3192
     * @param int|array $student_id  Student id(s)
3193
     * @param string    $course_code Course code
3194
     * @param array     $lp_ids      Limit average to listed lp ids
3195
     * @param int       $session_id  Session id (optional), if param $session_id is null(default)
3196
     *                               it'll return results including sessions, 0 = session is not filtered
3197
     *
3198
     * @return int Total time in seconds
3199
     */
3200
    public static function get_time_spent_in_lp(
3201
        $student_id,
3202
        $course_code,
3203
        $lp_ids = [],
3204
        $session_id = 0
3205
    ) {
3206
        $course = api_get_course_info($course_code);
3207
        $student_id = (int) $student_id;
3208
        $session_id = (int) $session_id;
3209
        $total_time = 0;
3210
3211
        if (!empty($course)) {
3212
            $lpTable = Database::get_course_table(TABLE_LP_MAIN);
3213
            $lpItemTable = Database::get_course_table(TABLE_LP_ITEM);
3214
            $lpViewTable = Database::get_course_table(TABLE_LP_VIEW);
3215
            $lpItemViewTable = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3216
            $trackExercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
3217
            $course_id = $course['real_id'];
3218
3219
            // Compose a filter based on optional learning paths list given
3220
            $condition_lp = '';
3221
            if (count($lp_ids) > 0) {
3222
                $condition_lp = " AND iid IN(".implode(',', $lp_ids).") ";
3223
            }
3224
3225
            // Check the real number of LPs corresponding to the filter in the
3226
            // database (and if no list was given, get them all)
3227
            $sql = "SELECT DISTINCT(iid) FROM $lpTable
3228
                    WHERE c_id = $course_id $condition_lp";
3229
            $result = Database::query($sql);
3230
            $session_condition = api_get_session_condition($session_id);
3231
3232
            // calculates time
3233
            if (Database::num_rows($result) > 0) {
3234
                while ($row = Database::fetch_array($result)) {
3235
                    $lp_id = (int) $row['iid'];
3236
3237
                    // Start Exercise in LP total_time
3238
                    // Get duration time from track_e_exercises.exe_duration instead of lp_view_item.total_time
3239
                    $list = learnpath::get_flat_ordered_items_list($lp_id, 0, $course_id);
3240
                    foreach ($list as $itemId) {
3241
                        $sql = "SELECT max(view_count)
3242
                                FROM $lpViewTable
3243
                                WHERE
3244
                                    c_id = $course_id AND
3245
                                    lp_id = $lp_id AND
3246
                                    user_id = $student_id
3247
                                    $session_condition";
3248
                        $res = Database::query($sql);
3249
                        $view = '';
3250
                        if (Database::num_rows($res) > 0) {
3251
                            $myrow = Database::fetch_array($res);
3252
                            $view = $myrow[0];
3253
                        }
3254
                        $viewCondition = null;
3255
                        if (!empty($view)) {
3256
                            $viewCondition = " AND v.view_count = $view  ";
3257
                        }
3258
                        $sql = "SELECT
3259
                            iv.iid,
3260
                            iv.total_time as mytime,
3261
                            i.iid as myid,
3262
                            iv.view_count as iv_view_count,
3263
                            path
3264
                        FROM $lpItemTable as i
3265
                        INNER JOIN $lpItemViewTable as iv
3266
                        ON (i.iid = iv.lp_item_id AND i.c_id = iv.c_id)
3267
                        INNER JOIN $lpViewTable as v
3268
                        ON (iv.lp_view_id = v.iid AND v.c_id = iv.c_id)
3269
                        WHERE
3270
                            v.c_id = $course_id AND
3271
                            i.id = $itemId AND
3272
                            i.lp_id = $lp_id  AND
3273
                            v.user_id = $student_id AND
3274
                            item_type = 'quiz' AND
3275
                            path <> '' AND
3276
                            v.session_id = $session_id
3277
                            $viewCondition
3278
                        ORDER BY iv.view_count DESC ";
3279
3280
                        $resultRow = Database::query($sql);
3281
                        if (Database::num_rows($resultRow)) {
3282
                            $row = Database::fetch_array($resultRow);
3283
                            $totalTimeInLpItemView = $row['mytime'];
3284
                            $lpItemViewId = $row['iid'];
3285
3286
                            $sql = 'SELECT SUM(exe_duration) exe_duration
3287
                                    FROM '.$trackExercises.'
3288
                                    WHERE
3289
                                        exe_exo_id="'.$row['path'].'" AND
3290
                                        exe_user_id="'.$student_id.'" AND
3291
                                        orig_lp_id = "'.$lp_id.'" AND
3292
                                        orig_lp_item_id = "'.$row['myid'].'" AND
3293
                                        c_id = '.$course_id.' AND
3294
                                        status <> "incomplete" AND
3295
                                        session_id = '.$session_id.'
3296
                                     ORDER BY exe_date DESC ';
3297
3298
                            $sumScoreResult = Database::query($sql);
3299
                            $durationRow = Database::fetch_array($sumScoreResult, 'ASSOC');
3300
                            if (!empty($durationRow['exe_duration'])) {
3301
                                $exeDuration = $durationRow['exe_duration'];
3302
                                if ($exeDuration != $totalTimeInLpItemView &&
3303
                                    !empty($lpItemViewId) &&
3304
                                    !empty($exeDuration)
3305
                                ) {
3306
                                    // Update c_lp_item_view.total_time
3307
                                    $sqlUpdate = "UPDATE $lpItemViewTable
3308
                                                  SET total_time = '$exeDuration'
3309
                                                  WHERE iid = ".$lpItemViewId;
3310
                                    Database::query($sqlUpdate);
3311
                                }
3312
                            }
3313
                        }
3314
                    }
3315
3316
                    // End total_time fix
3317
3318
                    // Calculate total time
3319
                    $sql = "SELECT SUM(total_time)
3320
                            FROM $lpItemViewTable AS item_view
3321
                            INNER JOIN $lpViewTable AS view
3322
                            ON (
3323
                                item_view.lp_view_id = view.iid AND
3324
                                item_view.c_id = view.c_id
3325
                            )
3326
                            WHERE
3327
                                item_view.c_id = $course_id AND
3328
                                view.c_id = $course_id AND
3329
                                view.lp_id = $lp_id AND
3330
                                view.user_id = $student_id AND
3331
                                session_id = $session_id";
3332
3333
                    $rs = Database::query($sql);
3334
                    if (Database::num_rows($rs) > 0) {
3335
                        $total_time += Database::result($rs, 0, 0);
3336
                    }
3337
                }
3338
            }
3339
        }
3340
3341
        return $total_time;
3342
    }
3343
3344
    /**
3345
     * This function gets last connection time to one learning path.
3346
     *
3347
     * @param int|array $student_id  Student id(s)
3348
     * @param string    $course_code Course code
3349
     * @param int       $lp_id       Learning path id
3350
     * @param int       $session_id
3351
     *
3352
     * @return int last connection timestamp
3353
     */
3354
    public static function get_last_connection_time_in_lp(
3355
        $student_id,
3356
        $course_code,
3357
        $lp_id,
3358
        $session_id = 0
3359
    ) {
3360
        $course = api_get_course_info($course_code);
3361
        if (empty($course)) {
3362
            return 0;
3363
        }
3364
3365
        $course_id = $course['real_id'];
3366
        $student_id = (int) $student_id;
3367
        $lp_id = (int) $lp_id;
3368
        $session_id = (int) $session_id;
3369
        $lastTime = 0;
3370
3371
        if (self::minimumTimeAvailable($session_id, $course_id)) {
3372
            $sql = "SELECT MAX(date_reg) max
3373
                    FROM track_e_access_complete
3374
                    WHERE
3375
                        user_id = $student_id AND
3376
                        c_id = $course_id AND
3377
                        session_id = $session_id AND
3378
                        tool = 'learnpath' AND
3379
                        tool_id = $lp_id AND
3380
                        action = 'view' AND
3381
                        login_as = 0
3382
                    ORDER BY date_reg ASC
3383
                    LIMIT 1";
3384
            $rs = Database::query($sql);
3385
3386
            $lastConnection = 0;
3387
            if (Database::num_rows($rs) > 0) {
3388
                $value = Database::fetch_array($rs);
3389
                if (isset($value['max']) && !empty($value['max'])) {
3390
                    $lastConnection = api_strtotime($value['max'], 'UTC');
3391
                }
3392
            }
3393
3394
            if (!empty($lastConnection)) {
3395
                return $lastConnection;
3396
            }
3397
        }
3398
        if (!empty($course)) {
3399
            $lp_table = Database::get_course_table(TABLE_LP_MAIN);
3400
            $t_lpv = Database::get_course_table(TABLE_LP_VIEW);
3401
            $t_lpiv = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3402
3403
            // Check the real number of LPs corresponding to the filter in the
3404
            // database (and if no list was given, get them all)
3405
            $sql = "SELECT iid FROM $lp_table
3406
                    WHERE c_id = $course_id AND iid = $lp_id ";
3407
            $row = Database::query($sql);
3408
            $count = Database::num_rows($row);
3409
3410
            // calculates last connection time
3411
            if ($count > 0) {
3412
                $sql = 'SELECT MAX(start_time)
3413
                        FROM '.$t_lpiv.' AS item_view
3414
                        INNER JOIN '.$t_lpv.' AS view
3415
                        ON (item_view.lp_view_id = view.iid AND item_view.c_id = view.c_id)
3416
                        WHERE
3417
                            status != "not attempted" AND
3418
                            item_view.c_id = '.$course_id.' AND
3419
                            view.c_id = '.$course_id.' AND
3420
                            view.lp_id = '.$lp_id.' AND
3421
                            view.user_id = '.$student_id.' AND
3422
                            view.session_id = '.$session_id;
3423
                $rs = Database::query($sql);
3424
                if (Database::num_rows($rs) > 0) {
3425
                    $lastTime = Database::result($rs, 0, 0);
3426
                }
3427
            }
3428
        }
3429
3430
        return $lastTime;
3431
    }
3432
3433
    public static function getFirstConnectionTimeInLp(
3434
        $student_id,
3435
        $course_code,
3436
        $lp_id,
3437
        $session_id = 0
3438
    ) {
3439
        $course = api_get_course_info($course_code);
3440
        $student_id = (int) $student_id;
3441
        $lp_id = (int) $lp_id;
3442
        $session_id = (int) $session_id;
3443
        $time = 0;
3444
3445
        if (!empty($course)) {
3446
            $course_id = $course['real_id'];
3447
            $lp_table = Database::get_course_table(TABLE_LP_MAIN);
3448
            $t_lpv = Database::get_course_table(TABLE_LP_VIEW);
3449
            $t_lpiv = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3450
3451
            // Check the real number of LPs corresponding to the filter in the
3452
            // database (and if no list was given, get them all)
3453
            $sql = "SELECT iid FROM $lp_table
3454
                    WHERE c_id = $course_id AND iid = $lp_id ";
3455
            $row = Database::query($sql);
3456
            $count = Database::num_rows($row);
3457
3458
            // calculates first connection time
3459
            if ($count > 0) {
3460
                $sql = 'SELECT MIN(start_time)
3461
                        FROM '.$t_lpiv.' AS item_view
3462
                        INNER JOIN '.$t_lpv.' AS view
3463
                        ON (item_view.lp_view_id = view.iid AND item_view.c_id = view.c_id)
3464
                        WHERE
3465
                            status != "not attempted" AND
3466
                            item_view.c_id = '.$course_id.' AND
3467
                            view.c_id = '.$course_id.' AND
3468
                            view.lp_id = '.$lp_id.' AND
3469
                            view.user_id = '.$student_id.' AND
3470
                            view.session_id = '.$session_id;
3471
                $rs = Database::query($sql);
3472
                if (Database::num_rows($rs) > 0) {
3473
                    $time = Database::result($rs, 0, 0);
3474
                }
3475
            }
3476
        }
3477
3478
        return $time;
3479
    }
3480
3481
    /**
3482
     * gets the list of students followed by coach.
3483
     *
3484
     * @param int $coach_id Coach id
3485
     *
3486
     * @return array List of students
3487
     */
3488
    public static function get_student_followed_by_coach($coach_id)
3489
    {
3490
        $coach_id = intval($coach_id);
3491
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3492
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3493
        $tbl_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
3494
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3495
3496
        $students = [];
3497
        // At first, courses where $coach_id is coach of the course //
3498
        $sql = 'SELECT session_id, c_id
3499
                FROM '.$tbl_session_course_user.'
3500
                WHERE user_id='.$coach_id.' AND status=2';
3501
3502
        if (api_is_multiple_url_enabled()) {
3503
            $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3504
            $access_url_id = api_get_current_access_url_id();
3505
            if (-1 != $access_url_id) {
3506
                $sql = 'SELECT scu.session_id, scu.c_id
3507
                        FROM '.$tbl_session_course_user.' scu
3508
                        INNER JOIN '.$tbl_session_rel_access_url.'  sru
3509
                        ON (scu.session_id=sru.session_id)
3510
                        WHERE
3511
                            scu.user_id='.$coach_id.' AND
3512
                            scu.status=2 AND
3513
                            sru.access_url_id = '.$access_url_id;
3514
            }
3515
        }
3516
3517
        $result = Database::query($sql);
3518
3519
        while ($a_courses = Database::fetch_array($result)) {
3520
            $courseId = $a_courses['c_id'];
3521
            $id_session = $a_courses['session_id'];
3522
3523
            $sql = "SELECT DISTINCT srcru.user_id
3524
                    FROM $tbl_session_course_user AS srcru
3525
                    INNER JOIN $tbl_session_user sru
3526
                    ON (srcru.user_id = sru.user_id AND srcru.session_id = sru.session_id)
3527
                    WHERE
3528
                        sru.relation_type <> ".SESSION_RELATION_TYPE_RRHH." AND
3529
                        srcru.c_id = '$courseId' AND
3530
                        srcru.session_id = '$id_session'";
3531
3532
            $rs = Database::query($sql);
3533
            while ($row = Database::fetch_array($rs)) {
3534
                $students[$row['user_id']] = $row['user_id'];
3535
            }
3536
        }
3537
3538
        // Then, courses where $coach_id is coach of the session
3539
        $sql = 'SELECT session_course_user.user_id
3540
                FROM '.$tbl_session_course_user.' as session_course_user
3541
                INNER JOIN '.$tbl_session_user.' sru
3542
                ON session_course_user.user_id = sru.user_id AND session_course_user.session_id = sru.session_id
3543
                INNER JOIN '.$tbl_session_course.' as session_course
3544
                ON session_course.c_id = session_course_user.c_id
3545
                AND session_course_user.session_id = session_course.session_id
3546
                INNER JOIN '.$tbl_session.' as session
3547
                ON session.id = session_course.session_id
3548
                AND session.id_coach = '.$coach_id;
3549
        if (api_is_multiple_url_enabled()) {
3550
            $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3551
            $access_url_id = api_get_current_access_url_id();
3552
            if (-1 != $access_url_id) {
3553
                $sql = 'SELECT session_course_user.user_id
3554
                        FROM '.$tbl_session_course_user.' as session_course_user
3555
                        INNER JOIN '.$tbl_session_user.' sru
3556
                        ON session_course_user.user_id = sru.user_id AND
3557
                           session_course_user.session_id = sru.session_id
3558
                        INNER JOIN '.$tbl_session_course.' as session_course
3559
                        ON session_course.c_id = session_course_user.c_id AND
3560
                        session_course_user.session_id = session_course.session_id
3561
                        INNER JOIN '.$tbl_session.' as session
3562
                        ON session.id = session_course.session_id AND
3563
                        session.id_coach = '.$coach_id.'
3564
                        INNER JOIN '.$tbl_session_rel_access_url.' session_rel_url
3565
                        ON session.id = session_rel_url.session_id
3566
                        WHERE access_url_id = '.$access_url_id;
3567
            }
3568
        }
3569
3570
        $result = Database::query($sql);
3571
        while ($row = Database::fetch_array($result)) {
3572
            $students[$row['user_id']] = $row['user_id'];
3573
        }
3574
3575
        return $students;
3576
    }
3577
3578
    /**
3579
     * Check if a coach is allowed to follow a student.
3580
     *
3581
     * @param    int        Coach id
3582
     * @param    int        Student id
3583
     *
3584
     * @return bool
3585
     */
3586
    public static function is_allowed_to_coach_student($coach_id, $student_id)
3587
    {
3588
        $coach_id = intval($coach_id);
3589
        $student_id = intval($student_id);
3590
3591
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3592
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3593
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3594
3595
        // At first, courses where $coach_id is coach of the course
3596
        $sql = 'SELECT 1 FROM '.$tbl_session_course_user.'
3597
                WHERE user_id='.$coach_id.' AND status=2';
3598
        $result = Database::query($sql);
3599
        if (Database::num_rows($result) > 0) {
3600
            return true;
3601
        }
3602
3603
        // Then, courses where $coach_id is coach of the session
3604
        $sql = 'SELECT session_course_user.user_id
3605
                FROM '.$tbl_session_course_user.' as session_course_user
3606
                INNER JOIN '.$tbl_session_course.' as session_course
3607
                ON session_course.c_id = session_course_user.c_id
3608
                INNER JOIN '.$tbl_session.' as session
3609
                ON session.id = session_course.session_id
3610
                AND session.id_coach = '.$coach_id.'
3611
                WHERE user_id = '.$student_id;
3612
        $result = Database::query($sql);
3613
        if (Database::num_rows($result) > 0) {
3614
            return true;
3615
        }
3616
3617
        return false;
3618
    }
3619
3620
    /**
3621
     * Get courses followed by coach.
3622
     *
3623
     * @param     int        Coach id
3624
     * @param    int        Session id (optional)
3625
     *
3626
     * @return array Courses list
3627
     */
3628
    public static function get_courses_followed_by_coach($coach_id, $id_session = 0)
3629
    {
3630
        $coach_id = intval($coach_id);
3631
        if (!empty($id_session)) {
3632
            $id_session = intval($id_session);
3633
        }
3634
3635
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3636
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3637
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3638
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3639
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3640
3641
        // At first, courses where $coach_id is coach of the course.
3642
        $sql = 'SELECT DISTINCT c.code
3643
                FROM '.$tbl_session_course_user.' sc
3644
                INNER JOIN '.$tbl_course.' c
3645
                ON (c.id = sc.c_id)
3646
                WHERE user_id = '.$coach_id.' AND status = 2';
3647
3648
        if (api_is_multiple_url_enabled()) {
3649
            $access_url_id = api_get_current_access_url_id();
3650
            if (-1 != $access_url_id) {
3651
                $sql = 'SELECT DISTINCT c.code
3652
                        FROM '.$tbl_session_course_user.' scu
3653
                        INNER JOIN '.$tbl_course.' c
3654
                        ON (c.code = scu.c_id)
3655
                        INNER JOIN '.$tbl_course_rel_access_url.' cru
3656
                        ON (c.id = cru.c_id)
3657
                        WHERE
3658
                            scu.user_id='.$coach_id.' AND
3659
                            scu.status=2 AND
3660
                            cru.access_url_id = '.$access_url_id;
3661
            }
3662
        }
3663
3664
        if (!empty($id_session)) {
3665
            $sql .= ' AND session_id='.$id_session;
3666
        }
3667
3668
        $courseList = [];
3669
        $result = Database::query($sql);
3670
        while ($row = Database::fetch_array($result)) {
3671
            $courseList[$row['code']] = $row['code'];
3672
        }
3673
3674
        // Then, courses where $coach_id is coach of the session
3675
        $sql = 'SELECT DISTINCT course.code
3676
                FROM '.$tbl_session_course.' as session_course
3677
                INNER JOIN '.$tbl_session.' as session
3678
                    ON session.id = session_course.session_id
3679
                    AND session.id_coach = '.$coach_id.'
3680
                INNER JOIN '.$tbl_course.' as course
3681
                    ON course.id = session_course.c_id';
3682
3683
        if (api_is_multiple_url_enabled()) {
3684
            $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3685
            $access_url_id = api_get_current_access_url_id();
3686
            if (-1 != $access_url_id) {
3687
                $sql = 'SELECT DISTINCT c.code
3688
                    FROM '.$tbl_session_course.' as session_course
3689
                    INNER JOIN '.$tbl_course.' c
3690
                    ON (c.id = session_course.c_id)
3691
                    INNER JOIN '.$tbl_session.' as session
3692
                    ON session.id = session_course.session_id
3693
                        AND session.id_coach = '.$coach_id.'
3694
                    INNER JOIN '.$tbl_course.' as course
3695
                        ON course.id = session_course.c_id
3696
                     INNER JOIN '.$tbl_course_rel_access_url.' course_rel_url
3697
                    ON (course_rel_url.c_id = c.id)';
3698
            }
3699
        }
3700
3701
        if (!empty($id_session)) {
3702
            $sql .= ' WHERE session_course.session_id='.$id_session;
3703
            if (api_is_multiple_url_enabled()) {
3704
                $sql .= ' AND access_url_id = '.$access_url_id;
3705
            }
3706
        } else {
3707
            if (api_is_multiple_url_enabled()) {
3708
                $sql .= ' WHERE access_url_id = '.$access_url_id;
3709
            }
3710
        }
3711
3712
        $result = Database::query($sql);
3713
        while ($row = Database::fetch_array($result)) {
3714
            $courseList[$row['code']] = $row['code'];
3715
        }
3716
3717
        return $courseList;
3718
    }
3719
3720
    /**
3721
     * Get sessions coached by user.
3722
     *
3723
     * @param int    $coach_id
3724
     * @param int    $start
3725
     * @param int    $limit
3726
     * @param bool   $getCount
3727
     * @param string $keyword
3728
     * @param string $description
3729
     * @param string $orderByName
3730
     * @param string $orderByDirection
3731
     * @param array  $options
3732
     *
3733
     * @return mixed
3734
     */
3735
    public static function get_sessions_coached_by_user(
3736
        $coach_id,
3737
        $start = 0,
3738
        $limit = 0,
3739
        $getCount = false,
3740
        $keyword = '',
3741
        $description = '',
3742
        $orderByName = '',
3743
        $orderByDirection = '',
3744
        $options = []
3745
    ) {
3746
        // table definition
3747
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3748
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3749
        $coach_id = (int) $coach_id;
3750
3751
        $select = ' SELECT * FROM ';
3752
        if ($getCount) {
3753
            $select = ' SELECT count(DISTINCT id) as count FROM ';
3754
        }
3755
3756
        $limitCondition = null;
3757
        if (!empty($start) && !empty($limit)) {
3758
            $limitCondition = " LIMIT ".intval($start).", ".intval($limit);
3759
        }
3760
3761
        $keywordCondition = null;
3762
        if (!empty($keyword)) {
3763
            $keyword = Database::escape_string($keyword);
3764
            $keywordCondition = " AND (name LIKE '%$keyword%' ) ";
3765
3766
            if (!empty($description)) {
3767
                $description = Database::escape_string($description);
3768
                $keywordCondition = " AND (name LIKE '%$keyword%' OR description LIKE '%$description%' ) ";
3769
            }
3770
        }
3771
3772
        $extraFieldModel = new ExtraFieldModel('session');
3773
        $conditions = $extraFieldModel->parseConditions($options);
3774
        $sqlInjectJoins = $conditions['inject_joins'];
3775
        $extraFieldsConditions = $conditions['where'];
3776
        $sqlInjectWhere = $conditions['inject_where'];
3777
        $injectExtraFields = $conditions['inject_extra_fields'];
3778
3779
        $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3780
        $access_url_id = api_get_current_access_url_id();
3781
3782
        $orderBy = '';
3783
        if (!empty($orderByName)) {
3784
            if (in_array($orderByName, ['name', 'access_start_date'])) {
3785
                $orderByDirection = in_array(strtolower($orderByDirection), ['asc', 'desc']) ? $orderByDirection : 'asc';
3786
                $orderByName = Database::escape_string($orderByName);
3787
                $orderBy .= " ORDER BY $orderByName $orderByDirection";
3788
            }
3789
        }
3790
3791
        $sql = "
3792
            $select
3793
            (
3794
                SELECT DISTINCT
3795
                    s.id,
3796
                    name,
3797
                    $injectExtraFields
3798
                    access_start_date,
3799
                    access_end_date
3800
                FROM $tbl_session s
3801
                INNER JOIN $tbl_session_rel_access_url session_rel_url
3802
                ON (s.id = session_rel_url.session_id)
3803
                $sqlInjectJoins
3804
                WHERE
3805
                    id_coach = $coach_id AND
3806
                    access_url_id = $access_url_id
3807
                    $keywordCondition
3808
                    $extraFieldsConditions
3809
                    $sqlInjectWhere
3810
            UNION
3811
                SELECT DISTINCT
3812
                    s.id,
3813
                    s.name,
3814
                    $injectExtraFields
3815
                    s.access_start_date,
3816
                    s.access_end_date
3817
                FROM $tbl_session as s
3818
                INNER JOIN $tbl_session_course_user as session_course_user
3819
                ON
3820
                    s.id = session_course_user.session_id AND
3821
                    session_course_user.user_id = $coach_id AND
3822
                    session_course_user.status = 2
3823
                INNER JOIN $tbl_session_rel_access_url session_rel_url
3824
                ON (s.id = session_rel_url.session_id)
3825
                $sqlInjectJoins
3826
                WHERE
3827
                    access_url_id = $access_url_id
3828
                    $keywordCondition
3829
                    $extraFieldsConditions
3830
                    $sqlInjectWhere
3831
            ) as sessions $limitCondition $orderBy
3832
            ";
3833
3834
        $rs = Database::query($sql);
3835
        if ($getCount) {
3836
            $row = Database::fetch_array($rs);
3837
3838
            return $row['count'];
3839
        }
3840
3841
        $sessions = [];
3842
        while ($row = Database::fetch_array($rs)) {
3843
            if ('0000-00-00 00:00:00' === $row['access_start_date']) {
3844
                $row['access_start_date'] = null;
3845
            }
3846
3847
            $sessions[$row['id']] = $row;
3848
        }
3849
3850
        if (!empty($sessions)) {
3851
            foreach ($sessions as &$session) {
3852
                if (empty($session['access_start_date'])) {
3853
                    $session['status'] = get_lang('active');
3854
                } else {
3855
                    $time_start = api_strtotime($session['access_start_date'], 'UTC');
3856
                    $time_end = api_strtotime($session['access_end_date'], 'UTC');
3857
                    if ($time_start < time() && time() < $time_end) {
3858
                        $session['status'] = get_lang('active');
3859
                    } else {
3860
                        if (time() < $time_start) {
3861
                            $session['status'] = get_lang('Not yet begun');
3862
                        } else {
3863
                            if (time() > $time_end) {
3864
                                $session['status'] = get_lang('Past');
3865
                            }
3866
                        }
3867
                    }
3868
                }
3869
            }
3870
        }
3871
3872
        return $sessions;
3873
    }
3874
3875
    /**
3876
     * Get courses list from a session.
3877
     *
3878
     * @param    int        Session id
3879
     *
3880
     * @return array Courses list
3881
     */
3882
    public static function get_courses_list_from_session($session_id)
3883
    {
3884
        $session_id = (int) $session_id;
3885
3886
        // table definition
3887
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3888
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
3889
3890
        $sql = "SELECT DISTINCT code, c_id
3891
                FROM $tbl_session_course sc
3892
                INNER JOIN $courseTable c
3893
                ON sc.c_id = c.id
3894
                WHERE session_id= $session_id";
3895
3896
        $result = Database::query($sql);
3897
3898
        $courses = [];
3899
        while ($row = Database::fetch_array($result)) {
3900
            $courses[$row['code']] = $row;
3901
        }
3902
3903
        return $courses;
3904
    }
3905
3906
    /**
3907
     * Count the number of documents that an user has uploaded to a course.
3908
     *
3909
     * @param    int|array   Student id(s)
3910
     * @param    string      Course code
3911
     * @param    int         Session id (optional),
3912
     * if param $session_id is null(default)
3913
     * return count of assignments including sessions, 0 = session is not filtered
3914
     *
3915
     * @return int Number of documents
3916
     */
3917
    public static function count_student_uploaded_documents(
3918
        $student_id,
3919
        $course_code,
3920
        $session_id = null
3921
    ) {
3922
        $a_course = api_get_course_info($course_code);
3923
        $repo = Container::getDocumentRepository();
3924
3925
        $user = api_get_user_entity($student_id);
3926
        $course = api_get_course_entity($a_course['real_id']);
3927
        $session = api_get_session_entity($session_id);
3928
        //$group = api_get_group_entity(api_get_group_id());
3929
3930
        $qb = $repo->getResourcesByCourseLinkedToUser($user, $course, $session);
3931
3932
        $qb->select('count(resource)');
3933
        $count = $qb->getQuery()->getSingleScalarResult();
3934
3935
        return $count;
3936
3937
        // get the information of the course
3938
        $a_course = api_get_course_info($course_code);
0 ignored issues
show
Unused Code introduced by
$a_course = api_get_course_info($course_code) is not reachable.

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

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

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

    return false;
}

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

Loading history...
3939
        if (!empty($a_course)) {
3940
            // table definition
3941
            $tbl_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
3942
            $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
3943
            $course_id = $a_course['real_id'];
3944
            if (is_array($student_id)) {
3945
                $studentList = array_map('intval', $student_id);
3946
                $condition_user = " AND ip.insert_user_id IN ('".implode(',', $studentList)."') ";
3947
            } else {
3948
                $student_id = (int) $student_id;
3949
                $condition_user = " AND ip.insert_user_id = '$student_id' ";
3950
            }
3951
3952
            $condition_session = null;
3953
            if (isset($session_id)) {
3954
                $session_id = (int) $session_id;
3955
                $condition_session = " AND pub.session_id = $session_id ";
3956
            }
3957
3958
            $sql = "SELECT count(ip.tool) AS count
3959
                    FROM $tbl_item_property ip
3960
                    INNER JOIN $tbl_document pub
3961
                    ON (ip.ref = pub.iid AND ip.c_id = pub.c_id)
3962
                    WHERE
3963
                        ip.c_id  = $course_id AND
3964
                        pub.c_id  = $course_id AND
3965
                        pub.filetype ='file' AND
3966
                        ip.tool = 'document'
3967
                        $condition_user $condition_session ";
3968
            $rs = Database::query($sql);
3969
            $row = Database::fetch_array($rs, 'ASSOC');
3970
3971
            return $row['count'];
3972
        }
3973
3974
        return null;
3975
    }
3976
3977
    /**
3978
     * Count assignments per student.
3979
     *
3980
     * @param array|int $student_id
3981
     * @param string    $course_code
3982
     * @param int       $session_id  if param is null(default) return count of assignments including sessions,
3983
     *                               0 = session is not filtered
3984
     *
3985
     * @return int Count of assignments
3986
     */
3987
    public static function count_student_assignments(
3988
        $student_id,
3989
        $course_code = null,
3990
        $session_id = null
3991
    ) {
3992
        if (empty($student_id)) {
3993
            return 0;
3994
        }
3995
3996
        $a_course = api_get_course_info($course_code);
3997
        $repo = Container::getStudentPublicationRepository();
3998
3999
        $user = api_get_user_entity($student_id);
4000
        $course = api_get_course_entity($a_course['real_id']);
4001
        $session = api_get_session_entity($session_id);
4002
        //$group = api_get_group_entity(api_get_group_id());
4003
4004
        $qb = $repo->getResourcesByCourseLinkedToUser($user, $course, $session);
4005
4006
        $qb->select('count(resource)');
4007
        $count = $qb->getQuery()->getSingleScalarResult();
4008
4009
        return $count;
4010
4011
        $conditions = [];
0 ignored issues
show
Unused Code introduced by
$conditions = array() is not reachable.

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

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

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

    return false;
}

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

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