Passed
Push — 1.11.x ( 1405b1...4520bd )
by Julito
14:06
created

get_documents_most_downloaded_by_course()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 33
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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