Passed
Push — 1.11.x ( 37b4d9...945d0c )
by Julito
09:07
created

Tracking::getLastConnectionInAnyCourse()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

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