Passed
Push — master ( 3fcb32...49d6fc )
by Julito
09:27
created

Tracking::count_number_of_threads_by_course()   A

Complexity

Conditions 5
Paths 9

Size

Total Lines 55
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 31
nc 9
nop 3
dl 0
loc 55
rs 9.1128
c 0
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

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

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

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

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

    return false;
}

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

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