Test Setup Failed
Push — master ( 4e700f...c7183e )
by Julito
63:12
created

Tracking::count_student_exercise_attempts()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 41
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

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

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1300
                    $teachers[] = $teacherData['user_id'];
1301
                }
1302
            }
1303
1304
            $humanResources = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1305
                'drh_all',
1306
                $userId,
1307
                $getCount,
1308
                null,
1309
                null,
1310
                null,
1311
                null,
1312
                null,
1313
                null,
1314
                null,
1315
                array(),
1316
                array(),
1317
                DRH
1318
            );
1319
1320 View Code Duplication
            if ($getCount) {
1321
                $drhCount = $humanResources;
1322
            } else {
1323
                $humanResourcesList = array();
1324
                if (is_array($humanResources)) {
1325
                    foreach ($humanResources as $item) {
1326
                        $humanResourcesList[] = $item['user_id'];
1327
                    }
1328
                }
1329
            }
1330
1331
            $platformCourses = SessionManager::getAllCoursesFollowedByUser(
1332
                $userId,
1333
                null,
1334
                null,
1335
                null,
1336
                null,
1337
                null,
1338
                $getCount
1339
            );
1340
1341 View Code Duplication
            if ($getCount) {
1342
                $courseCount = $platformCourses;
1343
            } else {
1344
                foreach ($platformCourses as $course) {
1345
                    $courses[$course['code']] = $course['code'];
1346
                }
1347
            }
1348
1349
            $sessions = SessionManager::get_sessions_followed_by_drh(
1350
                $userId,
1351
                null,
1352
                null,
1353
                false
1354
            );
1355
        } else {
1356
            $studentList = UserManager::getUsersFollowedByUser(
1357
                $userId,
1358
                STUDENT,
1359
                false,
1360
                false,
1361
                false,
1362
                null,
1363
                null,
1364
                null,
1365
                null,
1366
                null,
1367
                null,
1368
                COURSEMANAGER
1369
            );
1370
1371
            $students = array();
1372
            if (is_array($studentList)) {
1373
                foreach ($studentList as $studentData) {
1374
                    $students[] = $studentData['user_id'];
1375
                }
1376
            }
1377
1378
            $studentBossesList = UserManager::getUsersFollowedByUser(
1379
                $userId,
1380
                STUDENT_BOSS,
1381
                false,
1382
                false,
1383
                $getCount,
1384
                null,
1385
                null,
1386
                null,
1387
                null,
1388
                null,
1389
                null,
1390
                COURSEMANAGER
1391
            );
1392
1393 View Code Duplication
            if ($getCount) {
1394
                $studentBossCount = $studentBossesList;
1395
            } else {
1396
                $studentBosses = array();
1397
                if (is_array($studentBossesList)) {
1398
                    foreach ($studentBossesList as $studentBossData) {
1399
                        $studentBosses[] = $studentBossData['user_id'];
1400
                    }
1401
                }
1402
            }
1403
1404
            $teacherList = UserManager::getUsersFollowedByUser(
1405
                $userId,
1406
                COURSEMANAGER,
1407
                false,
1408
                false,
1409
                $getCount,
1410
                null,
1411
                null,
1412
                null,
1413
                null,
1414
                null,
1415
                null,
1416
                COURSEMANAGER
1417
            );
1418
1419 View Code Duplication
            if ($getCount) {
1420
                $teachersCount = $teacherList;
1421
            } else {
1422
                $teachers = array();
1423
                foreach ($teacherList as $teacherData) {
1424
                    $teachers[] = $teacherData['user_id'];
1425
                }
1426
            }
1427
1428
            $humanResources = UserManager::getUsersFollowedByUser(
1429
                $userId,
1430
                DRH,
1431
                false,
1432
                false,
1433
                $getCount,
1434
                null,
1435
                null,
1436
                null,
1437
                null,
1438
                null,
1439
                null,
1440
                COURSEMANAGER
1441
            );
1442
1443 View Code Duplication
            if ($getCount) {
1444
                $drhCount = $humanResources;
1445
            } else {
1446
                $humanResourcesList = array();
1447
                foreach ($humanResources as $item) {
1448
                    $humanResourcesList[] = $item['user_id'];
1449
                }
1450
            }
1451
1452
            $platformCourses = CourseManager::getCoursesFollowedByUser(
1453
                $userId,
1454
                COURSEMANAGER,
1455
                null,
1456
                null,
1457
                null,
1458
                null,
1459
                $getCount,
1460
                null,
1461
                null,
1462
                true
1463
            );
1464
1465
            if ($getCount) {
1466
                $assignedCourseCount = $platformCourses;
1467
            } else {
1468
                foreach ($platformCourses as $course) {
1469
                    $assignedCourses[$course['code']] = $course['code'];
1470
                }
1471
            }
1472
1473
            $platformCourses = CourseManager::getCoursesFollowedByUser(
1474
                $userId,
1475
                COURSEMANAGER,
1476
                null,
1477
                null,
1478
                null,
1479
                null,
1480
                $getCount
1481
            );
1482
1483 View Code Duplication
            if ($getCount) {
1484
                $courseCount = $platformCourses;
1485
            } else {
1486
                foreach ($platformCourses as $course) {
1487
                    $courses[$course['code']] = $course['code'];
1488
                }
1489
            }
1490
1491
            $sessions = SessionManager::getSessionsFollowedByUser(
1492
                $userId,
1493
                COURSEMANAGER,
1494
                null,
1495
                null,
1496
                false
1497
            );
1498
        }
1499
1500
        if ($getCount) {
1501
            return [
1502
                'drh' => $drhCount,
1503
                'teachers' => $teachersCount,
1504
                'student_count' => count($students),
1505
                'student_list' => $students,
1506
                'student_bosses' => $studentBossCount,
1507
                'courses' => $courseCount,
1508
                'session_count' => count($sessions),
1509
                'session_list' => $sessions,
1510
                'assigned_courses' => $assignedCourseCount
1511
            ];
1512
        }
1513
1514
        return array(
1515
            'drh' => $humanResourcesList,
1516
            'teachers' => $teachers,
1517
            'student_list' => $students,
1518
            'student_bosses' => $studentBosses,
1519
            'courses' => $courses,
1520
            'sessions' => $sessions,
1521
            'assigned_courses' => $assignedCourses
1522
        );
1523
    }
1524
1525
    /**
1526
     * Calculates the time spent on the platform by a user
1527
     * @param   int|array User id
1528
     * @param   string $timeFilter type of time filter: 'last_week' or 'custom'
1529
     * @param   string  $start_date start date date('Y-m-d H:i:s')
1530
     * @param   string  $end_date end date date('Y-m-d H:i:s')
1531
     *
1532
     * @return int $nb_seconds
1533
     */
1534
    public static function get_time_spent_on_the_platform(
1535
        $userId,
1536
        $timeFilter = 'last_7_days',
1537
        $start_date = null,
1538
        $end_date = null
1539
    ) {
1540
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1541
        $condition_time = '';
1542
1543
        if (is_array($userId)) {
1544
            $userList = array_map('intval', $userId);
1545
            $userCondition = " login_user_id IN ('".implode("','", $userList)."')";
1546
        } else {
1547
            $userCondition = " login_user_id = ".intval($userId);
1548
        }
1549
1550
        if (empty($timeFilter)) {
1551
            $timeFilter = 'last_week';
1552
        }
1553
1554
        $today = new DateTime('now', new DateTimeZone('UTC'));
1555
1556
        switch ($timeFilter) {
1557 View Code Duplication
            case 'last_7_days':
1558
                $newDate = new DateTime('-7 day', new DateTimeZone('UTC'));
1559
                $condition_time = " AND (login_date >= '{$newDate->format('Y-m-d H:i:s')}'";
1560
                $condition_time .= " AND logout_date <= '{$today->format('Y-m-d H:i:s')}') ";
1561
                break;
1562 View Code Duplication
            case 'last_30_days':
1563
                $newDate = new DateTime('-30 days', new DateTimeZone('UTC'));
1564
                $condition_time = " AND (login_date >= '{$newDate->format('Y-m-d H:i:s')}'";
1565
                $condition_time .= "AND logout_date <= '{$today->format('Y-m-d H:i:s')}') ";
1566
                break;
1567
            case 'custom':
1568
                if (!empty($start_date) && !empty($end_date)) {
1569
                    $start_date = Database::escape_string($start_date);
1570
                    $end_date = Database::escape_string($end_date);
1571
                    $condition_time = ' AND (login_date >= "'.$start_date.'" AND logout_date <= "'.$end_date.'" ) ';
1572
                }
1573
                break;
1574
        }
1575
1576
        $sql = 'SELECT SUM(TIMESTAMPDIFF(SECOND, login_date, logout_date)) diff
1577
    	        FROM '.$tbl_track_login.'
1578
                WHERE '.$userCondition.$condition_time;
1579
        $rs = Database::query($sql);
1580
        $row = Database::fetch_array($rs, 'ASSOC');
1581
        $diff = $row['diff'];
1582
1583
        if ($diff >= 0) {
1584
            return $diff;
1585
        } else {
1586
            return -1;
1587
        }
1588
    }
1589
1590
    /**
1591
     * Calculates the time spent on the course
1592
     * @param integer $user_id
1593
     * @param integer  $courseId
1594
     * @param int Session id (optional)
1595
     *
1596
     * @return int Time in seconds
1597
     */
1598
    public static function get_time_spent_on_the_course($user_id, $courseId, $session_id = 0)
1599
    {
1600
        $courseId = intval($courseId);
1601
        $session_id  = intval($session_id);
1602
        $tbl_track_course = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1603
        if (is_array($user_id)) {
1604
            $user_id = array_map('intval', $user_id);
1605
            $condition_user = " AND user_id IN (".implode(',', $user_id).") ";
1606
        } else {
1607
            $user_id = intval($user_id);
1608
            $condition_user = " AND user_id = $user_id ";
1609
        }
1610
1611
        $sql = "SELECT
1612
                SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as nb_seconds
1613
                FROM $tbl_track_course
1614
                WHERE UNIX_TIMESTAMP(logout_course_date) > UNIX_TIMESTAMP(login_course_date) ";
1615
1616
        if ($courseId != 0) {
1617
            $sql .= "AND c_id = '$courseId' ";
1618
        }
1619
1620
        if ($session_id != -1) {
1621
            $sql .= "AND session_id = '$session_id' ";
1622
        }
1623
1624
        $sql .= $condition_user;
1625
        $rs = Database::query($sql);
1626
        $row = Database::fetch_array($rs);
1627
1628
        return $row['nb_seconds'];
1629
    }
1630
1631
    /**
1632
     * Get first connection date for a student
1633
     * @param int $student_id
1634
     *
1635
     * @return string|bool Date format long without day or false if there are no connections
1636
     */
1637
    public static function get_first_connection_date($student_id)
1638
    {
1639
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1640
        $sql = 'SELECT login_date
1641
                FROM '.$table.'
1642
                WHERE login_user_id = ' . intval($student_id).'
1643
                ORDER BY login_date ASC
1644
                LIMIT 0,1';
1645
1646
        $rs = Database::query($sql);
1647
        if (Database::num_rows($rs) > 0) {
1648
            if ($first_login_date = Database::result($rs, 0, 0)) {
1649
                return api_convert_and_format_date(
1650
                    $first_login_date,
1651
                    DATE_FORMAT_SHORT,
1652
                    date_default_timezone_get()
1653
                );
1654
            }
1655
        }
1656
1657
        return false;
1658
    }
1659
1660
    /**
1661
     * Get las connection date for a student
1662
     * @param int $student_id
1663
     * @param bool $warning_message Show a warning message (optional)
1664
     * @param bool $return_timestamp True for returning results in timestamp (optional)
1665
     * @return string|int|bool Date format long without day, false if there are no connections or
1666
     * timestamp if parameter $return_timestamp is true
1667
     */
1668
    public static function get_last_connection_date(
1669
        $student_id,
1670
        $warning_message = false,
1671
        $return_timestamp = false
1672
    ) {
1673
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1674
        $sql = 'SELECT login_date
1675
                FROM ' . $table.'
1676
                WHERE login_user_id = ' . intval($student_id).'
1677
                ORDER BY login_date
1678
                DESC LIMIT 0,1';
1679
1680
        $rs = Database::query($sql);
1681
        if (Database::num_rows($rs) > 0) {
1682
            if ($last_login_date = Database::result($rs, 0, 0)) {
1683
                $last_login_date = api_get_local_time($last_login_date);
1684
                if ($return_timestamp) {
1685
                    return api_strtotime($last_login_date, 'UTC');
1686
                } else {
1687
                    if (!$warning_message) {
1688
                        return api_format_date($last_login_date, DATE_FORMAT_SHORT);
1689
                    } else {
1690
                        $timestamp = api_strtotime($last_login_date, 'UTC');
1691
                        $currentTimestamp = time();
1692
1693
                        //If the last connection is > than 7 days, the text is red
1694
                        //345600 = 7 days in seconds
1695
                        if ($currentTimestamp - $timestamp > 604800) {
1696
                            return '<span style="color: #F00;">'.api_format_date($last_login_date, DATE_FORMAT_SHORT).'</span>';
1697
                        } else {
1698
                            return api_format_date($last_login_date, DATE_FORMAT_SHORT);
1699
                        }
1700
                    }
1701
                }
1702
            }
1703
        }
1704
1705
        return false;
1706
    }
1707
1708
    /**
1709
     * Get las connection date for a student
1710
     * @param array $studentList Student id array
1711
     * @param int $days
1712
     * @param bool $getCount
1713
     * @return int
1714
     */
1715
    public static function getInactiveUsers($studentList, $days, $getCount = true)
1716
    {
1717
        if (empty($studentList)) {
1718
            return 0;
1719
        }
1720
        $days = intval($days);
1721
        $date = api_get_utc_datetime(strtotime($days.' days ago'));
1722
        $studentList = array_map('intval', $studentList);
1723
1724
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1725
        $select = " SELECT login_user_id ";
1726
        if ($getCount) {
1727
            $select = " SELECT count(DISTINCT login_user_id) as count";
1728
        }
1729
        $sql = "$select
1730
                FROM $tbl_track_login
1731
                WHERE
1732
                    login_user_id IN (' ".implode("','", $studentList)."' ) AND
1733
                    login_date < '$date'
1734
                ";
1735
        $rs = Database::query($sql);
1736 View Code Duplication
        if (Database::num_rows($rs) > 0) {
1737
            if ($getCount) {
1738
                $count = Database::fetch_array($rs);
1739
                return $count['count'];
1740
            }
1741
            return Database::store_result($rs, 'ASSOC');
1742
        }
1743
        return false;
1744
    }
1745
1746
    /**
1747
     * Get first user's connection date on the course
1748
     * @param int User id
1749
     * @param int $courseId
1750
     * @param int Session id (optional, default=0)
1751
     * @param bool $convert_date
1752
     * @return string|bool Date with format long without day or false if there is no date
1753
     */
1754
    public static function get_first_connection_date_on_the_course(
1755
        $student_id,
1756
        $courseId,
1757
        $session_id = 0,
1758
        $convert_date = true
1759
    ) {
1760
        $student_id  = intval($student_id);
1761
        $courseId = intval($courseId);
1762
        $session_id  = intval($session_id);
1763
1764
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1765
        $sql = 'SELECT login_course_date
1766
                FROM '.$tbl_track_login.'
1767
                WHERE
1768
                    user_id = '.$student_id.' AND
1769
                    c_id = '.$courseId.' AND
1770
                    session_id = '.$session_id.'
1771
                ORDER BY login_course_date ASC 
1772
                LIMIT 0,1';
1773
        $rs = Database::query($sql);
1774
        if (Database::num_rows($rs) > 0) {
1775
            if ($first_login_date = Database::result($rs, 0, 0)) {
1776
                if ($convert_date) {
1777
                    return api_convert_and_format_date(
1778
                        $first_login_date,
1779
                        DATE_FORMAT_SHORT
1780
                    );
1781
                } else {
1782
                    return $first_login_date;
1783
                }
1784
            }
1785
        }
1786
1787
        return false;
1788
    }
1789
1790
    /**
1791
     * Get last user's connection date on the course
1792
     * @param     int         User id
1793
     * @param    array $courseInfo real_id and code are used
1794
     * @param    int            Session id (optional, default=0)
1795
     * @param bool $convert_date
1796
     * @return    string|bool    Date with format long without day or false if there is no date
1797
     */
1798
    public static function get_last_connection_date_on_the_course(
1799
        $student_id,
1800
        $courseInfo,
1801
        $session_id = 0,
1802
        $convert_date = true
1803
    ) {
1804
        // protect data
1805
        $student_id  = intval($student_id);
1806
        $courseId = $courseInfo['real_id'];
1807
        $session_id  = intval($session_id);
1808
1809
        $tbl_track_e_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
1810
        $sql = 'SELECT access_date
1811
                FROM '.$tbl_track_e_access.'
1812
                WHERE   access_user_id = '.$student_id.' AND
1813
                        c_id = "'.$courseId.'" AND
1814
                        access_session_id = '.$session_id.'
1815
                ORDER BY access_date DESC
1816
                LIMIT 0,1';
1817
1818
        $rs = Database::query($sql);
1819
        if (Database::num_rows($rs) > 0) {
1820
            if ($last_login_date = Database::result($rs, 0, 0)) {
1821
                if (empty($last_login_date)) {
1822
                    return false;
1823
                }
1824
                //see #5736
1825
                $last_login_date_timestamp = api_strtotime($last_login_date);
1826
                $now = time();
1827
                //If the last connection is > than 7 days, the text is red
1828
                //345600 = 7 days in seconds
1829
                if ($now - $last_login_date_timestamp > 604800) {
1830
                    if ($convert_date) {
1831
                        $last_login_date = api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
1832
                        $icon = api_is_allowed_to_edit() ?
1833
                            '<a href="'.api_get_path(WEB_CODE_PATH).'announcements/announcements.php?action=add&remind_inactive='.$student_id.'&cidReq='.$courseInfo['code'].'" title="'.get_lang('RemindInactiveUser').'">
1834
                              '.Display::return_icon('messagebox_warning.gif').'
1835
                             </a>'
1836
                            : null;
1837
                        return $icon.Display::label($last_login_date, 'warning');
1838
                    } else {
1839
                        return $last_login_date;
1840
                    }
1841
                } else {
1842
                    if ($convert_date) {
1843
                        return api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
1844
                    } else {
1845
                        return $last_login_date;
1846
                    }
1847
                }
1848
            }
1849
        }
1850
        return false;
1851
    }
1852
1853
    /**
1854
     * Get count of the connections to the course during a specified period
1855
     * @param   int  $courseId
1856
     * @param   int     Session id (optional)
1857
     * @param   int     Datetime from which to collect data (defaults to 0)
1858
     * @param   int     Datetime to which to collect data (defaults to now)
1859
     * @return  int     count connections
1860
     */
1861
    public static function get_course_connections_count(
1862
        $courseId,
1863
        $session_id = 0,
1864
        $start = 0,
1865
        $stop = null
1866
    ) {
1867
        if ($start < 0) {
1868
            $start = 0;
1869
        }
1870
        if (!isset($stop) or ($stop < 0)) {
1871
            $stop = api_get_utc_datetime();
1872
        }
1873
1874
        // Given we're storing in cache, round the start and end times
1875
        // to the lower minute
1876
        $roundedStart = substr($start, 0, -2).'00';
1877
        $roundedStop = substr($stop, 0, -2).'00';
1878
        $roundedStart = Database::escape_string($roundedStart);
1879
        $roundedStop = Database::escape_string($roundedStop);
1880
        $month_filter = " AND login_course_date > '$roundedStart' AND login_course_date < '$roundedStop' ";
1881
        $courseId = intval($courseId);
1882
        $session_id = intval($session_id);
1883
        $count = 0;
1884
        $tbl_track_e_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1885
        $sql = "SELECT count(*) as count_connections
1886
                FROM $tbl_track_e_course_access
1887
                WHERE
1888
                    c_id = $courseId AND
1889
                    session_id = $session_id
1890
                    $month_filter";
1891
1892
        //This query can be very slow (several seconds on an indexed table
1893
        // with 14M rows). As such, we'll try to use APCu if it is
1894
        // available to store the resulting value for a few seconds
1895
        $cacheAvailable = api_get_configuration_value('apc');
1896
        if ($cacheAvailable === true) {
1897
            $apc = apcu_cache_info(true);
1898
            $apc_end = $apc['start_time'] + $apc['ttl'];
1899
            $apc_var = api_get_configuration_value('apc_prefix').'course_access_'.$courseId.'_'.$session_id.'_'.strtotime($roundedStart).'_'.strtotime($roundedStop);
1900
            if (apcu_exists($apc_var) && (time() < $apc_end) &&
1901
                apcu_fetch($apc_var) > 0
1902
            ) {
1903
                $count = apcu_fetch($apc_var);
1904
            } else {
1905
                $rs = Database::query($sql);
1906
                if (Database::num_rows($rs) > 0) {
1907
                    $row = Database::fetch_object($rs);
1908
                    $count = $row->count_connections;
1909
                }
1910
                apcu_clear_cache();
1911
                apcu_store($apc_var, $count, 60);
1912
            }
1913 View Code Duplication
        } else {
1914
            $rs = Database::query($sql);
1915
            if (Database::num_rows($rs) > 0) {
1916
                $row = Database::fetch_object($rs);
1917
                $count = $row->count_connections;
1918
            }
1919
        }
1920
1921
        return $count;
1922
    }
1923
1924
    /**
1925
     * Get count courses per student
1926
     * @param     int $user_id Student id
1927
     * @param    bool $include_sessions Include sessions (optional)
1928
     * @return  int        count courses
1929
     */
1930
    public static function count_course_per_student($user_id, $include_sessions = true)
1931
    {
1932
        $user_id = intval($user_id);
1933
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1934
        $tbl_session_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1935
1936
        $sql = 'SELECT DISTINCT c_id
1937
                FROM '.$tbl_course_rel_user.'
1938
                WHERE user_id = '.$user_id.' AND relation_type<>'.COURSE_RELATION_TYPE_RRHH;
1939
        $rs = Database::query($sql);
1940
        $nb_courses = Database::num_rows($rs);
1941
1942
        if ($include_sessions) {
1943
            $sql = 'SELECT DISTINCT c_id
1944
                    FROM '.$tbl_session_course_rel_user.'
1945
                    WHERE user_id = '.$user_id;
1946
            $rs = Database::query($sql);
1947
            $nb_courses += Database::num_rows($rs);
1948
        }
1949
1950
        return $nb_courses;
1951
    }
1952
1953
    /**
1954
     * Gets the score average from all tests in a course by student
1955
     *
1956
     * @param $student_id
1957
     * @param $course_code
1958
     * @param int $exercise_id
1959
     * @param null $session_id
1960
     * @param int $active_filter    2 for consider all tests
1961
     *                              1 for active <> -1
1962
     *                              0 for active <> 0
1963
     * @param int $into_lp  1 for all exercises
1964
     *                      0 for without LP
1965
     * @internal param \Student $mixed id
1966
     * @internal param \Course $string code
1967
     * @internal param \Exercise $int id (optional), filtered by exercise
1968
     * @internal param \Session $int id (optional), if param $session_id is null
1969
     * it'll return results including sessions, 0 = session is not filtered
1970
     * @return   string    value (number %) Which represents a round integer about the score average.
1971
     */
1972
    public static function get_avg_student_exercise_score(
1973
        $student_id,
1974
        $course_code,
1975
        $exercise_id = 0,
1976
        $session_id = null,
1977
        $active_filter = 1,
1978
        $into_lp = 0
1979
    ) {
1980
        $course_code = Database::escape_string($course_code);
1981
        $course_info = api_get_course_info($course_code);
1982
        if (!empty($course_info)) {
1983
            // table definition
1984
            $tbl_course_quiz = Database::get_course_table(TABLE_QUIZ_TEST);
1985
            $tbl_stats_exercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1986
1987
            // Compose a filter based on optional exercise given
1988
            $condition_quiz = "";
1989
            if (!empty($exercise_id)) {
1990
                $exercise_id = intval($exercise_id);
1991
                $condition_quiz = " AND id = $exercise_id ";
1992
            }
1993
1994
            // Compose a filter based on optional session id given
1995
            $condition_session = '';
1996
            if (isset($session_id)) {
1997
                $session_id = intval($session_id);
1998
                $condition_session = " AND session_id = $session_id ";
1999
            }
2000
            if ($active_filter == 1) {
2001
                $condition_active = 'AND active <> -1';
2002
            } elseif ($active_filter == 0) {
2003
                $condition_active = 'AND active <> 0';
2004
            } else {
2005
                $condition_active = '';
2006
            }
2007
            $condition_into_lp = '';
2008
            $select_lp_id = '';
2009
            if ($into_lp == 0) {
2010
                $condition_into_lp = 'AND orig_lp_id = 0 AND orig_lp_item_id = 0';
2011
            } else {
2012
                $select_lp_id = ', orig_lp_id as lp_id ';
2013
            }
2014
2015
            $sql = "SELECT count(id) 
2016
    		        FROM $tbl_course_quiz
2017
    				WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz ";
2018
            $count_quiz = 0;
2019
            $countQuizResult = Database::query($sql);
2020
            if (!empty($countQuizResult)) {
2021
                $count_quiz = Database::fetch_row($countQuizResult);
2022
            }
2023
2024
            if (!empty($count_quiz[0]) && !empty($student_id)) {
2025
                if (is_array($student_id)) {
2026
                    $student_id = array_map('intval', $student_id);
2027
                    $condition_user = " AND exe_user_id IN (".implode(',', $student_id).") ";
2028
                } else {
2029
                    $student_id = intval($student_id);
2030
                    $condition_user = " AND exe_user_id = '$student_id' ";
2031
                }
2032
2033
                if (empty($exercise_id)) {
2034
                    $sql = "SELECT id FROM $tbl_course_quiz
2035
                            WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz";
2036
                    $result = Database::query($sql);
2037
                    $exercise_list = array();
2038
                    $exercise_id = null;
2039
                    if (!empty($result) && Database::num_rows($result)) {
2040
                        while ($row = Database::fetch_array($result)) {
2041
                            $exercise_list[] = $row['id'];
2042
                        }
2043
                    }
2044
                    if (!empty($exercise_list)) {
2045
                        $exercise_id = implode("','", $exercise_list);
2046
                    }
2047
                }
2048
2049
                $count_quiz = Database::fetch_row(Database::query($sql));
2050
                $sql = "SELECT
2051
                        SUM(exe_result/exe_weighting*100) as avg_score,
2052
                        COUNT(*) as num_attempts
2053
                        $select_lp_id
2054
                        FROM $tbl_stats_exercise
2055
                        WHERE
2056
                            exe_exo_id IN ('".$exercise_id."')
2057
                            $condition_user AND
2058
                            status = '' AND
2059
                            c_id = {$course_info['real_id']}
2060
                            $condition_session
2061
                            $condition_into_lp
2062
                        ORDER BY exe_date DESC";
2063
2064
                $res = Database::query($sql);
2065
                $row = Database::fetch_array($res);
2066
                $quiz_avg_score = null;
2067
2068
                if (!empty($row['avg_score'])) {
2069
                    $quiz_avg_score = round($row['avg_score'], 2);
2070
                }
2071
2072
                if (!empty($row['num_attempts'])) {
2073
                    $quiz_avg_score = round($quiz_avg_score / $row['num_attempts'], 2);
2074
                }
2075
                if (is_array($student_id)) {
2076
                    $quiz_avg_score = round($quiz_avg_score / count($student_id), 2);
2077
                }
2078
                if ($into_lp == 0) {
2079
                    return $quiz_avg_score;
2080
                } else {
2081
                    if (!empty($row['lp_id'])) {
2082
                        $tbl_lp = Database::get_course_table(TABLE_LP_MAIN);
2083
                        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2084
                        $sql = "SELECT lp.name
2085
                                FROM $tbl_lp as lp, $tbl_course as c
2086
                                WHERE
2087
                                    c.code = '$course_code' AND
2088
                                    lp.id = ".$row['lp_id']." AND
2089
                                    lp.c_id = c.id
2090
                                LIMIT 1;
2091
                        ";
2092
                        $result = Database::query($sql);
2093
                        $row_lp = Database::fetch_row($result);
2094
                        $lp_name = $row_lp[0];
2095
                        return array($quiz_avg_score, $lp_name);
2096
                    } else {
2097
                        return array($quiz_avg_score, null);
2098
                    }
2099
                }
2100
            }
2101
        }
2102
        return null;
2103
    }
2104
2105
    /**
2106
     * Get count student's exercise COMPLETED attempts
2107
     * @param int $student_id
2108
     * @param int $courseId
2109
     * @param int $exercise_id
2110
     * @param int $lp_id
2111
     * @param int $lp_item_id
2112
     * @param int $session_id
2113
     * @param int $find_all_lp  0 = just LP specified
2114
     *                          1 = LP specified or whitout LP,
2115
     *                          2 = all rows
2116
     * @internal param \Student $int id
2117
     * @internal param \Course $string code
2118
     * @internal param \Exercise $int id
2119
     * @internal param \Learning $int path id (optional),
2120
     * for showing attempts inside a learning path $lp_id and $lp_item_id params are required.
2121
     * @internal param \Learning $int path item id (optional),
2122
     * for showing attempts inside a learning path $lp_id and $lp_item_id params are required.
2123
     * @return  int     count of attempts
2124
     */
2125
    public static function count_student_exercise_attempts(
2126
        $student_id,
2127
        $courseId,
2128
        $exercise_id,
2129
        $lp_id = 0,
2130
        $lp_item_id = 0,
2131
        $session_id = 0,
2132
        $find_all_lp = 0
2133
    ) {
2134
        $courseId = intval($courseId);
2135
        $student_id = intval($student_id);
2136
        $exercise_id = intval($exercise_id);
2137
        $session_id = intval($session_id);
2138
2139
        $lp_id = intval($lp_id);
2140
        $lp_item_id = intval($lp_item_id);
2141
        $tbl_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2142
2143
        $sql = "SELECT COUNT(ex.exe_id) as essais 
2144
                FROM $tbl_stats_exercises AS ex
2145
                WHERE  
2146
                    ex.c_id = $courseId AND 
2147
                    ex.exe_exo_id = $exercise_id AND 
2148
                    status = '' AND 
2149
                    exe_user_id= $student_id AND 
2150
                    session_id = $session_id ";
2151
2152
        if ($find_all_lp == 1) {
2153
            $sql .= "AND (orig_lp_id = $lp_id OR orig_lp_id = 0)
2154
                AND (orig_lp_item_id = $lp_item_id OR orig_lp_item_id = 0)";
2155
        } elseif ($find_all_lp == 0) {
2156
            $sql .= "AND orig_lp_id = $lp_id
2157
                AND orig_lp_item_id = $lp_item_id";
2158
        }
2159
2160
        $rs = Database::query($sql);
2161
        $row = Database::fetch_row($rs);
2162
        $count_attempts = $row[0];
2163
2164
        return $count_attempts;
2165
    }
2166
2167
    /**
2168
     * Get count student's exercise progress
2169
     *
2170
     * @param array $exercise_list
2171
     * @param int $user_id
2172
     * @param int $courseId
2173
     * @param int $session_id
2174
     *
2175
     * @return string
2176
     */
2177
    public static function get_exercise_student_progress(
2178
        $exercise_list,
2179
        $user_id,
2180
        $courseId,
2181
        $session_id
2182
    ) {
2183
        $courseId = intval($courseId);
2184
        $user_id = intval($user_id);
2185
        $session_id = intval($session_id);
2186
2187
        if (empty($exercise_list)) {
2188
            return '0%';
2189
        }
2190
        $tbl_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2191
        $exercise_list = array_keys($exercise_list);
2192
        $exercise_list = array_map('intval', $exercise_list);
2193
2194
        $exercise_list_imploded = implode("' ,'", $exercise_list);
2195
2196
        $sql = "SELECT COUNT(DISTINCT ex.exe_exo_id)
2197
                FROM $tbl_stats_exercises AS ex
2198
                WHERE
2199
                    ex.c_id = $courseId AND
2200
                    ex.session_id  = $session_id AND
2201
                    ex.exe_user_id = $user_id AND
2202
                    ex.exe_exo_id IN ('$exercise_list_imploded') ";
2203
2204
        $rs = Database::query($sql);
2205
        $count = 0;
2206
        if ($rs) {
2207
            $row = Database::fetch_row($rs);
2208
            $count = $row[0];
2209
        }
2210
        $count = ($count != 0) ? 100 * round(intval($count) / count($exercise_list), 2).'%' : '0%';
2211
        return $count;
2212
    }
2213
2214
    /**
2215
     * @param array $exercise_list
2216
     * @param int $user_id
2217
     * @param int $courseId
2218
     * @param int $session_id
2219
     * @return string
2220
     */
2221 View Code Duplication
    public static function get_exercise_student_average_best_attempt(
2222
        $exercise_list,
2223
        $user_id,
2224
        $courseId,
2225
        $session_id
2226
    ) {
2227
        $result = 0;
2228
        if (!empty($exercise_list)) {
2229
            foreach ($exercise_list as $exercise_data) {
2230
                $exercise_id = $exercise_data['id'];
2231
                $best_attempt = Event::get_best_attempt_exercise_results_per_user(
2232
                    $user_id,
2233
                    $exercise_id,
2234
                    $courseId,
2235
                    $session_id
2236
                );
2237
2238
                if (!empty($best_attempt) && !empty($best_attempt['exe_weighting'])) {
2239
                    $result += $best_attempt['exe_result'] / $best_attempt['exe_weighting'];
2240
                }
2241
            }
2242
            $result = $result / count($exercise_list);
2243
            $result = round($result, 2) * 100;
2244
        }
2245
2246
        return $result.'%';
2247
    }
2248
2249
    /**
2250
     * get teacher progress by course and session
2251
     * @param int course id
2252
     * @param int session id
2253
     * @return array
2254
     */
2255
    static function get_teachers_progress_by_course($courseId, $sessionId)
2256
    {
2257
        $course = api_get_course_info_by_id($courseId);
2258
        $sessionId = intval($sessionId);
2259
        $courseId = intval($courseId);
2260
2261
        $sessionCourseUserTable = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2262
        $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
2263
2264
        //get teachers
2265
        $sql = "SELECT scu.session_id, scu.user_id, s.name
2266
                FROM $sessionCourseUserTable scu, $sessionTable s
2267
                WHERE
2268
                    scu.session_id = s.id
2269
                    AND scu.status = 2
2270
                    AND scu.visibility = 1
2271
                    AND scu.c_id = '%s'
2272
                    AND scu.session_id = %s";
2273
        $query = sprintf($sql, intval($courseId), $sessionId);
2274
        $rs = Database::query($query);
2275
        $teachers = array();
2276
        while ($teacher = Database::fetch_array($rs, 'ASSOC')) {
2277
            $teachers[] = $teacher;
2278
        }
2279
        $data = array();
2280
        foreach ($teachers as $teacher) {
2281
            //total documents added
2282
            $sql = "SELECT count(*) as total
2283
                    FROM c_item_property
2284
                    WHERE lastedit_type = 'DocumentAdded'
2285
                    AND c_id = %s
2286
                    AND insert_user_id = %s
2287
                    AND session_id = %s";
2288
            $query = sprintf(
2289
                $sql,
2290
                $courseId,
2291
                $teacher['user_id'],
2292
                $teacher['session_id']
2293
            );
2294
2295
            $rs = Database::query($query);
2296
            $totalDocuments = 0;
2297
            if ($rs) {
2298
                $row = Database::fetch_row($rs);
2299
                $totalDocuments = $row[0];
2300
            }
2301
            // Total links added
2302
            $sql = "SELECT count(*) as total
2303
                    FROM c_item_property
2304
                    WHERE lastedit_type = 'LinkAdded'
2305
                    AND c_id = %s
2306
                    AND insert_user_id = %s
2307
                    AND session_id = %s";
2308
            $query = sprintf(
2309
                $sql,
2310
                $courseId,
2311
                $teacher['user_id'],
2312
                $teacher['session_id']
2313
            );
2314
            $rs = Database::query($query);
2315
2316
            $totalLinks = 0;
2317
            if ($rs) {
2318
                $row = Database::fetch_row($rs);
2319
                $totalLinks = $row[0];
2320
            }
2321
            //total forums added
2322
            $sql = "SELECT count(*) as total
2323
                    FROM c_item_property
2324
                    WHERE lastedit_type = 'ForumthreadVisible'
2325
                    AND c_id = %s
2326
                    AND insert_user_id = %s
2327
                    AND session_id = %s";
2328
            $query = sprintf(
2329
                $sql,
2330
                $courseId,
2331
                $teacher['user_id'],
2332
                $teacher['session_id']
2333
            );
2334
            $rs = Database::query($query);
2335
2336
            $totalForums = 0;
2337
            if ($rs) {
2338
                $row = Database::fetch_row($rs);
2339
                $totalForums = $row[0];
2340
            }
2341
2342
            //total wikis added
2343
            $sql = "SELECT COUNT(DISTINCT(ref)) as total
2344
                    FROM c_item_property
2345
                    WHERE lastedit_type = 'WikiAdded'
2346
                    AND c_id = %s
2347
                    AND insert_user_id = %s
2348
                    AND session_id = %s";
2349
2350
            $query = sprintf(
2351
                $sql,
2352
                $courseId,
2353
                $teacher['user_id'],
2354
                $teacher['session_id']
2355
            );
2356
2357
            $rs = Database::query($query);
2358
2359
            $totalWikis = 0;
2360
            if ($rs) {
2361
                $row = Database::fetch_row($rs);
2362
                $totalWikis = $row[0];
2363
            }
2364
2365
            // Total works added
2366
            $sql = "SELECT COUNT(*) as total
2367
                    FROM c_item_property
2368
                    WHERE lastedit_type = 'DirectoryCreated'
2369
                    AND tool = 'work'
2370
                    AND c_id = %s
2371
                    AND insert_user_id = %s
2372
                    AND session_id = %s";
2373
            $query = sprintf(
2374
                $sql,
2375
                $courseId,
2376
                $teacher['user_id'],
2377
                $teacher['session_id']
2378
            );
2379
            $rs = Database::query($query);
2380
2381
            $totalWorks = 0;
2382
            if ($rs) {
2383
                $row = Database::fetch_row($rs);
2384
                $totalWorks = $row[0];
2385
            }
2386
            //total announcements added
2387
            $sql = "SELECT COUNT(*) as total
2388
                    FROM c_item_property
2389
                    WHERE lastedit_type = 'AnnouncementAdded'
2390
                    AND c_id = %s
2391
                    AND insert_user_id = %s
2392
                    AND session_id = %s";
2393
            $query = sprintf(
2394
                $sql,
2395
                $courseId,
2396
                $teacher['user_id'],
2397
                $teacher['session_id']
2398
            );
2399
            $rs = Database::query($query);
2400
2401
            $totalAnnouncements = 0;
2402
            if ($rs) {
2403
                $row = Database::fetch_row($rs);
2404
                $totalAnnouncements = $row[0];
2405
            }
2406
            $tutor = api_get_user_info($teacher['user_id']);
2407
            $data[] = array(
2408
                'course' => $course['title'],
2409
                'session' => $teacher['name'],
2410
                'tutor' => $tutor['username'].' - '.$tutor['lastname'].' '.$tutor['firstname'],
2411
                'documents' => $totalDocuments,
2412
                'links' => $totalLinks,
2413
                'forums' => $totalForums,
2414
                'works' => $totalWorks,
2415
                'wikis' => $totalWikis,
2416
                'announcements' => $totalAnnouncements,
2417
            );
2418
        }
2419
2420
        return $data;
2421
    }
2422
2423
    /**
2424
     * Returns the average student progress in the learning paths of the given
2425
     * course, it will take into account the progress that were not started.
2426
     * @param int|array $studentId
2427
     * @param string $courseCode
2428
     * @param array $lpIdList Limit average to listed lp ids
2429
     * @param int $sessionId     Session id (optional),
2430
     * if parameter $session_id is null(default) it'll return results including
2431
     * sessions, 0 = session is not filtered
2432
     * @param bool $returnArray Will return an array of the type:
2433
     * [sum_of_progresses, number] if it is set to true
2434
     * @param boolean $onlySeriousGame Optional. Limit average to lp on seriousgame mode
2435
     * @return double Average progress of the user in this course
2436
     */
2437
    public static function get_avg_student_progress(
2438
        $studentId,
2439
        $courseCode = null,
2440
        $lpIdList = array(),
2441
        $sessionId = null,
2442
        $returnArray = false,
2443
        $onlySeriousGame = false
2444
    ) {
2445
        // If there is at least one learning path and one student.
2446
        if (empty($studentId)) {
2447
            return false;
2448
        }
2449
2450
        $sessionId = intval($sessionId);
2451
        $courseInfo = api_get_course_info($courseCode);
2452
2453
        if (empty($courseInfo)) {
2454
            return false;
2455
        }
2456
2457
        $lPTable = Database::get_course_table(TABLE_LP_MAIN);
2458
        $lpViewTable = Database::get_course_table(TABLE_LP_VIEW);
2459
        $lpConditions = [];
2460
        $lpConditions['c_id = ? '] = $courseInfo['real_id'];
2461
2462
        if ($sessionId > 0) {
2463
            $lpConditions['AND (session_id = ? OR session_id = 0 OR session_id IS NULL)'] = $sessionId;
2464
        } else {
2465
            $lpConditions['AND session_id = ?'] = $sessionId;
2466
        }
2467
2468
        if (is_array($lpIdList) && count($lpIdList) > 0) {
2469
            $placeHolders = [];
2470
            for ($i = 0; $i < count($lpIdList); $i++) {
2471
                $placeHolders[] = '?';
2472
            }
2473
            $lpConditions['AND id IN('.implode(', ', $placeHolders).') '] = $lpIdList;
2474
        }
2475
2476
        if ($onlySeriousGame) {
2477
            $lpConditions['AND seriousgame_mode = ? '] = true;
2478
        }
2479
2480
        $resultLP = Database::select(
2481
            'id',
2482
            $lPTable,
2483
            ['where' => $lpConditions]
2484
        );
2485
        $filteredLP = array_keys($resultLP);
2486
2487
        if (empty($filteredLP)) {
2488
            return false;
2489
        }
2490
2491
        $conditions = [
2492
            " c_id = {$courseInfo['real_id']} ",
2493
            " lp_view.lp_id IN(".implode(', ', $filteredLP).") "
2494
        ];
2495
2496
        $groupBy = 'GROUP BY lp_id';
2497
2498
        if (is_array($studentId)) {
2499
            $studentId = array_map('intval', $studentId);
2500
            $conditions[] = " lp_view.user_id IN (".implode(',', $studentId).")  ";
2501
        } else {
2502
            $studentId = intval($studentId);
2503
            $conditions[] = " lp_view.user_id = '$studentId' ";
2504
2505
            if (empty($lpIdList)) {
2506
                $lpList = new LearnpathList(
2507
                    $studentId,
2508
                    $courseCode,
2509
                    $sessionId,
2510
                    null,
2511
                    false,
2512
                    null,
2513
                    true
2514
                );
2515
                $lpList = $lpList->get_flat_list();
2516
                if (!empty($lpList)) {
2517
                    /** @var  $lp */
2518
                    foreach ($lpList as $lpId => $lp) {
2519
                        $lpIdList[] = $lpId;
2520
                    }
2521
                }
2522
            }
2523
        }
2524
2525
        if (!empty($sessionId)) {
2526
            $conditions[] = " session_id = $sessionId ";
2527
        }
2528
2529
        $conditionToString = implode('AND', $conditions);
2530
        $sql = "
2531
            SELECT lp_id, view_count, progress 
2532
            FROM $lpViewTable lp_view
2533
            WHERE
2534
                $conditionToString
2535
                $groupBy
2536
            ORDER BY view_count DESC
2537
        ";
2538
2539
        $result = Database::query($sql);
2540
2541
        $progress = array();
2542
        $viewCount = array();
2543 View Code Duplication
        while ($row = Database::fetch_array($result, 'ASSOC')) {
2544
            if (!isset($viewCount[$row['lp_id']])) {
2545
                $progress[$row['lp_id']] = $row['progress'];
2546
            }
2547
            $viewCount[$row['lp_id']] = $row['view_count'];
2548
        }
2549
2550
        // Fill with lp ids
2551
        if (!empty($lpIdList)) {
2552
            foreach ($lpIdList as $lpId) {
2553
                if (!isset($progress[$lpId])) {
2554
                    $progress[$lpId] = 0;
2555
                }
2556
            }
2557
        }
2558
2559
        if (!empty($progress)) {
2560
            $sum = array_sum($progress);
2561
            $average = $sum / count($lpIdList);
2562
        } else {
2563
            $average = 0;
2564
            $sum = 0;
2565
        }
2566
2567
        if ($returnArray) {
2568
            return [
2569
                $sum,
2570
                count($lpIdList)
2571
            ];
2572
        }
2573
2574
        return round($average, 1);
2575
    }
2576
2577
    /**
2578
     * This function gets:
2579
     * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores.
2580
     * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores.
2581
     * 3. And finally it will return the average between 1. and 2.
2582
     * @todo improve performance, when loading 1500 users with 20 lps the script dies
2583
     * This function does not take the results of a Test out of a LP
2584
     *
2585
     * @param mixed $student_id Array of user ids or an user id
2586
     * @param string $course_code
2587
     * @param array $lp_ids List of LP ids
2588
     * @param int $session_id Session id (optional),
2589
     * if param $session_id is null(default) it'll return results
2590
     * including sessions, 0 = session is not filtered
2591
     * @param bool $return_array Returns an array of the
2592
     * type [sum_score, num_score] if set to true
2593
     * @param bool $get_only_latest_attempt_results get only the latest attempts or ALL attempts
2594
     * @param bool $getOnlyBestAttempt
2595
     *
2596
     * @return  string      Value (number %) Which represents a round integer explain in got in 3.
2597
     */
2598
    public static function get_avg_student_score(
2599
        $student_id,
2600
        $course_code,
2601
        $lp_ids = array(),
2602
        $session_id = null,
2603
        $return_array = false,
2604
        $get_only_latest_attempt_results = false,
2605
        $getOnlyBestAttempt = false
2606
    ) {
2607
        $debug = false;
2608
        if ($debug) echo '<h1>Tracking::get_avg_student_score</h1>';
2609
        $tbl_stats_exercices = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2610
        $tbl_stats_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
2611
        $course = api_get_course_info($course_code);
2612
        if (!empty($course)) {
2613
            // Get course tables names
2614
            $tbl_quiz_questions = Database::get_course_table(TABLE_QUIZ_QUESTION);
2615
            $lp_table = Database::get_course_table(TABLE_LP_MAIN);
2616
            $lp_item_table = Database::get_course_table(TABLE_LP_ITEM);
2617
            $lp_view_table = Database::get_course_table(TABLE_LP_VIEW);
2618
            $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW);
2619
            $course_id = $course['real_id'];
2620
2621
            // Compose a filter based on optional learning paths list given
2622
            $condition_lp = '';
2623 View Code Duplication
            if (count($lp_ids) > 0) {
2624
                $condition_lp = " AND id IN(".implode(',', $lp_ids).") ";
2625
            }
2626
2627
            // Compose a filter based on optional session id
2628
            $session_id = intval($session_id);
2629
            if (count($lp_ids) > 0) {
2630
                $condition_session = " AND session_id = $session_id ";
2631
            } else {
2632
                $condition_session = " WHERE session_id = $session_id ";
2633
            }
2634
2635
            // Check the real number of LPs corresponding to the filter in the
2636
            // database (and if no list was given, get them all)
2637
2638
            if (empty($session_id)) {
2639
                $sql = "SELECT DISTINCT(id), use_max_score
2640
                        FROM $lp_table
2641
                        WHERE c_id = $course_id AND (session_id = 0 OR session_id IS NULL ) $condition_lp ";
2642
            } else {
2643
                $sql = "SELECT DISTINCT(id), use_max_score
2644
                        FROM $lp_table
2645
                        WHERE c_id = $course_id $condition_lp ";
2646
            }
2647
2648
            $res_row_lp = Database::query($sql);
2649
            $count_row_lp = Database::num_rows($res_row_lp);
2650
2651
            $lp_list = $use_max_score = array();
2652
            while ($row_lp = Database::fetch_array($res_row_lp)) {
2653
                $lp_list[] = $row_lp['id'];
2654
                $use_max_score[$row_lp['id']] = $row_lp['use_max_score'];
2655
            }
2656
2657
            if ($debug) {
2658
                echo '$lp_list: ';
2659
                var_dump($lp_list);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($lp_list); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
2660
                echo 'Use max score or not list: ';
2661
                var_dump($use_max_score);
2662
            }
2663
2664
            // prepare filter on users
2665 View Code Duplication
            if (is_array($student_id)) {
2666
                array_walk($student_id, 'intval');
2667
                $condition_user1 = " AND user_id IN (".implode(',', $student_id).") ";
2668
            } else {
2669
                $condition_user1 = " AND user_id = $student_id ";
2670
            }
2671
2672
            if ($count_row_lp > 0 && !empty($student_id)) {
2673
                // Getting latest LP result for a student
2674
                //@todo problem when a  course have more than 1500 users
2675
                $sql = "SELECT MAX(view_count) as vc, id, progress, lp_id, user_id
2676
                        FROM $lp_view_table
2677
                        WHERE
2678
                            c_id = $course_id AND
2679
                            lp_id IN (".implode(',', $lp_list).")
2680
                            $condition_user1 AND
2681
                            session_id = $session_id
2682
                        GROUP BY lp_id, user_id";
2683
                if ($debug) {
2684
                    echo 'get LP results';
2685
                    var_dump($sql);
2686
                }
2687
2688
                $rs_last_lp_view_id = Database::query($sql);
2689
                $global_result = 0;
2690
2691
                if (Database::num_rows($rs_last_lp_view_id) > 0) {
2692
                    // Cycle through each line of the results (grouped by lp_id, user_id)
2693
                    while ($row_lp_view = Database::fetch_array($rs_last_lp_view_id)) {
2694
                        $count_items = 0;
2695
                        $lpPartialTotal = 0;
2696
                        $list = array();
2697
                        $lp_view_id = $row_lp_view['id'];
2698
                        $lp_id = $row_lp_view['lp_id'];
2699
                        $user_id = $row_lp_view['user_id'];
2700
2701
                        if ($debug) {
2702
                            echo '<h2>LP id '.$lp_id.'</h2>';
2703
                            echo "get_only_latest_attempt_results: $get_only_latest_attempt_results <br />";
2704
                            echo "getOnlyBestAttempt: $getOnlyBestAttempt <br />";
2705
                        }
2706
2707
                        if ($get_only_latest_attempt_results || $getOnlyBestAttempt) {
2708
                            // Getting lp_items done by the user
2709
                            $sql = "SELECT DISTINCT lp_item_id
2710
                                    FROM $lp_item_view_table
2711
                                    WHERE
2712
                                        c_id = $course_id AND
2713
                                        lp_view_id = $lp_view_id
2714
                                    ORDER BY lp_item_id";
2715
                            $res_lp_item = Database::query($sql);
2716
                            if ($debug) {
2717
                                echo 'Getting lp_items done by the user<br />';
2718
                                var_dump($sql);
2719
                            }
2720
2721
                            while ($row_lp_item = Database::fetch_array($res_lp_item, 'ASSOC')) {
2722
                                $my_lp_item_id = $row_lp_item['lp_item_id'];
2723
                                $order = ' view_count DESC';
2724
                                if ($getOnlyBestAttempt) {
2725
                                    $order = ' lp_iv.score DESC';
2726
                                }
2727
2728
                                // Getting the most recent attempt
2729
                                $sql = "SELECT  lp_iv.id as lp_item_view_id,
2730
                                                lp_iv.score as score,
2731
                                                lp_i.max_score,
2732
                                                lp_iv.max_score as max_score_item_view,
2733
                                                lp_i.path,
2734
                                                lp_i.item_type,
2735
                                                lp_i.id as iid
2736
                                        FROM $lp_item_view_table as lp_iv
2737
                                        INNER JOIN $lp_item_table as lp_i
2738
                                        ON (lp_i.id = lp_iv.lp_item_id AND lp_iv.c_id = lp_i.c_id)                                            
2739
                                        WHERE
2740
                                            lp_iv.c_id = $course_id AND
2741
                                            lp_i.c_id  = $course_id AND
2742
                                            lp_item_id = $my_lp_item_id AND
2743
                                            lp_view_id = $lp_view_id AND
2744
                                            (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."')
2745
                                        ORDER BY $order
2746
                                        LIMIT 1";
2747
2748
                                $res_lp_item_result = Database::query($sql);
2749
                                while ($row_max_score = Database::fetch_array($res_lp_item_result, 'ASSOC')) {
2750
                                    $list[] = $row_max_score;
2751
                                }
2752
                            }
2753
                        } else {
2754
                            // For the currently analysed view, get the score and
2755
                            // max_score of each item if it is a sco or a TOOL_QUIZ
2756
                            $sql = "SELECT
2757
                                        lp_iv.id as lp_item_view_id,
2758
                                        lp_iv.score as score,
2759
                                        lp_i.max_score,
2760
                                        lp_iv.max_score as max_score_item_view,
2761
                                        lp_i.path,
2762
                                        lp_i.item_type,
2763
                                        lp_i.id as iid
2764
                                      FROM $lp_item_view_table as lp_iv
2765
                                      INNER JOIN $lp_item_table as lp_i
2766
                                      ON lp_i.id = lp_iv.lp_item_id AND
2767
                                         lp_iv.c_id = lp_i.c_id
2768
                                      WHERE 
2769
                                        lp_iv.c_id = $course_id AND 
2770
                                        lp_i.c_id  = $course_id AND
2771
                                        lp_view_id = $lp_view_id AND
2772
                                        (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."')
2773
                                    ";
2774
                            if ($debug) var_dump($sql);
2775
                            $res_max_score = Database::query($sql);
2776
2777
                            while ($row_max_score = Database::fetch_array($res_max_score, 'ASSOC')) {
2778
                                $list[] = $row_max_score;
2779
                            }
2780
                        }
2781
2782
                        if ($debug) var_dump($list);
2783
2784
                        // Go through each scorable element of this view
2785
                        $score_of_scorm_calculate = 0;
2786
                        foreach ($list as $row_max_score) {
2787
                            // Came from the original lp_item
2788
                            $max_score = $row_max_score['max_score'];
2789
                            // Came from the lp_item_view
2790
                            $max_score_item_view = $row_max_score['max_score_item_view'];
2791
                            $score = $row_max_score['score'];
2792
2793
                            if ($debug) echo '<h3>Item Type: '.$row_max_score['item_type'].'</h3>';
2794
2795
                            if ($row_max_score['item_type'] == 'sco') {
2796
                                /* Check if it is sco (easier to get max_score)
2797
                                   when there's no max score, we assume 100 as the max score,
2798
                                   as the SCORM 1.2 says that the value should always be between 0 and 100.
2799
                                */
2800
                                if ($max_score == 0 || is_null($max_score) || $max_score == '') {
2801
                                    // Chamilo style
2802
                                    if ($use_max_score[$lp_id]) {
2803
                                        $max_score = 100;
2804
                                    } else {
2805
                                        // Overwrites max score = 100 to use the one that came in the lp_item_view see BT#1613
2806
                                        $max_score = $max_score_item_view;
2807
                                    }
2808
                                }
2809
                                // Avoid division by zero errors
2810
                                if (!empty($max_score)) {
2811
                                    $lpPartialTotal += $score / $max_score;
2812
                                }
2813
                                if ($debug) {
2814
                                    var_dump("lpPartialTotal: $lpPartialTotal");
2815
                                    var_dump("score: $score");
2816
                                    var_dump("max_score: $max_score");
2817
                                }
2818
                            } else {
2819
                                // Case of a TOOL_QUIZ element
2820
                                $item_id = $row_max_score['iid'];
2821
                                $item_path = $row_max_score['path'];
2822
                                $lp_item_view_id = $row_max_score['lp_item_view_id'];
2823
2824
                                // Get last attempt to this exercise through
2825
                                // the current lp for the current user
2826
                                $order = 'exe_date DESC';
2827
                                if ($getOnlyBestAttempt) {
2828
                                    $order = 'exe_result DESC';
2829
                                }
2830
                                $sql = "SELECT exe_id, exe_result
2831
                                        FROM $tbl_stats_exercices
2832
                                        WHERE
2833
                                            exe_exo_id           = '$item_path' AND
2834
                                            exe_user_id          = $user_id AND
2835
                                            orig_lp_item_id      = $item_id AND
2836
                                            orig_lp_item_view_id = $lp_item_view_id AND
2837
                                            c_id                 = $course_id AND
2838
                                            session_id           = $session_id AND
2839
                                            status = ''
2840
                                        ORDER BY $order
2841
                                        LIMIT 1";
2842
2843
                                $result_last_attempt = Database::query($sql);
2844
                                if ($debug) var_dump($sql);
2845
                                $num = Database::num_rows($result_last_attempt);
2846
                                if ($num > 0) {
2847
                                    $attemptResult = Database::fetch_array($result_last_attempt, 'ASSOC');
2848
                                    $id_last_attempt = $attemptResult['exe_id'];
2849
                                    // We overwrite the score with the best one not the one saved in the LP (latest)
2850
                                    if ($getOnlyBestAttempt && $get_only_latest_attempt_results == false) {
2851
                                        if ($debug) echo "Following score comes from the track_exercise table not in the LP because the score is the best<br />";
2852
                                        $score = $attemptResult['exe_result'];
2853
                                    }
2854
2855
                                    if ($debug) echo "Attempt id: $id_last_attempt with score $score<br />";
2856
                                    // Within the last attempt number tracking, get the sum of
2857
                                    // the max_scores of all questions that it was
2858
                                    // made of (we need to make this call dynamic because of random questions selection)
2859
                                    $sql = "SELECT SUM(t.ponderation) as maxscore FROM
2860
                                            (
2861
                                                SELECT DISTINCT
2862
                                                    question_id,
2863
                                                    marks,
2864
                                                    ponderation
2865
                                                FROM $tbl_stats_attempts AS at
2866
                                                INNER JOIN $tbl_quiz_questions AS q
2867
                                                ON (q.id = at.question_id AND q.c_id = q.c_id)
2868
                                                WHERE
2869
                                                    exe_id ='$id_last_attempt' AND
2870
                                                    q.c_id = $course_id
2871
                                            )
2872
                                            AS t";
2873
2874
                                    $res_max_score_bis = Database::query($sql);
2875
                                    $row_max_score_bis = Database::fetch_array($res_max_score_bis);
2876
2877
                                    if (!empty($row_max_score_bis['maxscore'])) {
2878
                                        $max_score = $row_max_score_bis['maxscore'];
2879
                                    }
2880
                                    if (!empty($max_score) && floatval($max_score) > 0) {
2881
                                        $lpPartialTotal += $score / $max_score;
2882
                                    }
2883
                                    if ($debug) {
2884
                                        var_dump("score: $score");
2885
                                        var_dump("max_score: $max_score");
2886
                                        var_dump("lpPartialTotal: $lpPartialTotal");
2887
                                    }
2888
                                }
2889
                            }
2890
2891
                            if (in_array($row_max_score['item_type'], array('quiz', 'sco'))) {
2892
                                // Normal way
2893
                                if ($use_max_score[$lp_id]) {
2894
                                    $count_items++;
2895
                                } else {
2896
                                    if ($max_score != '') {
2897
                                        $count_items++;
2898
                                    }
2899
                                }
2900
                                if ($debug) echo '$count_items: '.$count_items;
2901
                            }
2902
                        } //end for
2903
2904
                        $score_of_scorm_calculate += $count_items ? (($lpPartialTotal / $count_items) * 100) : 0;
2905
                        $global_result += $score_of_scorm_calculate;
2906
2907
                        if ($debug) {
2908
                            var_dump("count_items: $count_items");
2909
                            var_dump("score_of_scorm_calculate: $score_of_scorm_calculate");
2910
                            var_dump("global_result: $global_result");
2911
                        }
2912
                    } // end while
2913
                }
2914
2915
                $lp_with_quiz = 0;
2916
                foreach ($lp_list as $lp_id) {
2917
                    // Check if LP have a score we assume that all SCO have an score
2918
                    $sql = "SELECT count(id) as count
2919
                            FROM $lp_item_table
2920
                            WHERE
2921
                                c_id = $course_id AND
2922
                                (item_type = 'quiz' OR item_type = 'sco') AND
2923
                                lp_id = ".$lp_id;
2924
                    if ($debug) {
2925
                        var_dump($sql);
2926
                    }
2927
                    $result_have_quiz = Database::query($sql);
2928
                    if (Database::num_rows($result_have_quiz) > 0) {
2929
                        $row = Database::fetch_array($result_have_quiz, 'ASSOC');
2930
                        if (is_numeric($row['count']) && $row['count'] != 0) {
2931
                            $lp_with_quiz++;
2932
                        }
2933
                    }
2934
                }
2935
2936
                if ($debug) echo '<h3>$lp_with_quiz '.$lp_with_quiz.' </h3>';
2937
                if ($debug) echo '<h3>Final return</h3>';
2938
2939
                if ($lp_with_quiz != 0) {
2940
                    if (!$return_array) {
2941
                        $score_of_scorm_calculate = round(($global_result / $lp_with_quiz), 2);
2942
                        if ($debug) var_dump($score_of_scorm_calculate);
2943
                        if (empty($lp_ids)) {
2944
                            if ($debug) echo '<h2>All lps fix: '.$score_of_scorm_calculate.'</h2>';
2945
                        }
2946
                        return $score_of_scorm_calculate;
2947
                    } else {
2948
                        if ($debug) var_dump($global_result, $lp_with_quiz);
2949
                        return array($global_result, $lp_with_quiz);
2950
                    }
2951
                } else {
2952
2953
                    return '-';
2954
                }
2955
            }
2956
        }
2957
2958
        return null;
2959
    }
2960
2961
    /**
2962
     * This function gets:
2963
     * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores.
2964
     * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores.
2965
     * 3. And finally it will return the average between 1. and 2.
2966
     * This function does not take the results of a Test out of a LP
2967
     *
2968
     * @param   int|array   Array of user ids or an user id
2969
     * @param   string      $course_code Course code
2970
     * @param   array       $lp_ids List of LP ids
2971
     * @param   int         $session_id Session id (optional), if param $session_id is 0(default)
2972
     * it'll return results including sessions, 0 = session is not filtered
2973
     * @param   bool        Returns an array of the type [sum_score, num_score] if set to true
2974
     * @param   bool        get only the latest attempts or ALL attempts
2975
     * @return  string      Value (number %) Which represents a round integer explain in got in 3.
2976
     */
2977
    public static function getAverageStudentScore(
2978
        $student_id,
2979
        $course_code = '',
2980
        $lp_ids = array(),
2981
        $session_id = 0
2982
    ) {
2983
        if (empty($student_id)) {
2984
            return 0;
2985
        }
2986
2987
        $conditions = array();
2988
        if (!empty($course_code)) {
2989
            $course = api_get_course_info($course_code);
2990
            $courseId = $course['real_id'];
2991
            $conditions[] = " c_id = $courseId";
2992
        }
2993
2994
        // Get course tables names
2995
        $lp_table = Database::get_course_table(TABLE_LP_MAIN);
2996
        $lp_item_table = Database::get_course_table(TABLE_LP_ITEM);
2997
        $lp_view_table = Database::get_course_table(TABLE_LP_VIEW);
2998
        $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW);
2999
3000
        // Compose a filter based on optional learning paths list given
3001
        if (!empty($lp_ids) && count($lp_ids) > 0) {
3002
            $conditions[] = " id IN(".implode(',', $lp_ids).") ";
3003
        }
3004
3005
        // Compose a filter based on optional session id
3006
        $session_id = intval($session_id);
3007
        if (!empty($session_id)) {
3008
            $conditions[] = " session_id = $session_id ";
3009
        }
3010
3011 View Code Duplication
        if (is_array($student_id)) {
3012
            array_walk($student_id, 'intval');
3013
            $conditions[] = " lp_view.user_id IN (".implode(',', $student_id).") ";
3014
        } else {
3015
            $conditions[] = " lp_view.user_id = $student_id ";
3016
        }
3017
3018
        $conditionsToString = implode('AND ', $conditions);
3019
        $sql = "SELECT
3020
                    SUM(lp_iv.score) sum_score,
3021
                    SUM(lp_i.max_score) sum_max_score
3022
                FROM $lp_table as lp
3023
                INNER JOIN $lp_item_table as lp_i
3024
                ON lp.id = lp_id AND lp.c_id = lp_i.c_id
3025
                INNER JOIN $lp_view_table as lp_view
3026
                ON lp_view.lp_id = lp_i.lp_id AND lp_view.c_id = lp_i.c_id
3027
                INNER JOIN $lp_item_view_table as lp_iv
3028
                ON lp_i.id = lp_iv.lp_item_id AND lp_view.c_id = lp_iv.c_id AND lp_iv.lp_view_id = lp_view.id
3029
                WHERE (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."') AND
3030
                $conditionsToString
3031
        ";
3032
        $result = Database::query($sql);
3033
        $row = Database::fetch_array($result, 'ASSOC');
3034
3035
        if (empty($row['sum_max_score'])) {
3036
            return 0;
3037
        }
3038
3039
        return ($row['sum_score'] / $row['sum_max_score']) * 100;
3040
    }
3041
3042
    /**
3043
     * This function gets time spent in learning path for a student inside a course
3044
     * @param int|array $student_id Student id(s)
3045
     * @param string $course_code Course code
3046
     * @param array $lp_ids Limit average to listed lp ids
3047
     * @param int $session_id Session id (optional), if param $session_id is null(default)
3048
     * it'll return results including sessions, 0 = session is not filtered
3049
     * @return int Total time
3050
     */
3051
    public static function get_time_spent_in_lp(
3052
        $student_id,
3053
        $course_code,
3054
        $lp_ids = array(),
3055
        $session_id = 0
3056
    ) {
3057
        $course = api_get_course_info($course_code);
3058
        $student_id = (int) $student_id;
3059
        $session_id = (int) $session_id;
3060
        $total_time = 0;
3061
3062
        if (!empty($course)) {
3063
            $lp_table = Database::get_course_table(TABLE_LP_MAIN);
3064
            $t_lpv = Database::get_course_table(TABLE_LP_VIEW);
3065
            $t_lpiv = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3066
            $course_id = $course['real_id'];
3067
3068
            // Compose a filter based on optional learning paths list given
3069
            $condition_lp = '';
3070 View Code Duplication
            if (count($lp_ids) > 0) {
3071
                $condition_lp = " AND id IN(".implode(',', $lp_ids).") ";
3072
            }
3073
3074
            // Check the real number of LPs corresponding to the filter in the
3075
            // database (and if no list was given, get them all)
3076
            $sql = "SELECT DISTINCT(id) FROM $lp_table 
3077
                    WHERE c_id = $course_id $condition_lp";
3078
            $res_row_lp = Database::query($sql);
3079
            $count_row_lp = Database::num_rows($res_row_lp);
3080
3081
            // calculates time
3082 View Code Duplication
            if ($count_row_lp > 0) {
3083
                while ($row_lp = Database::fetch_array($res_row_lp)) {
3084
                    $lp_id = intval($row_lp['id']);
3085
                    $sql = "SELECT SUM(total_time)
3086
                            FROM $t_lpiv AS item_view
3087
                            INNER JOIN $t_lpv AS view
3088
                            ON (
3089
                                item_view.lp_view_id = view.id AND
3090
                                item_view.c_id = view.c_id
3091
                            )
3092
                            WHERE
3093
                                item_view.c_id = $course_id AND
3094
                                view.c_id = $course_id AND
3095
                                view.lp_id = $lp_id AND
3096
                                view.user_id = $student_id AND
3097
                                session_id = $session_id";
3098
3099
                    $rs = Database::query($sql);
3100
                    if (Database::num_rows($rs) > 0) {
3101
                        $total_time += Database::result($rs, 0, 0);
3102
                    }
3103
                }
3104
            }
3105
        }
3106
3107
        return $total_time;
3108
    }
3109
3110
    /**
3111
     * This function gets last connection time to one learning path
3112
     * @param int|array $student_id Student id(s)
3113
     * @param string $course_code      Course code
3114
     * @param int $lp_id    Learning path id
3115
     * @param int $session_id
3116
     * @return int         Total time
3117
     */
3118
    public static function get_last_connection_time_in_lp(
3119
        $student_id,
3120
        $course_code,
3121
        $lp_id,
3122
        $session_id = 0
3123
    ) {
3124
        $course = api_get_course_info($course_code);
3125
        $student_id = intval($student_id);
3126
        $lp_id = intval($lp_id);
3127
        $last_time = 0;
3128
        $session_id = intval($session_id);
3129
3130
        if (!empty($course)) {
3131
            $course_id = $course['real_id'];
3132
            $lp_table = Database::get_course_table(TABLE_LP_MAIN);
3133
            $t_lpv = Database::get_course_table(TABLE_LP_VIEW);
3134
            $t_lpiv = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3135
3136
            // Check the real number of LPs corresponding to the filter in the
3137
            // database (and if no list was given, get them all)
3138
            $sql = "SELECT id FROM $lp_table 
3139
                    WHERE c_id = $course_id AND id = $lp_id ";
3140
            $res_row_lp = Database::query($sql);
3141
            $count_row_lp = Database::num_rows($res_row_lp);
3142
3143
            // calculates last connection time
3144
            if ($count_row_lp > 0) {
3145
                $sql = 'SELECT MAX(start_time)
3146
                        FROM ' . $t_lpiv.' AS item_view
3147
                        INNER JOIN ' . $t_lpv.' AS view
3148
                        ON (item_view.lp_view_id = view.id AND item_view.c_id = view.c_id)
3149
                        WHERE
3150
                            item_view.c_id = '.$course_id.' AND
3151
                            view.c_id = '.$course_id.' AND
3152
                            view.lp_id = '.$lp_id.' AND 
3153
                            view.user_id = '.$student_id.' AND 
3154
                            view.session_id = '.$session_id;
3155
                $rs = Database::query($sql);
3156
                if (Database::num_rows($rs) > 0) {
3157
                    $last_time = Database::result($rs, 0, 0);
3158
                }
3159
            }
3160
        }
3161
3162
        return $last_time;
3163
    }
3164
3165
    /**
3166
     * gets the list of students followed by coach
3167
     * @param     int     $coach_id Coach id
3168
     * @return     array     List of students
3169
     */
3170
    public static function get_student_followed_by_coach($coach_id)
3171
    {
3172
        $coach_id = intval($coach_id);
3173
3174
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3175
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3176
        $tbl_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
3177
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3178
3179
        $students = [];
3180
3181
        // At first, courses where $coach_id is coach of the course //
3182
        $sql = 'SELECT session_id, c_id
3183
                FROM ' . $tbl_session_course_user.'
3184
                WHERE user_id=' . $coach_id.' AND status=2';
3185
3186
        if (api_is_multiple_url_enabled()) {
3187
            $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3188
            $access_url_id = api_get_current_access_url_id();
3189
            if ($access_url_id != -1) {
3190
                $sql = 'SELECT scu.session_id, scu.c_id
3191
                        FROM '.$tbl_session_course_user.' scu
3192
                        INNER JOIN '.$tbl_session_rel_access_url.'  sru
3193
                        ON (scu.session_id=sru.session_id)
3194
                        WHERE
3195
                            scu.user_id=' . $coach_id.' AND
3196
                            scu.status=2 AND
3197
                            sru.access_url_id = '.$access_url_id;
3198
            }
3199
        }
3200
3201
        $result = Database::query($sql);
3202
3203 View Code Duplication
        while ($a_courses = Database::fetch_array($result)) {
3204
            $courseId = $a_courses['c_id'];
3205
            $id_session = $a_courses['session_id'];
3206
3207
            $sql = "SELECT DISTINCT srcru.user_id
3208
                    FROM $tbl_session_course_user AS srcru
3209
                    INNER JOIN $tbl_session_user sru
3210
                    ON (srcru.user_id = sru.user_id AND srcru.session_id = sru.session_id)
3211
                    WHERE
3212
                        sru.relation_type<>".SESSION_RELATION_TYPE_RRHH." AND
3213
                        srcru.c_id = '$courseId' AND
3214
                        srcru.session_id = '$id_session'";
3215
3216
            $rs = Database::query($sql);
3217
            while ($row = Database::fetch_array($rs)) {
3218
                $students[$row['user_id']] = $row['user_id'];
3219
            }
3220
        }
3221
3222
        // Then, courses where $coach_id is coach of the session    //
3223
        $sql = 'SELECT session_course_user.user_id
3224
                FROM '.$tbl_session_course_user.' as session_course_user
3225
                INNER JOIN '.$tbl_session_user.' sru
3226
                ON session_course_user.user_id = sru.user_id AND session_course_user.session_id = sru.session_id
3227
                INNER JOIN '.$tbl_session_course.' as session_course
3228
                ON session_course.c_id = session_course_user.c_id
3229
                AND session_course_user.session_id = session_course.session_id
3230
                INNER JOIN '.$tbl_session.' as session
3231
                ON session.id = session_course.session_id
3232
                AND session.id_coach = ' . $coach_id;
3233 View Code Duplication
        if (api_is_multiple_url_enabled()) {
3234
            $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3235
            $access_url_id = api_get_current_access_url_id();
3236
            if ($access_url_id != -1) {
3237
                $sql = 'SELECT session_course_user.user_id
3238
                        FROM '.$tbl_session_course_user.' as session_course_user
3239
                        INNER JOIN '.$tbl_session_user.' sru
3240
                        ON session_course_user.user_id = sru.user_id AND
3241
                           session_course_user.session_id = sru.session_id
3242
                        INNER JOIN '.$tbl_session_course.' as session_course
3243
                        ON session_course.c_id = session_course_user.c_id AND
3244
                        session_course_user.session_id = session_course.session_id
3245
                        INNER JOIN '.$tbl_session.' as session
3246
                        ON session.id = session_course.session_id AND
3247
                        session.id_coach = '.$coach_id.'
3248
                        INNER JOIN '.$tbl_session_rel_access_url.' session_rel_url
3249
                        ON session.id = session_rel_url.session_id 
3250
                        WHERE access_url_id = '.$access_url_id;
3251
            }
3252
        }
3253
3254
        $result = Database::query($sql);
3255
        while ($row = Database::fetch_array($result)) {
3256
            $students[$row['user_id']] = $row['user_id'];
3257
        }
3258
3259
        return $students;
3260
    }
3261
3262
    /**
3263
     * Get student followed by a coach inside a session
3264
     * @param    int        Session id
3265
     * @param    int        Coach id
3266
     * @return   array    students list
3267
     */
3268
    public static function get_student_followed_by_coach_in_a_session(
3269
        $id_session,
3270
        $coach_id
3271
    ) {
3272
        $coach_id = intval($coach_id);
3273
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3274
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3275
3276
        $students = [];
3277
        // At first, courses where $coach_id is coach of the course //
3278
        $sql = 'SELECT c_id FROM '.$tbl_session_course_user.'
3279
                WHERE session_id="' . $id_session.'" AND user_id='.$coach_id.' AND status=2';
3280
        $result = Database::query($sql);
3281
3282
        while ($a_courses = Database::fetch_array($result)) {
3283
            $courseId = $a_courses['c_id'];
3284
            $sql = "SELECT DISTINCT srcru.user_id
3285
                    FROM $tbl_session_course_user AS srcru
3286
                    WHERE
3287
                        c_id = '$courseId' AND
3288
                        session_id = '".$id_session."'";
3289
            $rs = Database::query($sql);
3290
            while ($row = Database::fetch_array($rs)) {
3291
                $students[$row['user_id']] = $row['user_id'];
3292
            }
3293
        }
3294
3295
        // Then, courses where $coach_id is coach of the session
3296
        $sql = 'SELECT id_coach FROM '.$tbl_session.'
3297
                WHERE id="' . $id_session.'" AND id_coach="'.$coach_id.'"';
3298
        $result = Database::query($sql);
3299
3300
        //He is the session_coach so we select all the users in the session
3301
        if (Database::num_rows($result) > 0) {
3302
            $sql = 'SELECT DISTINCT srcru.user_id
3303
                    FROM ' . $tbl_session_course_user.' AS srcru
3304
                    WHERE session_id="' . $id_session.'"';
3305
            $result = Database::query($sql);
3306
            while ($row = Database::fetch_array($result)) {
3307
                $students[$row['user_id']] = $row['user_id'];
3308
            }
3309
        }
3310
3311
        return $students;
3312
    }
3313
3314
    /**
3315
     * Check if a coach is allowed to follow a student
3316
     * @param    int        Coach id
3317
     * @param    int        Student id
3318
     * @return    bool
3319
     */
3320
    public static function is_allowed_to_coach_student($coach_id, $student_id)
3321
    {
3322
        $coach_id = intval($coach_id);
3323
        $student_id = intval($student_id);
3324
3325
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3326
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3327
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3328
3329
        // At first, courses where $coach_id is coach of the course //
3330
3331
        $sql = 'SELECT 1 FROM '.$tbl_session_course_user.'
3332
                WHERE user_id=' . $coach_id.' AND status=2';
3333
        $result = Database::query($sql);
3334
        if (Database::num_rows($result) > 0) {
3335
            return true;
3336
        }
3337
3338
        // Then, courses where $coach_id is coach of the session
3339
        $sql = 'SELECT session_course_user.user_id
3340
                FROM '.$tbl_session_course_user.' as session_course_user
3341
                INNER JOIN '.$tbl_session_course.' as session_course
3342
                ON session_course.c_id = session_course_user.c_id
3343
                INNER JOIN '.$tbl_session.' as session
3344
                ON session.id = session_course.session_id
3345
                AND session.id_coach = ' . $coach_id.'
3346
                WHERE user_id = ' . $student_id;
3347
        $result = Database::query($sql);
3348
        if (Database::num_rows($result) > 0) {
3349
            return true;
3350
        }
3351
3352
        return false;
3353
    }
3354
3355
    /**
3356
     * Get courses followed by coach
3357
     * @param     int        Coach id
3358
     * @param    int        Session id (optional)
3359
     * @return    array    Courses list
3360
     */
3361
    public static function get_courses_followed_by_coach($coach_id, $id_session = 0)
3362
    {
3363
        $coach_id = intval($coach_id);
3364
        if (!empty($id_session)) {
3365
            $id_session = intval($id_session);
3366
        }
3367
3368
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3369
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3370
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3371
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3372
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3373
3374
        // At first, courses where $coach_id is coach of the course.
3375
3376
        $sql = 'SELECT DISTINCT c.code
3377
                FROM ' . $tbl_session_course_user.' sc
3378
                INNER JOIN '.$tbl_course.' c
3379
                ON (c.id = sc.c_id)
3380
                WHERE user_id = ' . $coach_id.' AND status = 2';
3381
3382
        if (api_is_multiple_url_enabled()) {
3383
            $access_url_id = api_get_current_access_url_id();
3384
            if ($access_url_id != -1) {
3385
                $sql = 'SELECT DISTINCT c.code
3386
                        FROM ' . $tbl_session_course_user.' scu
3387
                        INNER JOIN '.$tbl_course.' c
3388
                        ON (c.code = scu.c_id)
3389
                        INNER JOIN '.$tbl_course_rel_access_url.' cru
3390
                        ON (c.id = cru.c_id)
3391
                        WHERE
3392
                            scu.user_id=' . $coach_id.' AND
3393
                            scu.status=2 AND
3394
                            cru.access_url_id = '.$access_url_id;
3395
            }
3396
        }
3397
3398
        if (!empty($id_session)) {
3399
            $sql .= ' AND session_id='.$id_session;
3400
        }
3401
3402
        $courseList = array();
3403
        $result = Database::query($sql);
3404
        while ($row = Database::fetch_array($result)) {
3405
            $courseList[$row['code']] = $row['code'];
3406
        }
3407
3408
        // Then, courses where $coach_id is coach of the session
3409
        $sql = 'SELECT DISTINCT course.code
3410
                FROM ' . $tbl_session_course.' as session_course
3411
                INNER JOIN ' . $tbl_session.' as session
3412
                    ON session.id = session_course.session_id
3413
                    AND session.id_coach = ' . $coach_id.'
3414
                INNER JOIN ' . $tbl_course.' as course
3415
                    ON course.id = session_course.c_id';
3416
3417 View Code Duplication
        if (api_is_multiple_url_enabled()) {
3418
            $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3419
            $access_url_id = api_get_current_access_url_id();
3420
            if ($access_url_id != -1) {
3421
                $sql = 'SELECT DISTINCT c.code
3422
                    FROM ' . $tbl_session_course.' as session_course
3423
                    INNER JOIN '.$tbl_course.' c
3424
                    ON (c.id = session_course.c_id)
3425
                    INNER JOIN ' . $tbl_session.' as session
3426
                    ON session.id = session_course.session_id
3427
                        AND session.id_coach = ' . $coach_id.'
3428
                    INNER JOIN ' . $tbl_course.' as course
3429
                        ON course.id = session_course.c_id
3430
                     INNER JOIN '.$tbl_course_rel_access_url.' course_rel_url
3431
                    ON (course_rel_url.c_id = c.id)';
3432
            }
3433
        }
3434
3435
        if (!empty ($id_session)) {
3436
            $sql .= ' WHERE session_course.session_id='.$id_session;
3437
            if (api_is_multiple_url_enabled())
3438
            $sql .= ' AND access_url_id = '.$access_url_id;
3439
        } else {
3440
            if (api_is_multiple_url_enabled())
3441
            $sql .= ' WHERE access_url_id = '.$access_url_id;
3442
        }
3443
3444
        $result = Database::query($sql);
3445
        while ($row = Database::fetch_array($result)) {
3446
            $courseList[$row['code']] = $row['code'];
3447
        }
3448
3449
        return $courseList;
3450
    }
3451
3452
    /**
3453
     * Get sessions coached by user
3454
     * @param $coach_id
3455
     * @param int $start
3456
     * @param int $limit
3457
     * @param bool $getCount
3458
     * @param string $keyword
3459
     * @param string $description
3460
     * @return mixed
3461
     */
3462
    public static function get_sessions_coached_by_user(
3463
        $coach_id,
3464
        $start = 0,
3465
        $limit = 0,
3466
        $getCount = false,
3467
        $keyword = '',
3468
        $description = ''
3469
    ) {
3470
        // table definition
3471
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3472
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3473
        $coach_id = intval($coach_id);
3474
3475
        $select = " SELECT * FROM ";
3476
        if ($getCount) {
3477
            $select = " SELECT count(DISTINCT id) as count FROM ";
3478
        }
3479
3480
        $limitCondition = null;
3481 View Code Duplication
        if (!empty($start) && !empty($limit)) {
3482
            $limitCondition = " LIMIT ".intval($start).", ".intval($limit);
3483
        }
3484
3485
        $keywordCondition = null;
3486
3487 View Code Duplication
        if (!empty($keyword)) {
3488
            $keyword = Database::escape_string($keyword);
3489
            $keywordCondition = " AND (name LIKE '%$keyword%' ) ";
3490
3491
            if (!empty($description)) {
3492
                $description = Database::escape_string($description);
3493
                $keywordCondition = " AND (name LIKE '%$keyword%' OR description LIKE '%$description%' ) ";
3494
            }
3495
        }
3496
3497
        $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3498
        $access_url_id = api_get_current_access_url_id();
3499
3500
        $sql = "
3501
            $select
3502
            (
3503
                SELECT DISTINCT
3504
                    id,
3505
                    name,
3506
                    access_start_date,
3507
                    access_end_date
3508
                FROM $tbl_session session
3509
                INNER JOIN $tbl_session_rel_access_url session_rel_url
3510
                ON (session.id = session_rel_url.session_id)
3511
                WHERE
3512
                    id_coach = $coach_id AND
3513
                    access_url_id = $access_url_id
3514
                    $keywordCondition
3515
            UNION
3516
                SELECT DISTINCT
3517
                    session.id,
3518
                    session.name,
3519
                    session.access_start_date,
3520
                    session.access_end_date
3521
                FROM $tbl_session as session
3522
                INNER JOIN $tbl_session_course_user as session_course_user
3523
                ON
3524
                    session.id = session_course_user.session_id AND
3525
                    session_course_user.user_id = $coach_id AND
3526
                    session_course_user.status = 2
3527
                INNER JOIN $tbl_session_rel_access_url session_rel_url
3528
                ON (session.id = session_rel_url.session_id)
3529
                WHERE
3530
                    access_url_id = $access_url_id
3531
                    $keywordCondition
3532
            ) as sessions $limitCondition
3533
            ";
3534
3535
        $rs = Database::query($sql);
3536
        if ($getCount) {
3537
            $row = Database::fetch_array($rs);
3538
            return $row['count'];
3539
        }
3540
3541
        $sessions = [];
3542
        while ($row = Database::fetch_array($rs)) {
3543
            if ($row['access_start_date'] == '0000-00-00 00:00:00') {
3544
                $row['access_start_date'] = null;
3545
            }
3546
3547
            $sessions[$row['id']] = $row;
3548
        }
3549
3550
        if (!empty($sessions)) {
3551
            foreach ($sessions as & $session) {
3552
                if (empty($session['access_start_date'])
3553
                ) {
3554
                    $session['status'] = get_lang('SessionActive');
3555
                }
3556
                else {
3557
                    $time_start = api_strtotime($session['access_start_date'], 'UTC');
3558
                    $time_end = api_strtotime($session['access_end_date'], 'UTC');
3559
                    if ($time_start < time() && time() < $time_end) {
3560
                        $session['status'] = get_lang('SessionActive');
3561
                    } else {
3562
                        if (time() < $time_start) {
3563
                            $session['status'] = get_lang('SessionFuture');
3564
                        } else {
3565
                            if (time() > $time_end) {
3566
                                $session['status'] = get_lang('SessionPast');
3567
                            }
3568
                        }
3569
                    }
3570
                }
3571
            }
3572
        }
3573
3574
        return $sessions;
3575
    }
3576
3577
    /**
3578
     * Get courses list from a session
3579
     * @param    int        Session id
3580
     * @return    array    Courses list
3581
     */
3582 View Code Duplication
    public static function get_courses_list_from_session($session_id)
3583
    {
3584
        $session_id = intval($session_id);
3585
3586
        // table definition
3587
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3588
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
3589
3590
        $sql = "SELECT DISTINCT code, c_id
3591
                FROM $tbl_session_course sc
3592
                INNER JOIN $courseTable c
3593
                ON sc.c_id = c.id
3594
                WHERE session_id= $session_id";
3595
3596
        $result = Database::query($sql);
3597
3598
        $courses = array();
3599
        while ($row = Database::fetch_array($result)) {
3600
            $courses[$row['code']] = $row;
3601
        }
3602
3603
        return $courses;
3604
    }
3605
3606
    /**
3607
     * Count the number of documents that an user has uploaded to a course
3608
     * @param    int|array   Student id(s)
3609
     * @param    string      Course code
3610
     * @param    int         Session id (optional),
3611
     * if param $session_id is null(default)
3612
     * return count of assignments including sessions, 0 = session is not filtered
3613
     * @return    int        Number of documents
3614
     */
3615
    public static function count_student_uploaded_documents($student_id, $course_code, $session_id = null)
3616
    {
3617
        // get the information of the course
3618
        $a_course = api_get_course_info($course_code);
3619
        if (!empty($a_course)) {
3620
            // table definition
3621
            $tbl_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
3622
            $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
3623
            $course_id = $a_course['real_id'];
3624
            if (is_array($student_id)) {
3625
                $studentList = array_map('intval', $student_id);
3626
                $condition_user = " AND ip.insert_user_id IN ('".implode(',', $studentList)."') ";
3627
            } else {
3628
                $student_id = intval($student_id);
3629
                $condition_user = " AND ip.insert_user_id = '$student_id' ";
3630
            }
3631
3632
            $condition_session = null;
3633
            if (isset($session_id)) {
3634
                $session_id = intval($session_id);
3635
                $condition_session = " AND pub.session_id = $session_id ";
3636
            }
3637
3638
            $sql = "SELECT count(ip.tool) AS count
3639
                    FROM $tbl_item_property ip
3640
                    INNER JOIN $tbl_document pub
3641
                    ON (ip.ref = pub.id AND ip.c_id = pub.c_id)
3642
                    WHERE
3643
                        ip.c_id  = $course_id AND
3644
                        pub.c_id  = $course_id AND
3645
                        pub.filetype ='file' AND
3646
                        ip.tool = 'document'
3647
                        $condition_user $condition_session ";
3648
            $rs = Database::query($sql);
3649
            $row = Database::fetch_array($rs, 'ASSOC');
3650
            return $row['count'];
3651
        }
3652
        return null;
3653
    }
3654
3655
    /**
3656
     * Count assignments per student
3657
     * @param $student_id
3658
     * @param null $course_code
3659
     * @param null $session_id
3660
     * @return int Count of assignments
3661
     * @internal param array|int $Student id(s)
3662
     * @internal param Course $string code
3663
     * @internal param Session $int id (optional),
3664
     * if param $session_id is null(default) return count of assignments
3665
     * including sessions, 0 = session is not filtered
3666
     */
3667
    public static function count_student_assignments($student_id, $course_code = null, $session_id = null)
3668
    {
3669
        if (empty($student_id)) {
3670
            return 0;
3671
        }
3672
3673
        $conditions = array();
3674
3675
        // Get the information of the course
3676
        $a_course = api_get_course_info($course_code);
3677
        if (!empty($a_course)) {
3678
            $course_id = $a_course['real_id'];
3679
            $conditions[] = " ip.c_id  = $course_id AND pub.c_id  = $course_id ";
3680
        }
3681
3682
        // table definition
3683
        $tbl_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
3684
        $tbl_student_publication = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
3685
3686 View Code Duplication
        if (is_array($student_id)) {
3687
            $studentList = array_map('intval', $student_id);
3688
            $conditions[] = " ip.insert_user_id IN ('".implode("','", $studentList)."') ";
3689
        } else {
3690
            $student_id = intval($student_id);
3691
            $conditions[] = " ip.insert_user_id = '$student_id' ";
3692
        }
3693
        if (isset($session_id)) {
3694
            $session_id = intval($session_id);
3695
            $conditions[] = " pub.session_id = $session_id ";
3696
        }
3697
3698
        $conditions[] = ' pub.active <> 2 ';
3699
3700
        $conditionToString = implode('AND', $conditions);
3701
3702
        $sql = "SELECT count(ip.tool) as count
3703
                FROM $tbl_item_property ip
3704
                INNER JOIN $tbl_student_publication pub
3705
                ON (ip.ref = pub.id AND ip.c_id = pub.c_id)
3706
                WHERE
3707
                    ip.tool='work' AND
3708
                    $conditionToString";
3709
        $rs = Database::query($sql);
3710
        $row = Database::fetch_array($rs, 'ASSOC');
3711
3712
        return $row['count'];
3713
    }
3714
3715
    /**
3716
     * Count messages per student inside forum tool
3717
     * @param    int|array        Student id
3718
     * @param    string    Course code
3719
     * @param    int        Session id (optional), if param $session_id is
3720
     * null(default) return count of messages including sessions, 0 = session is not filtered
3721
     * @return    int        Count of messages
3722
     */
3723
    public static function count_student_messages($student_id, $courseCode = null, $session_id = null)
3724
    {
3725
        if (empty($student_id)) {
3726
            return 0;
3727
        }
3728
3729
        // Table definition.
3730
        $tbl_forum_post = Database::get_course_table(TABLE_FORUM_POST);
3731
        $tbl_forum = Database::get_course_table(TABLE_FORUM);
3732
3733
        $conditions = array();
3734 View Code Duplication
        if (is_array($student_id)) {
3735
            $studentList = array_map('intval', $student_id);
3736
            $conditions[] = " post.poster_id IN ('".implode("','", $studentList)."') ";
3737
        } else {
3738
            $student_id = intval($student_id);
3739
            $conditions[] = " post.poster_id = '$student_id' ";
3740
        }
3741
3742
        $conditionsToString = implode('AND ', $conditions);
3743
3744
        if (empty($courseCode)) {
3745
            $sql = "SELECT count(poster_id) as count
3746
                    FROM $tbl_forum_post post
3747
                    INNER JOIN $tbl_forum forum
3748
                    ON (forum.forum_id = post.forum_id AND forum.c_id = post.c_id)
3749
                    WHERE $conditionsToString";
3750
3751
            $rs = Database::query($sql);
3752
            $row = Database::fetch_array($rs, 'ASSOC');
3753
            return $row['count'];
3754
        }
3755
3756
        require_once api_get_path(SYS_CODE_PATH).'forum/forumconfig.inc.php';
3757
        require_once api_get_path(SYS_CODE_PATH).'forum/forumfunction.inc.php';
3758
3759
        $courseInfo = api_get_course_info($courseCode);
3760
3761
        $forums = [];
3762
        if (!empty($courseInfo)) {
3763
            $forums = get_forums('', $courseCode, true, $session_id);
3764
            $course_id = $courseInfo['real_id'];
3765
            $conditions[] = " post.c_id  = $course_id ";
3766
        }
3767
3768
        if (!empty($forums)) {
3769
            $idList = array_column($forums, 'forum_id');
3770
            $idListToString = implode("', '", $idList);
3771
            $conditions[] = " post.forum_id  IN ('$idListToString')";
3772
        }
3773
3774
        $conditionsToString = implode('AND ', $conditions);
3775
        $sql = "SELECT count(poster_id) as count
3776
                FROM $tbl_forum_post post
3777
                WHERE $conditionsToString";
3778
3779
        $rs = Database::query($sql);
3780
        $row = Database::fetch_array($rs, 'ASSOC');
3781
        $count = $row['count'];
3782
3783
        return $count;
3784
    }
3785
3786
    /**
3787
     * This function counts the number of post by course
3788
     * @param      string     Course code
3789
     * @param    int        Session id (optional), if param $session_id is
3790
     * null(default) it'll return results including sessions,
3791
     * 0 = session is not filtered
3792
     * @param int $groupId
3793
     * @return    int     The number of post by course
3794
     */
3795 View Code Duplication
    public static function count_number_of_posts_by_course($course_code, $session_id = null, $groupId = 0)
3796
    {
3797
        $courseInfo = api_get_course_info($course_code);
3798
        if (!empty($courseInfo)) {
3799
            $tbl_posts = Database::get_course_table(TABLE_FORUM_POST);
3800
            $tbl_forums = Database::get_course_table(TABLE_FORUM);
3801
3802
            $condition_session = '';
3803
            if (isset($session_id)) {
3804
                $session_id = intval($session_id);
3805
                $condition_session = api_get_session_condition(
3806
                    $session_id,
3807
                    true,
3808
                    false,
3809
                    'f.session_id'
3810
                );
3811
            }
3812
3813
            $course_id = $courseInfo['real_id'];
3814
            $groupId = intval($groupId);
3815
            if (!empty($groupId)) {
3816
                $groupCondition = " i.to_group_id = $groupId  ";
3817
            } else {
3818
                $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) ";
3819
            }
3820
3821
            $item = Database::get_course_table(TABLE_ITEM_PROPERTY);
3822
            $sql = "SELECT count(*) FROM $tbl_posts p
3823
                    INNER JOIN $tbl_forums f
3824
                    ON f.forum_id = p.forum_id AND p.c_id = f.c_id
3825
                    INNER JOIN $item i
3826
                    ON (tool = '".TOOL_FORUM."' AND f.c_id = i.c_id AND f.iid = i.ref)
3827
                    WHERE
3828
                        p.c_id = $course_id AND
3829
                        f.c_id = $course_id AND
3830
                        $groupCondition
3831
                        $condition_session
3832
                    ";
3833
            $result = Database::query($sql);
3834
            $row = Database::fetch_row($result);
3835
            $count = $row[0];
3836
3837
            return $count;
3838
        } else {
3839
            return null;
3840
        }
3841
    }
3842
3843
    /**
3844
     * This function counts the number of threads by course
3845
     * @param      string     Course code
3846
     * @param    int        Session id (optional),
3847
     * if param $session_id is null(default) it'll return results including
3848
     * sessions, 0 = session is not filtered
3849
     * @param int $groupId
3850
     * @return    int     The number of threads by course
3851
     */
3852 View Code Duplication
    public static function count_number_of_threads_by_course($course_code, $session_id = null, $groupId = 0)
3853
    {
3854
        $course_info = api_get_course_info($course_code);
3855
        if (empty($course_info)) {
3856
            return null;
3857
        }
3858
3859
        $course_id = $course_info['real_id'];
3860
        $tbl_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3861
        $tbl_forums = Database::get_course_table(TABLE_FORUM);
3862
3863
        $condition_session = '';
3864
        if (isset($session_id)) {
3865
            $session_id = intval($session_id);
3866
            $condition_session = ' AND f.session_id = '.$session_id;
3867
        }
3868
3869
        $groupId = intval($groupId);
3870
3871
        if (!empty($groupId)) {
3872
            $groupCondition = " i.to_group_id = $groupId ";
3873
        } else {
3874
            $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) ";
3875
        }
3876
3877
        $item = Database::get_course_table(TABLE_ITEM_PROPERTY);
3878
        $sql = "SELECT count(*)
3879
                FROM $tbl_threads t
3880
                INNER JOIN $tbl_forums f
3881
                ON f.iid = t.forum_id AND f.c_id = t.c_id
3882
                INNER JOIN $item i
3883
                ON (
3884
                    tool = '".TOOL_FORUM_THREAD."' AND
3885
                    f.c_id = i.c_id AND
3886
                    t.iid = i.ref
3887
                )
3888
                WHERE
3889
                    t.c_id = $course_id AND
3890
                    f.c_id = $course_id AND
3891
                    $groupCondition
3892
                    $condition_session
3893
                ";
3894
3895
        $result = Database::query($sql);
3896
        if (Database::num_rows($result)) {
3897
            $row = Database::fetch_row($result);
3898
            $count = $row[0];
3899
3900
            return $count;
3901
        } else {
3902
3903
            return null;
3904
        }
3905
    }
3906
3907
    /**
3908
     * This function counts the number of forums by course
3909
     * @param      string     Course code
3910
     * @param    int        Session id (optional),
3911
     * if param $session_id is null(default) it'll return results
3912
     * including sessions, 0 = session is not filtered
3913
     * @param int $groupId
3914
     * @return    int     The number of forums by course
3915
     */
3916
    public static function count_number_of_forums_by_course($course_code, $session_id = null, $groupId = 0)
3917
    {
3918
        $course_info = api_get_course_info($course_code);
3919
        if (empty($course_info)) {
3920
            return null;
3921
        }
3922
        $course_id = $course_info['real_id'];
3923
3924
        $condition_session = '';
3925
        if (isset($session_id)) {
3926
             $session_id = intval($session_id);
3927
             $condition_session = ' AND f.session_id = '.$session_id;
3928
        }
3929
3930
        $groupId = intval($groupId);
3931
        if (!empty($groupId)) {
3932
            $groupCondition = " i.to_group_id = $groupId ";
3933
        } else {
3934
            $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) ";
3935
        }
3936
3937
        $tbl_forums = Database::get_course_table(TABLE_FORUM);
3938
        $item = Database::get_course_table(TABLE_ITEM_PROPERTY);
3939
3940
        $sql = "SELECT count(*)
3941
                FROM $tbl_forums f
3942
                INNER JOIN $item i
3943
                ON f.c_id = i.c_id AND f.iid = i.ref AND tool = '".TOOL_FORUM."'
3944
                WHERE
3945
                    f.c_id = $course_id AND
3946
                    $groupCondition
3947
                    $condition_session
3948
                ";
3949
        $result = Database::query($sql);
3950
        if (Database::num_rows($result)) {
3951
            $row = Database::fetch_row($result);
3952
            $count = $row[0];
3953
            return $count;
3954
        } else {
3955
            return null;
3956
        }
3957
    }
3958
3959
    /**
3960
     * This function counts the chat last connections by course in x days
3961
     * @param      string     Course code
3962
     * @param      int     Last x days
3963
     * @param    int        Session id (optional)
3964
     * @return     int     Chat last connections by course in x days
3965
     */
3966
    public static function chat_connections_during_last_x_days_by_course($course_code, $last_days, $session_id = 0)
3967
    {
3968
        $course_info = api_get_course_info($course_code);
3969
        if (empty($course_info)) {
3970
            return null;
3971
        }
3972
        $course_id = $course_info['real_id'];
3973
3974
        // Protect data
3975
        $last_days = intval($last_days);
3976
        $session_id = intval($session_id);
3977
        $tbl_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
3978
        $now = api_get_utc_datetime();
3979
3980
        $sql = "SELECT count(*) FROM $tbl_stats_access
3981
                WHERE
3982
                    DATE_SUB('$now',INTERVAL $last_days DAY) <= access_date AND
3983
                    c_id = '$course_id' AND
3984
                    access_tool='".TOOL_CHAT."' AND
3985
                    access_session_id='$session_id' ";
3986
        $result = Database::query($sql);
3987
        if (Database::num_rows($result)) {
3988
            $row = Database::fetch_row($result);
3989
            $count = $row[0];
3990
            return $count;
3991
        } else {
3992
            return null;
3993
        }
3994
    }
3995
3996
    /**
3997
     * This function gets the last student's connection in chat
3998
     * @param      int     Student id
3999
     * @param      string     Course code
4000
     * @param    int        Session id (optional)
4001
     * @return     string    datetime formatted without day (e.g: February 23, 2010 10:20:50 )
4002
     */
4003
    public static function chat_last_connection($student_id, $courseId, $session_id = 0)
4004
    {
4005
        $student_id = intval($student_id);
4006
        $courseId = intval($courseId);
4007
        $session_id = intval($session_id);
4008
        $date_time  = '';
4009
4010
        // table definition
4011
        $tbl_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4012
        $sql = "SELECT access_date
4013
                FROM $tbl_stats_access
4014
                WHERE
4015
                     access_tool='".TOOL_CHAT."' AND
4016
                     access_user_id='$student_id' AND
4017
                     c_id = $courseId AND
4018
                     access_session_id = '$session_id'
4019
                ORDER BY access_date DESC limit 1";
4020
        $rs = Database::query($sql);
4021
        if (Database::num_rows($rs) > 0) {
4022
            $row = Database::fetch_array($rs);
4023
            $date_time = api_convert_and_format_date(
4024
                $row['access_date'],
4025
                null,
4026
                date_default_timezone_get()
4027
            );
4028
        }
4029
        return $date_time;
4030
    }
4031
4032
    /**
4033
     * Get count student's visited links
4034
     * @param    int $student_id Student id
4035
     * @param    int $courseId
4036
     * @param    int $session_id Session id (optional)
4037
     * @return    int        count of visited links
4038
     */
4039 View Code Duplication
    public static function count_student_visited_links($student_id, $courseId, $session_id = 0)
4040
    {
4041
        $student_id  = intval($student_id);
4042
        $courseId = intval($courseId);
4043
        $session_id  = intval($session_id);
4044
4045
        // table definition
4046
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
4047
4048
        $sql = 'SELECT 1
4049
                FROM '.$table.'
4050
                WHERE
4051
                    links_user_id= '.$student_id.' AND
4052
                    c_id = "'.$courseId.'" AND
4053
                    links_session_id = '.$session_id.' ';
4054
4055
        $rs = Database::query($sql);
4056
        return Database::num_rows($rs);
4057
    }
4058
4059
    /**
4060
     * Get count student downloaded documents
4061
     * @param    int        Student id
4062
     * @param    int    $courseId
4063
     * @param    int        Session id (optional)
4064
     * @return    int        Count downloaded documents
4065
     */
4066 View Code Duplication
    public static function count_student_downloaded_documents($student_id, $courseId, $session_id = 0)
4067
    {
4068
        $student_id  = intval($student_id);
4069
        $courseId = intval($courseId);
4070
        $session_id  = intval($session_id);
4071
4072
        // table definition
4073
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
4074
4075
        $sql = 'SELECT 1
4076
                FROM '.$table.'
4077
                WHERE down_user_id = '.$student_id.'
4078
                AND c_id  = "'.$courseId.'"
4079
                AND down_session_id = '.$session_id.' ';
4080
        $rs = Database::query($sql);
4081
4082
        return Database::num_rows($rs);
4083
    }
4084
4085
    /**
4086
     * Get course list inside a session from a student
4087
     * @param    int        $user_id Student id
4088
     * @param    int        $id_session Session id (optional)
4089
     * @return    array    Courses list
4090
     */
4091
    public static function get_course_list_in_session_from_student($user_id, $id_session = 0)
4092
    {
4093
        $user_id = intval($user_id);
4094
        $id_session = intval($id_session);
4095
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4096
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
4097
4098
        $sql = "SELECT c.code
4099
                FROM $tbl_session_course_user sc
4100
                INNER JOIN $courseTable c
4101
                WHERE
4102
                    user_id= $user_id  AND
4103
                    session_id = $id_session";
4104
        $result = Database::query($sql);
4105
        $courses = array();
4106
        while ($row = Database::fetch_array($result)) {
4107
            $courses[$row['code']] = $row['code'];
4108
        }
4109
4110
        return $courses;
4111
    }
4112
4113
    /**
4114
     * Get inactive students in course
4115
     * @param int   $courseId
4116
     * @param string|int $since  Since login course date (optional, default = 'never')
4117
     * @param int $session_id    (optional)
4118
     * @return array Inactive users
4119
     */
4120
    public static function getInactiveStudentsInCourse(
4121
        $courseId,
4122
        $since = 'never',
4123
        $session_id = 0
4124
    ) {
4125
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
4126
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4127
        $table_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4128
        $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
4129
        $now = api_get_utc_datetime();
4130
        $courseId = (int) $courseId;
4131
        $session_id = (int) $session_id;
4132
4133
        if (empty($courseId)) {
4134
            return false;
4135
        }
4136
4137
        if ($since === 'never') {
4138
            if (empty($session_id)) {
4139
                $sql = 'SELECT course_user.user_id
4140
                        FROM ' . $table_course_rel_user.' course_user
4141
                        LEFT JOIN ' . $tbl_track_login.' stats_login
4142
                        ON course_user.user_id = stats_login.user_id AND
4143
                        relation_type<>' . COURSE_RELATION_TYPE_RRHH.'
4144
                        INNER JOIN ' . $tableCourse.' c
4145
                        ON (c.id = course_user.c_id)
4146
                        WHERE
4147
                            course_user.c_id = ' . $courseId.' AND
4148
                            stats_login.login_course_date IS NULL
4149
                        GROUP BY course_user.user_id';
4150
            } else {
4151
                $sql = 'SELECT session_course_user.user_id
4152
                        FROM '.$tbl_session_course_user.' session_course_user
4153
                        LEFT JOIN ' . $tbl_track_login.' stats_login
4154
                        ON session_course_user.user_id = stats_login.user_id
4155
                        INNER JOIN ' . $tableCourse.' c
4156
                        ON (c.id = session_course_user.c_id)
4157
                        WHERE
4158
                            session_course_user.c_id = ' . $courseId.' AND
4159
                            stats_login.login_course_date IS NULL
4160
                        GROUP BY session_course_user.user_id';
4161
            }
4162
        } else {
4163
            $since = (int) $since;
4164
            if (empty($session_id)) {
4165
                $inner = 'INNER JOIN '.$table_course_rel_user.' course_user
4166
                          ON course_user.user_id = stats_login.user_id AND course_user.c_id = c.id ';
4167
            } else {
4168
                $inner = 'INNER JOIN '.$tbl_session_course_user.' session_course_user
4169
                          ON
4170
                            c.id = session_course_user.c_id AND
4171
                            session_course_user.session_id = '.$session_id.' AND
4172
                            session_course_user.user_id = stats_login.user_id ';
4173
            }
4174
4175
            $sql = 'SELECT 
4176
                    stats_login.user_id, 
4177
                    MAX(login_course_date) max_date
4178
                FROM '.$tbl_track_login.' stats_login
4179
                INNER JOIN '.$tableCourse.' c
4180
                ON (c.id = stats_login.c_id)
4181
                '.$inner.'
4182
                WHERE c.id = '.$courseId.'
4183
                GROUP BY stats_login.user_id
4184
                HAVING DATE_SUB("'.$now.'", INTERVAL '.$since.' DAY) > max_date ';
4185
        }
4186
4187
        $rs = Database::query($sql);
4188
        $users = [];
4189
        while ($user = Database::fetch_array($rs)) {
4190
            $users[] = $user['user_id'];
4191
        }
4192
4193
        return $users;
4194
    }
4195
4196
    /**
4197
     * Get count login per student
4198
     * @param    int    $student_id    Student id
4199
     * @param    int    $courseId
4200
     * @param    int    $session_id    Session id (optional)
4201
     * @return    int        count login
4202
     */
4203
    public static function count_login_per_student($student_id, $courseId, $session_id = 0)
4204
    {
4205
        $student_id  = intval($student_id);
4206
        $courseId = intval($courseId);
4207
        $session_id  = intval($session_id);
4208
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
4209
4210
        $sql = 'SELECT '.$student_id.'
4211
                FROM '.$table.'
4212
                WHERE
4213
                    access_user_id='.$student_id.' AND
4214
                    c_id="'.$courseId.'" AND
4215
                    access_session_id = "'.$session_id.'" ';
4216
4217
        $rs = Database::query($sql);
4218
        $nb_login = Database::num_rows($rs);
4219
4220
        return $nb_login;
4221
    }
4222
4223
    /**
4224
     * Get students followed by a human resources manager
4225
     * @param    int        Drh id
4226
     * @return    array    Student list
4227
     */
4228 View Code Duplication
    public static function get_student_followed_by_drh($hr_dept_id)
4229
    {
4230
        $hr_dept_id = intval($hr_dept_id);
4231
        $a_students = array();
4232
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
4233
4234
        $sql = 'SELECT DISTINCT user_id FROM '.$tbl_user.' as user
4235
                WHERE hr_dept_id='.$hr_dept_id;
4236
        $rs = Database::query($sql);
4237
4238
        while ($user = Database::fetch_array($rs)) {
4239
            $a_students[$user['user_id']] = $user['user_id'];
4240
        }
4241
4242
        return $a_students;
4243
    }
4244
4245
4246
4247
    /**
4248
     * get count clicks about tools most used by course
4249
     * @param    int      $courseId
4250
     * @param    int        Session id (optional),
4251
     * if param $session_id is null(default) it'll return results
4252
     * including sessions, 0 = session is not filtered
4253
     * @return    array     tools data
4254
     */
4255
    public static function get_tools_most_used_by_course($courseId, $session_id = null)
4256
    {
4257
        $courseId = intval($courseId);
4258
        $data = array();
4259
        $TABLETRACK_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4260
        $condition_session     = '';
4261
        if (isset($session_id)) {
4262
            $session_id = intval($session_id);
4263
            $condition_session = ' AND access_session_id = '.$session_id;
4264
        }
4265
        $sql = "SELECT
4266
                    access_tool,
4267
                    COUNT(DISTINCT access_user_id),
4268
                    count(access_tool) as count_access_tool
4269
                FROM $TABLETRACK_ACCESS
4270
                WHERE
4271
                    access_tool IS NOT NULL AND
4272
                    access_tool != '' AND
4273
                    c_id = '$courseId'
4274
                    $condition_session
4275
                GROUP BY access_tool
4276
                ORDER BY count_access_tool DESC
4277
                LIMIT 0, 3";
4278
        $rs = Database::query($sql);
4279
        if (Database::num_rows($rs) > 0) {
4280
            while ($row = Database::fetch_array($rs)) {
4281
                $data[] = $row;
4282
            }
4283
        }
4284
        return $data;
4285
    }
4286
4287
    /**
4288
     * Get total clicks
4289
     * THIS FUNCTION IS NOT BEEN USED, IT WAS MEANT TO BE USE WITH track_e_course_access.date_from and track_e_course_access.date_to,
4290
     * BUT NO ROW MATCH THE CONDITION, IT SHOULD BE FINE TO USE IT WHEN YOU USE USER DEFINED DATES AND NO CHAMILO DATES
4291
     * @param   int     User Id
4292
     * @param   int     Course Id
4293
     * @param   int     Session Id (optional), if param $session_id is 0 (default) it'll return results including sessions, 0 = session is not filtered
4294
     * @param   string  Date from
4295
     * @param   string  Date to
4296
     * @return  array   Data
4297
     * @author  César Perales [email protected] 2014-01-16
4298
     */
4299
    public static function get_total_clicks($userId, $courseId, $sessionId = 0, $date_from = '', $date_to = '')
4300
    {
4301
        $course = api_get_course_info_by_id($courseId);
4302
        $tables = array(
4303
            TABLE_STATISTIC_TRACK_E_LASTACCESS => array(
4304
                'course'    => 'c_id',
4305
                'session'   => 'access_session_id',
4306
                'user'      => 'access_user_id',
4307
                'start_date'=> 'access_date',
4308
            ),
4309
            TABLE_STATISTIC_TRACK_E_ACCESS => array(
4310
                'course'    => 'c_id',
4311
                'session'   => 'access_session_id',
4312
                'user'      => 'access_user_id',
4313
                'start_date'=> 'access_date',
4314
            ),
4315
            #TABLE_STATISTIC_TRACK_E_LOGIN, array(,, 'login_date', 'logout_date');
4316
            TABLE_STATISTIC_TRACK_E_DOWNLOADS => array(
4317
                'course'    => 'c_id',
4318
                'session'   => 'down_session_id',
4319
                'user'      => 'down_user_id',
4320
                'start_date'=> 'down_date',
4321
                ),
4322
            TABLE_STATISTIC_TRACK_E_LINKS => array(
4323
                'course'    => 'c_id',
4324
                'session'   => 'links_session_id',
4325
                'user'      => 'links_user_id',
4326
                'start_date'=> 'links_date',
4327
            ),
4328
            TABLE_STATISTIC_TRACK_E_ONLINE => array(
4329
                'course'    => 'c_id',
4330
                'session'   => 'session_id',
4331
                'user'      => 'login_user_id',
4332
                'start_date'=> 'login_date',
4333
            ),
4334
            #TABLE_STATISTIC_TRACK_E_HOTPOTATOES,
4335
            /*TABLE_STATISTIC_TRACK_E_COURSE_ACCESS => array(
4336
                'course'    => 'c_id',
4337
                'session'   => 'session_id',
4338
                'user'      => 'user_id',
4339
                'start_date'=> 'login_course_date',
4340
                'end_date'  => 'logout_course_date',
4341
                ),*/
4342
            TABLE_STATISTIC_TRACK_E_EXERCISES => array(
4343
                'course'    => 'c_id',
4344
                'session'   => 'session_id',
4345
                'user'      => 'exe_user_id',
4346
                'start_date'=> 'exe_date',
4347
            ),
4348
            TABLE_STATISTIC_TRACK_E_ATTEMPT => array(
4349
                'course'    => 'c_id',
4350
                'session'   => 'session_id',
4351
                'user'      => 'user_id',
4352
                'start_date'=> 'tms',
4353
            ),
4354
            #TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING,
4355
            #TABLE_STATISTIC_TRACK_E_DEFAULT,
4356
            TABLE_STATISTIC_TRACK_E_UPLOADS => array(
4357
                'course'    => 'c_id',
4358
                'session'   => 'upload_session_id',
4359
                'user'      => 'upload_user_id',
4360
                'start_date'=> 'upload_date',
4361
            ),
4362
        );
4363
4364
        foreach ($tables as $tableName => $fields) {
4365
            //If session is defined, add it to query
4366
            $where = '';
4367
            if (isset($sessionId) && !empty($sessionId)) {
4368
                $sessionField = $fields['session'];
4369
                $where .= " AND $sessionField = $sessionId";
4370
            }
4371
4372
            //filter by date
4373
            if (!empty($date_from) && !empty($date_to)) {
4374
                $fieldStartDate = $fields['start_date'];
4375
                if (!isset($fields['end_date'])) {
4376
                    $where .= sprintf(" AND ($fieldStartDate BETWEEN '%s' AND '%s' )", $date_from, $date_to);
4377
                } else {
4378
                    $fieldEndDate = $fields['end_date'];
4379
                    $where .= sprintf(" AND fieldStartDate >= '%s'
4380
                        AND $fieldEndDate <= '%s'", $date_from, $date_to);
4381
                }
4382
            }
4383
4384
            //query
4385
            $sql = "SELECT %s as user, count(*) as total
4386
                FROM %s
4387
                WHERE %s = '%s'
4388
                AND %s = %s
4389
                $where
4390
                GROUP BY %s";
4391
            $sql = sprintf($sql,
4392
                $fields['user'], //user field
4393
                $tableName, //FROM
4394
                $fields['course'], //course condition
4395
                $course['real_id'], //course condition
4396
                $fields['user'], //user condition
4397
                $userId, //user condition
4398
                $fields['user']     //GROUP BY
4399
                );
4400
            $rs = Database::query($sql);
4401
4402
            //iterate query
4403
            if (Database::num_rows($rs) > 0) {
4404
                while ($row = Database::fetch_array($rs)) {
4405
                    $data[$row['user']] = (isset($data[$row['user']])) ? $data[$row['user']] + $row[total] : $row['total'];
4406
                }
4407
            }
4408
        }
4409
4410
        return $data;
4411
    }
4412
4413
    /**
4414
     * get documents most downloaded by course
4415
     * @param      string     Course code
4416
     * @param    int        Session id (optional),
4417
     * if param $session_id is null(default) it'll return results including
4418
     * sessions, 0 = session is not filtered
4419
     * @param    int        Limit (optional, default = 0, 0 = without limit)
4420
     * @return    array     documents downloaded
4421
     */
4422
    public static function get_documents_most_downloaded_by_course($course_code, $session_id = 0, $limit = 0)
4423
    {
4424
        //protect data
4425
        $courseId = api_get_course_int_id($course_code);
4426
        $data = array();
4427
4428
        $TABLETRACK_DOWNLOADS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
4429
        $condition_session = '';
4430
        $session_id = intval($session_id);
4431
        if (!empty($session_id)) {
4432
            $condition_session = ' AND down_session_id = '.$session_id;
4433
        }
4434
        $sql = "SELECT
4435
                    down_doc_path,
4436
                    COUNT(DISTINCT down_user_id),
4437
                    COUNT(down_doc_path) as count_down
4438
                FROM $TABLETRACK_DOWNLOADS
4439
                WHERE c_id = $courseId
4440
                    $condition_session
4441
                GROUP BY down_doc_path
4442
                ORDER BY count_down DESC
4443
                LIMIT 0,  $limit";
4444
        $rs = Database::query($sql);
4445
4446
        if (Database::num_rows($rs) > 0) {
4447
            while ($row = Database::fetch_array($rs)) {
4448
                $data[] = $row;
4449
            }
4450
        }
4451
        return $data;
4452
    }
4453
4454
    /**
4455
     * get links most visited by course
4456
     * @param      string     Course code
4457
     * @param    int        Session id (optional),
4458
     * if param $session_id is null(default) it'll
4459
     * return results including sessions, 0 = session is not filtered
4460
     * @return    array     links most visited
4461
     */
4462
    public static function get_links_most_visited_by_course($course_code, $session_id = null)
4463
    {
4464
        $course_code = Database::escape_string($course_code);
4465
        $course_info = api_get_course_info($course_code);
4466
        $course_id = $course_info['real_id'];
4467
        $data = array();
4468
4469
        $TABLETRACK_LINKS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
4470
        $TABLECOURSE_LINKS = Database::get_course_table(TABLE_LINK);
4471
4472
        $condition_session = '';
4473
        if (isset($session_id)) {
4474
            $session_id = intval($session_id);
4475
            $condition_session = ' AND cl.session_id = '.$session_id;
4476
        }
4477
4478
        $sql = "SELECT cl.title, cl.url,count(DISTINCT sl.links_user_id), count(cl.title) as count_visits
4479
                FROM $TABLETRACK_LINKS AS sl, $TABLECOURSE_LINKS AS cl
4480
                WHERE
4481
                    cl.c_id = $course_id AND
4482
                    sl.links_link_id = cl.id AND
4483
                    sl.c_id = $course_id
4484
                    $condition_session
4485
                GROUP BY cl.title, cl.url
4486
                ORDER BY count_visits DESC
4487
                LIMIT 0, 3";
4488
        $rs = Database::query($sql);
4489
        if (Database::num_rows($rs) > 0) {
4490
            while ($row = Database::fetch_array($rs)) {
4491
                $data[] = $row;
4492
            }
4493
        }
4494
        return $data;
4495
    }
4496
4497
    /**
4498
     * Shows the user progress (when clicking in the Progress tab)
4499
     *
4500
     * @param int $user_id
4501
     * @param int $session_id
4502
     * @param string $extra_params
4503
     * @param bool $show_courses
4504
     * @param bool $showAllSessions
4505
     *
4506
     * @return string
4507
     */
4508
    public static function show_user_progress(
4509
        $user_id,
4510
        $session_id = 0,
4511
        $extra_params = '',
4512
        $show_courses = true,
4513
        $showAllSessions = true
4514
    ) {
4515
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
4516
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
4517
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4518
        $tbl_access_rel_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4519
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4520
        $tbl_access_rel_session = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
4521
4522
        $trackingColumns = [
4523
            'course_session' => [
4524
                'course_title' => true,
4525
                'published_exercises' => true,
4526
                'new_exercises' => true,
4527
                'my_average' => true,
4528
                'average_exercise_result' => true,
4529
                'time_spent' => true,
4530
                'lp_progress' => true,
4531
                'score' => true,
4532
                'best_score' => true,
4533
                'last_connection' => true,
4534
                'details' => true,
4535
            ],
4536
        ];
4537
4538
        $trackingColumnsConfig = api_get_configuration_value('tracking_columns');
4539
        if (!empty($trackingColumnsConfig)) {
4540
            $trackingColumns = $trackingColumnsConfig;
4541
        }
4542
4543
        $user_id = intval($user_id);
4544
        $session_id = intval($session_id);
4545
        $urlId = api_get_current_access_url_id();
4546
4547
        if (api_is_multiple_url_enabled()) {
4548
            $sql = "SELECT c.code, title
4549
                    FROM $tbl_course_user cu
4550
                    INNER JOIN $tbl_course c
4551
                    ON (cu.c_id = c.id)
4552
                    INNER JOIN $tbl_access_rel_course a
4553
                    ON (a.c_id = c.id)
4554
                    WHERE
4555
                        cu.user_id = $user_id AND
4556
                        relation_type<> ".COURSE_RELATION_TYPE_RRHH." AND
4557
                        access_url_id = ".$urlId."
4558
                    ORDER BY title";
4559
        } else {
4560
            $sql = "SELECT c.code, title
4561
                    FROM $tbl_course_user u
4562
                    INNER JOIN $tbl_course c ON (c_id = c.id)
4563
                    WHERE
4564
                        u.user_id= $user_id AND
4565
                        relation_type<>".COURSE_RELATION_TYPE_RRHH."
4566
                    ORDER BY title";
4567
        }
4568
4569
        $rs = Database::query($sql);
4570
        $courses = $course_in_session = $temp_course_in_session = array();
4571
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4572
            $courses[$row['code']] = $row['title'];
4573
        }
4574
4575
        $orderBy = " ORDER BY name ";
4576
        $extraInnerJoin = null;
4577
4578
        if (SessionManager::orderCourseIsEnabled() && !empty($session_id)) {
4579
            $orderBy = " ORDER BY s.id, position ";
4580
            $tableSessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
4581
            $extraInnerJoin = " INNER JOIN $tableSessionRelCourse src
4582
                                ON (cu.c_id = src.c_id AND src.session_id = $session_id) ";
4583
        }
4584
4585
        $sessionCondition = '';
4586
        if (!empty($session_id)) {
4587
            $sessionCondition = " AND s.id = $session_id";
4588
        }
4589
4590
        // Get the list of sessions where the user is subscribed as student
4591
        if (api_is_multiple_url_enabled()) {
4592
            $sql = "SELECT DISTINCT c.code, s.id as session_id, name
4593
                    FROM $tbl_session_course_user cu
4594
                    INNER JOIN $tbl_access_rel_session a
4595
                    ON (a.session_id = cu.session_id)
4596
                    INNER JOIN $tbl_session s
4597
                    ON (s.id = a.session_id)
4598
                    INNER JOIN $tbl_course c
4599
                    ON (c.id = cu.c_id)
4600
                    $extraInnerJoin
4601
                    WHERE
4602
                        cu.user_id = $user_id AND
4603
                        access_url_id = ".$urlId."
4604
                        $sessionCondition
4605
                    $orderBy ";
4606
        } else {
4607
            $sql = "SELECT DISTINCT c.code, s.id as session_id, name
4608
                    FROM $tbl_session_course_user cu
4609
                    INNER JOIN $tbl_session s
4610
                    ON (s.id = cu.session_id)
4611
                    INNER JOIN $tbl_course c
4612
                    ON (c.id = cu.c_id)
4613
                    $extraInnerJoin
4614
                    WHERE
4615
                        cu.user_id = $user_id
4616
                        $sessionCondition
4617
                    $orderBy ";
4618
        }
4619
4620
        $rs = Database::query($sql);
4621
        $simple_session_array = array();
4622
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4623
            $course_info = api_get_course_info($row['code']);
4624
            $temp_course_in_session[$row['session_id']]['course_list'][$course_info['real_id']] = $course_info;
4625
            $temp_course_in_session[$row['session_id']]['name'] = $row['name'];
4626
            $simple_session_array[$row['session_id']] = $row['name'];
4627
        }
4628
4629
        foreach ($simple_session_array as $my_session_id => $session_name) {
4630
            $course_list = $temp_course_in_session[$my_session_id]['course_list'];
4631
            $my_course_data = array();
4632
            foreach ($course_list as $courseId => $course_data) {
4633
                $my_course_data[$courseId] = $course_data['title'];
4634
            }
4635
4636
            if (empty($session_id)) {
4637
                $my_course_data = utf8_sort($my_course_data);
4638
            }
4639
4640
            $final_course_data = array();
4641
            foreach ($my_course_data as $course_id => $value) {
4642
                if (isset($course_list[$course_id])) {
4643
                    $final_course_data[$course_id] = $course_list[$course_id];
4644
                }
4645
            }
4646
            $course_in_session[$my_session_id]['course_list'] = $final_course_data;
4647
            $course_in_session[$my_session_id]['name'] = $session_name;
4648
        }
4649
4650
        $html = '';
4651
4652
        // Course list
4653
        if ($show_courses) {
4654
            if (!empty($courses)) {
4655
                $html .= Display::page_subheader(
4656
                    Display::return_icon(
4657
                        'course.png',
4658
                        get_lang('MyCourses'),
4659
                        array(),
4660
                        ICON_SIZE_SMALL
4661
                    ).' '.get_lang('MyCourses')
4662
                );
4663
                $html .= '<div class="table-responsive">';
4664
                $html .= '<table class="table table-striped table-hover">';
4665
                $html .= '<thead>';
4666
                $html .= '<tr>
4667
                          '.Display::tag('th', get_lang('Course'), array('width'=>'300px')).'
4668
                          '.Display::tag('th', get_lang('TimeSpentInTheCourse')).'
4669
                          '.Display::tag('th', get_lang('Progress')).'
4670
                          '.Display::tag('th', get_lang('BestScore')).'
4671
                          '.Display::tag('th', get_lang('LastConnexion')).'
4672
                          '.Display::tag('th', get_lang('Details')).'
4673
                        </tr>';
4674
                $html .= '</thead><tbody>';
4675
4676
                foreach ($courses as $course_code => $course_title) {
4677
                    $courseInfo = api_get_course_info($course_code);
4678
                    $courseId = $courseInfo['real_id'];
4679
4680
                    $total_time_login = self::get_time_spent_on_the_course(
4681
                        $user_id,
4682
                        $courseId
4683
                    );
4684
                    $time = api_time_to_hms($total_time_login);
4685
                    $progress = self::get_avg_student_progress(
4686
                        $user_id,
4687
                        $course_code
4688
                    );
4689
                    $bestScore = self::get_avg_student_score(
4690
                        $user_id,
4691
                        $course_code,
4692
                        array(),
4693
                        null,
4694
                        false,
4695
                        false,
4696
                        true
4697
                    );
4698
4699
                    $last_connection = self::get_last_connection_date_on_the_course(
4700
                        $user_id,
4701
                        $courseInfo
4702
                    );
4703
4704
                    if (is_null($progress) || empty($progress)) {
4705
                        $progress = '0%';
4706
                    } else {
4707
                        $progress = $progress.'%';
4708
                    }
4709
4710
                    if (isset($_GET['course']) &&
4711
                        $course_code == $_GET['course'] &&
4712
                        empty($_GET['session_id'])
4713
                    ) {
4714
                        $html .= '<tr class="row_odd" style="background-color:#FBF09D">';
4715
                    } else {
4716
                        $html .= '<tr class="row_even">';
4717
                    }
4718
                    $url = api_get_course_url($course_code, $session_id);
4719
                    $course_url = Display::url($course_title, $url, array('target'=>SESSION_LINK_TARGET));
4720
                    $html .= '<td>'.$course_url.'</td>';
4721
                    $html .= '<td align="center">'.$time.'</td>';
4722
                    $html .= '<td align="center">'.$progress.'</td>';
4723
                    $html .= '<td align="center">';
4724
                    if (empty($bestScore)) {
4725
                        $html .= '-';
4726
                    } else {
4727
                        $html .= $bestScore.'%';
4728
                    }
4729
4730
                    $html .= '</td>';
4731
                    $html .= '<td align="center">'.$last_connection.'</td>';
4732
                    $html .= '<td align="center">';
4733
                    if (isset($_GET['course']) &&
4734
                        $course_code == $_GET['course'] &&
4735
                        empty($_GET['session_id'])
4736
                    ) {
4737
                        $html .= '<a href="#course_session_header">';
4738
                        $html .= Display::return_icon('2rightarrow_na.png', get_lang('Details'));
4739 View Code Duplication
                    } else {
4740
                        $html .= '<a href="'.api_get_self().'?course='.$course_code.$extra_params.'#course_session_header">';
4741
                        $html .= Display::return_icon('2rightarrow.png', get_lang('Details'));
4742
                    }
4743
                    $html .= '</a>';
4744
                    $html .= '</td></tr>';
4745
                }
4746
                $html .= '</tbody></table>';
4747
                $html .= '</div>';
4748
            }
4749
        }
4750
4751
        // Session list
4752
        if (!empty($course_in_session)) {
4753
            $main_session_graph = '';
4754
            //Load graphics only when calling to an specific session
4755
            $session_graph = array();
4756
            $all_exercise_graph_name_list = array();
4757
            $my_results = array();
4758
            $all_exercise_graph_list = array();
4759
            $all_exercise_start_time = array();
4760
            foreach ($course_in_session as $my_session_id => $session_data) {
4761
                $course_list = $session_data['course_list'];
4762
                $user_count = count(SessionManager::get_users_by_session($my_session_id));
4763
                $exercise_graph_name_list = array();
4764
                $exercise_graph_list = array();
4765
4766
                foreach ($course_list as $course_data) {
4767
                    $exercise_list = ExerciseLib::get_all_exercises(
4768
                        $course_data,
4769
                        $my_session_id,
4770
                        false,
4771
                        null,
4772
                        false,
4773
                        1
4774
                    );
4775
4776
                    foreach ($exercise_list as $exercise_data) {
4777
                        $exercise_obj = new Exercise($course_data['real_id']);
4778
                        $exercise_obj->read($exercise_data['id']);
4779
                        // Exercise is not necessary to be visible to show results check the result_disable configuration instead
4780
                        //$visible_return = $exercise_obj->is_visible();
4781
                        if ($exercise_data['results_disabled'] == 0 || $exercise_data['results_disabled'] == 2) {
4782
                            $best_average = intval(
4783
                                ExerciseLib::get_best_average_score_by_exercise(
4784
                                    $exercise_data['id'],
4785
                                    $course_data['real_id'],
4786
                                    $my_session_id,
4787
                                    $user_count
4788
                                )
4789
                            );
4790
4791
                            $exercise_graph_list[] = $best_average;
4792
                            $all_exercise_graph_list[] = $best_average;
4793
4794
                            $user_result_data = ExerciseLib::get_best_attempt_by_user(
4795
                                api_get_user_id(),
4796
                                $exercise_data['id'],
4797
                                $course_data['real_id'],
4798
                                $my_session_id
4799
                            );
4800
4801
                            $score = 0;
4802
                            if (!empty($user_result_data['exe_weighting']) && intval($user_result_data['exe_weighting']) != 0) {
4803
                                $score = intval($user_result_data['exe_result'] / $user_result_data['exe_weighting'] * 100);
4804
                            }
4805
                            $time = api_strtotime($exercise_data['start_time']) ? api_strtotime($exercise_data['start_time'], 'UTC') : 0;
4806
                            $all_exercise_start_time[] = $time;
4807
                            $my_results[] = $score;
4808
                            if (count($exercise_list) <= 10) {
4809
                                $title = cut($course_data['title'], 30)." \n ".cut($exercise_data['title'], 30);
4810
                                $exercise_graph_name_list[] = $title;
4811
                                $all_exercise_graph_name_list[] = $title;
4812
                            } else {
4813
                                // if there are more than 10 results, space becomes difficult to find,
4814
                                // so only show the title of the exercise, not the tool
4815
                                $title = cut($exercise_data['title'], 30);
4816
                                $exercise_graph_name_list[] = $title;
4817
                                $all_exercise_graph_name_list[] = $title;
4818
                            }
4819
                        }
4820
                    }
4821
                }
4822
            }
4823
4824
            // Complete graph
4825
            if (!empty($my_results) && !empty($all_exercise_graph_list)) {
4826
                asort($all_exercise_start_time);
4827
4828
                //Fix exams order
4829
                $final_all_exercise_graph_name_list = array();
4830
                $my_results_final = array();
4831
                $final_all_exercise_graph_list = array();
4832
4833
                foreach ($all_exercise_start_time as $key => $time) {
4834
                    $label_time = '';
4835
                    if (!empty($time)) {
4836
                        $label_time = date('d-m-y', $time);
4837
                    }
4838
                    $final_all_exercise_graph_name_list[] = $all_exercise_graph_name_list[$key].' '.$label_time;
4839
                    $my_results_final[] = $my_results[$key];
4840
                    $final_all_exercise_graph_list[] = $all_exercise_graph_list[$key];
4841
                }
4842
                $main_session_graph = self::generate_session_exercise_graph(
4843
                    $final_all_exercise_graph_name_list,
4844
                    $my_results_final,
4845
                    $final_all_exercise_graph_list
4846
                );
4847
            }
4848
4849
            $sessionIcon = Display::return_icon(
4850
                'session.png',
4851
                get_lang('Sessions'),
4852
                array(),
4853
                ICON_SIZE_SMALL
4854
            );
4855
4856
            $anchor = Display::url('', '', ['name' => 'course_session_header']);
4857
            $html .= $anchor.Display::page_subheader(
4858
                $sessionIcon.' '.get_lang('Sessions')
4859
            );
4860
4861
            $html .= '<div class="table-responsive">';
4862
            $html .= '<table class="table table-striped table-hover">';
4863
            $html .= '<thead>';
4864
            $html .= '<tr>
4865
                  '.Display::tag('th', get_lang('Session'), array('width'=>'300px')).'
4866
                  '.Display::tag('th', get_lang('PublishedExercises'), array('width'=>'300px')).'
4867
                  '.Display::tag('th', get_lang('NewExercises')).'
4868
                  '.Display::tag('th', get_lang('AverageExerciseResult')).'
4869
                  '.Display::tag('th', get_lang('Details')).'
4870
                  </tr>';
4871
            $html .= '</thead>';
4872
            $html .= '<tbody>';
4873
4874
            foreach ($course_in_session as $my_session_id => $session_data) {
4875
                $course_list = $session_data['course_list'];
4876
                $session_name = $session_data['name'];
4877
                if ($showAllSessions == false) {
4878
                    if (isset($session_id) && !empty($session_id)) {
4879
                        if ($session_id != $my_session_id) {
4880
                            continue;
4881
                        }
4882
                    }
4883
                }
4884
4885
                $all_exercises = 0;
4886
                $all_unanswered_exercises_by_user = 0;
4887
                $all_average = 0;
4888
                $stats_array = array();
4889
4890
                foreach ($course_list as $course_data) {
4891
                    // All exercises in the course @todo change for a real count
4892
                    $exercises = ExerciseLib::get_all_exercises($course_data, $my_session_id);
4893
                    $count_exercises = 0;
4894
                    if (is_array($exercises) && !empty($exercises)) {
4895
                        $count_exercises = count($exercises);
4896
                    }
4897
4898
                    // Count of user results
4899
                    $done_exercises = null;
4900
                    $courseInfo = api_get_course_info($course_data['code']);
4901
4902
                    $answered_exercises = 0;
4903
                    if (!empty($exercises)) {
4904
                        foreach ($exercises as $exercise_item) {
4905
                            $attempts = Event::count_exercise_attempts_by_user(
4906
                                api_get_user_id(),
4907
                                $exercise_item['id'],
4908
                                $courseInfo['real_id'],
4909
                                $my_session_id
4910
                            );
4911
                            if ($attempts > 1) {
4912
                                $answered_exercises++;
4913
                            }
4914
                        }
4915
                    }
4916
4917
                    // Average
4918
                    $average = ExerciseLib::get_average_score_by_course(
4919
                        $courseInfo['real_id'],
4920
                        $my_session_id
4921
                    );
4922
                    $all_exercises += $count_exercises;
4923
                    $all_unanswered_exercises_by_user += $count_exercises - $answered_exercises;
4924
                    $all_average += $average;
4925
                }
4926
4927
                if (!empty($course_list)) {
4928
                    $all_average = $all_average / count($course_list);
4929
                }
4930
4931
                if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) {
4932
                    $html .= '<tr style="background-color:#FBF09D">';
4933
                } else {
4934
                    $html .= '<tr>';
4935
                }
4936
                $url = api_get_path(WEB_CODE_PATH)."session/index.php?session_id={$my_session_id}";
4937
4938
                $html .= Display::tag('td', Display::url($session_name, $url, array('target'=>SESSION_LINK_TARGET)));
4939
                $html .= Display::tag('td', $all_exercises);
4940
                $html .= Display::tag('td', $all_unanswered_exercises_by_user);
4941
                $html .= Display::tag('td', ExerciseLib::convert_to_percentage($all_average));
4942
4943
                if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) {
4944
                    $icon = Display::url(
4945
                        Display::return_icon(
4946
                            '2rightarrow_na.png',
4947
                            get_lang('Details')
4948
                        ),
4949
                        api_get_self().'?session_id='.$my_session_id.'#course_session_list'
4950
                    );
4951
                } else {
4952
                    $icon = Display::url(
4953
                        Display::return_icon(
4954
                            '2rightarrow.png',
4955
                            get_lang('Details')
4956
                        ),
4957
                        api_get_self().'?session_id='.$my_session_id.'#course_session_list'
4958
                    );
4959
                }
4960
                $html .= Display::tag('td', $icon);
4961
                $html .= '</tr>';
4962
            }
4963
            $html .= '</tbody>';
4964
            $html .= '</table></div><br />';
4965
            $html .= Display::div(
4966
                $main_session_graph,
4967
                array(
4968
                    'id' => 'session_graph',
4969
                    'class' => 'chart-session',
4970
                    'style' => 'position:relative; text-align: center;',
4971
                )
4972
            );
4973
4974
            // Checking selected session.
4975
            if (isset($_GET['session_id'])) {
4976
                $session_id_from_get = intval($_GET['session_id']);
4977
                $session_data = $course_in_session[$session_id_from_get];
4978
                $course_list = $session_data['course_list'];
4979
4980
                $html .= '<a name= "course_session_list"></a>';
4981
                $html .= Display::tag('h3', $session_data['name'].' - '.get_lang('CourseList'));
4982
4983
                $html .= '<div class="table-responsive">';
4984
                $html .= '<table class="table table-hover table-striped">';
4985
4986
                $columnHeaders = [
4987
                    'course_title' => [
4988
                        get_lang('Course'),
4989
                        array('width'=>'300px')
4990
                    ],
4991
                    'published_exercises' => [
4992
                        get_lang('PublishedExercises')
4993
                    ],
4994
                    'new_exercises' => [
4995
                        get_lang('NewExercises'),
4996
                    ],
4997
                    'my_average' => [
4998
                        get_lang('MyAverage'),
4999
                    ],
5000
                    'average_exercise_result'  => [
5001
                        get_lang('AverageExerciseResult'),
5002
                    ],
5003
                    'time_spent'  => [
5004
                        get_lang('TimeSpentInTheCourse'),
5005
                    ],
5006
                    'lp_progress'  => [
5007
                        get_lang('LPProgress'),
5008
                    ],
5009
                    'score'  => [
5010
                        get_lang('Score').Display::return_icon('info3.gif', get_lang('ScormAndLPTestTotalAverage'), array('align' => 'absmiddle', 'hspace' => '3px')),
5011
                    ],
5012
                    'best_score'  => [
5013
                        get_lang('BestScore'),
5014
                    ],
5015
                    'last_connection'  => [
5016
                        get_lang('LastConnexion'),
5017
                    ],
5018
                    'details'  => [
5019
                        get_lang('Details'),
5020
                    ],
5021
                ];
5022
5023
                $html .= '<thead><tr>';
5024
                foreach ($columnHeaders as $key => $columnSetting) {
5025
                    if (isset($trackingColumns['course_session']) &&
5026
                        in_array($key, $trackingColumns['course_session']) &&
5027
                        $trackingColumns['course_session'][$key]
5028
                    ) {
5029
                        $settings = isset($columnSetting[1]) ? $columnSetting[1] : [];
5030
                        $html .= Display::tag(
5031
                             'th',
5032
                             $columnSetting[0],
5033
                             $settings
0 ignored issues
show
Bug introduced by
It seems like $settings defined by isset($columnSetting[1])...umnSetting[1] : array() on line 5029 can also be of type string; however, Display::tag() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
5034
                         );
5035
                    }
5036
                }
5037
5038
                $html .= '</tr>
5039
                    </thead>
5040
                    <tbody>';
5041
5042
                foreach ($course_list as $course_data) {
5043
                    $course_code = $course_data['code'];
5044
                    $course_title = $course_data['title'];
5045
                    $courseId = $course_data['real_id'];
5046
5047
                    // All exercises in the course @todo change for a real count
5048
                    $exercises = ExerciseLib::get_all_exercises(
5049
                        $course_data,
5050
                        $session_id_from_get
5051
                    );
5052
                    $count_exercises = 0;
5053
                    if (!empty($exercises)) {
5054
                        $count_exercises = count($exercises);
5055
                    }
5056
                    $answered_exercises = 0;
5057
                    foreach ($exercises as $exercise_item) {
5058
                        $attempts = Event::count_exercise_attempts_by_user(
5059
                            api_get_user_id(),
5060
                            $exercise_item['id'],
5061
                            $courseId,
5062
                            $session_id_from_get
5063
                        );
5064
                        if ($attempts > 1) {
5065
                            $answered_exercises++;
5066
                        }
5067
                    }
5068
5069
                    $unanswered_exercises = $count_exercises - $answered_exercises;
5070
5071
                    // Average
5072
                    $average = ExerciseLib::get_average_score_by_course(
5073
                        $courseId,
5074
                        $session_id_from_get
5075
                    );
5076
                    $my_average = ExerciseLib::get_average_score_by_course_by_user(
5077
                        api_get_user_id(),
5078
                        $courseId,
5079
                        $session_id_from_get
5080
                    );
5081
5082
                    $bestScore = self::get_avg_student_score(
5083
                        $user_id,
5084
                        $course_code,
5085
                        array(),
5086
                        $session_id_from_get,
5087
                        false,
5088
                        false,
5089
                        true
5090
                    );
5091
5092
                    $stats_array[$course_code] = array(
5093
                        'exercises' => $count_exercises,
5094
                        'unanswered_exercises_by_user' => $unanswered_exercises,
5095
                        'done_exercises' => $done_exercises,
5096
                        'average' => $average,
5097
                        'my_average' => $my_average,
5098
                        'best_score' => $bestScore
5099
                    );
5100
5101
                    $last_connection = self::get_last_connection_date_on_the_course(
5102
                        $user_id,
5103
                        $course_data,
5104
                        $session_id_from_get
5105
                    );
5106
5107
                    $progress = self::get_avg_student_progress(
5108
                        $user_id,
5109
                        $course_code,
5110
                        array(),
5111
                        $session_id_from_get
5112
                    );
5113
5114
                    $total_time_login = self::get_time_spent_on_the_course(
5115
                        $user_id,
5116
                        $courseId,
5117
                        $session_id_from_get
5118
                    );
5119
                    $time = api_time_to_hms($total_time_login);
5120
5121
                    $percentage_score = self::get_avg_student_score(
5122
                        $user_id,
5123
                        $course_code,
5124
                        array(),
5125
                        $session_id_from_get
5126
                    );
5127
                    $courseCodeFromGet = isset($_GET['course']) ? $_GET['course'] : null;
5128
5129
                    if ($course_code == $courseCodeFromGet && $_GET['session_id'] == $session_id_from_get) {
5130
                        $html .= '<tr class="row_odd" style="background-color:#FBF09D" >';
5131
                    } else {
5132
                        $html .= '<tr class="row_even">';
5133
                    }
5134
5135
                    $url = api_get_course_url($course_code, $session_id_from_get);
5136
                    $course_url = Display::url(
5137
                        $course_title,
5138
                        $url,
5139
                        array('target' => SESSION_LINK_TARGET)
5140
                    );
5141
5142
                    if (is_numeric($progress)) {
5143
                        $progress = $progress.'%';
5144
                    } else {
5145
                        $progress = '0%';
5146
                    }
5147
                    if (is_numeric($percentage_score)) {
5148
                        $percentage_score = $percentage_score.'%';
5149
                    } else {
5150
                        $percentage_score = '0%';
5151
                    }
5152
5153
                    if (is_numeric($stats_array[$course_code]['best_score'])) {
5154
                        $bestScore = $stats_array[$course_code]['best_score'].'%';
5155
                    } else {
5156
                        $bestScore = '-';
5157
                    }
5158
5159
                    if (empty($last_connection) || is_bool($last_connection)) {
5160
                        $last_connection = '';
5161
                    }
5162
5163
                    if ($course_code == $courseCodeFromGet &&
5164
                        $_GET['session_id'] == $session_id_from_get
5165
                    ) {
5166
                        $details = Display::url(
5167
                            Display::return_icon('2rightarrow_na.png', get_lang('Details')),
5168
                        '#course_session_data'
5169
                        );
5170
                    } else {
5171
                        $url = api_get_self().'?course='.$course_code.'&session_id='.$session_id_from_get.$extra_params.'#course_session_data';
5172
                        $details = Display::url(
5173
                            Display::return_icon(
5174
                                '2rightarrow.png',
5175
                                get_lang('Details')
5176
                            ),
5177
                            $url
5178
                        );
5179
                    }
5180
                    $details .= '</a>';
5181
5182
                    $data = [
5183
                        'course_title' => $course_url,
5184
                        'published_exercises' => $stats_array[$course_code]['exercises'], // exercise available
5185
                        'new_exercises' => $stats_array[$course_code]['unanswered_exercises_by_user'],
5186
                        'my_average' => ExerciseLib::convert_to_percentage($stats_array[$course_code]['my_average']),
5187
                        'average_exercise_result' => $stats_array[$course_code]['average'] == 0 ? '-' : '('.ExerciseLib::convert_to_percentage($stats_array[$course_code]['average']).')',
5188
                        'time_spent' => $time,
5189
                        'lp_progress' => $progress,
5190
                        'score' => $percentage_score,
5191
                        'best_score' => $bestScore,
5192
                        'last_connection' => $last_connection,
5193
                        'details' => $details,
5194
                    ];
5195
5196
                    foreach ($data as $key => $value) {
5197
                        if (in_array($key, $trackingColumns['course_session'])
5198
                            && $trackingColumns['course_session'][$key]
5199
                        ) {
5200
                            $html .= Display::tag('td', $value);
5201
                        }
5202
                    }
5203
                    $html .= '</tr>';
5204
                }
5205
                $html .= '</tbody></table></div>';
5206
            }
5207
        }
5208
5209
        return $html;
5210
    }
5211
5212
    /**
5213
     * Shows the user detail progress (when clicking in the details link)
5214
     * @param   int     $user_id
5215
     * @param   string  $course_code
5216
     * @param   int     $session_id
5217
     * @return  string  html code
5218
     */
5219
    public static function show_course_detail($user_id, $course_code, $session_id)
5220
    {
5221
        $html = '';
5222
        if (isset($course_code)) {
5223
            $user_id = intval($user_id);
5224
            $session_id = intval($session_id);
5225
            $course = Database::escape_string($course_code);
5226
            $course_info = api_get_course_info($course);
5227
            if (empty($course_info)) {
5228
                return '';
5229
            }
5230
5231
            $html .= '<a name="course_session_data"></a>';
5232
            $html .= Display::page_subheader($course_info['title']);
5233
            $html .= '<div class="table-responsive">';
5234
            $html .= '<table class="table table-striped table-hover">';
5235
5236
            //Course details
5237
            $html .= '
5238
                <thead>
5239
                <tr>
5240
                <th>'.get_lang('Exercises').'</th>
5241
                <th>'.get_lang('Attempts').'</th>
5242
                <th>'.get_lang('BestAttempt').'</th>
5243
                <th>'.get_lang('Ranking').'</th>
5244
                <th>'.get_lang('BestResultInCourse').'</th>
5245
                <th>'.get_lang('Statistics').' '.Display::return_icon('info3.gif', get_lang('OnlyBestResultsPerStudent'), array('align' => 'absmiddle', 'hspace' => '3px')).'</th>
5246
                </tr>
5247
                </thead>
5248
                <tbody>';
5249
5250
            if (empty($session_id)) {
5251
                $user_list = CourseManager::get_user_list_from_course_code(
5252
                    $course,
5253
                    $session_id,
5254
                    null,
5255
                    null,
5256
                    STUDENT
5257
                );
5258
            } else {
5259
                $user_list = CourseManager::get_user_list_from_course_code(
5260
                    $course,
5261
                    $session_id,
5262
                    null,
5263
                    null,
5264
                    0
5265
                );
5266
            }
5267
5268
            // Show exercise results of invisible exercises? see BT#4091
5269
            $exercise_list = ExerciseLib::get_all_exercises(
5270
                $course_info,
5271
                $session_id,
5272
                false,
5273
                null,
5274
                false,
5275
                2
5276
            );
5277
5278
            $to_graph_exercise_result = array();
5279
            if (!empty($exercise_list)) {
5280
                $score = $weighting = $exe_id = 0;
5281
                foreach ($exercise_list as $exercices) {
5282
5283
                    $exercise_obj = new Exercise($course_info['real_id']);
5284
                    $exercise_obj->read($exercices['id']);
5285
                    $visible_return = $exercise_obj->is_visible();
5286
                    $score = $weighting = $attempts = 0;
5287
5288
                    // Getting count of attempts by user
5289
                    $attempts = Event::count_exercise_attempts_by_user(
5290
                        api_get_user_id(),
5291
                        $exercices['id'],
5292
                        $course_info['real_id'],
5293
                        $session_id
5294
                    );
5295
5296
                    $html .= '<tr class="row_even">';
5297
                    $url = api_get_path(WEB_CODE_PATH)."exercise/overview.php?cidReq={$course_info['code']}&id_session=$session_id&exerciseId={$exercices['id']}";
5298
5299
                    if ($visible_return['value'] == true) {
5300
                        $exercices['title'] = Display::url(
5301
                            $exercices['title'],
5302
                            $url,
5303
                            array('target' => SESSION_LINK_TARGET)
5304
                        );
5305
                    } elseif ($exercices['active'] == -1) {
5306
                        $exercices['title'] = sprintf(get_lang('XParenthesisDeleted'), $exercices['title']);
5307
                    }
5308
5309
                    $html .= Display::tag('td', $exercices['title']);
5310
5311
                    // Exercise configuration show results or show only score
5312
                    if ($exercices['results_disabled'] == 0 || $exercices['results_disabled'] == 2) {
5313
                        //For graphics
5314
                        $best_exercise_stats = Event::get_best_exercise_results_by_user(
5315
                            $exercices['id'],
5316
                            $course_info['real_id'],
5317
                            $session_id
5318
                        );
5319
5320
                        $to_graph_exercise_result[$exercices['id']] = array(
5321
                            'title' => $exercices['title'],
5322
                            'data' => $best_exercise_stats
5323
                        );
5324
5325
                        $latest_attempt_url = '';
5326
                        $best_score = $position = $percentage_score_result = '-';
5327
                        $graph = $normal_graph = null;
5328
5329
                        // Getting best results
5330
                        $best_score_data = ExerciseLib::get_best_attempt_in_course(
5331
                            $exercices['id'],
5332
                            $course_info['real_id'],
5333
                            $session_id
5334
                        );
5335
5336
                        $best_score = '';
5337
                        if (!empty($best_score_data)) {
5338
                            $best_score = ExerciseLib::show_score(
5339
                                $best_score_data['exe_result'],
5340
                                $best_score_data['exe_weighting']
5341
                            );
5342
                        }
5343
5344
                        if ($attempts > 0) {
5345
                            $exercise_stat = ExerciseLib::get_best_attempt_by_user(
5346
                                api_get_user_id(),
5347
                                $exercices['id'],
5348
                                $course_info['real_id'],
5349
                                $session_id
5350
                            );
5351
                            if (!empty($exercise_stat)) {
5352
                                // Always getting the BEST attempt
5353
                                $score = $exercise_stat['exe_result'];
5354
                                $weighting = $exercise_stat['exe_weighting'];
5355
                                $exe_id = $exercise_stat['exe_id'];
5356
5357
                                $latest_attempt_url .= api_get_path(WEB_CODE_PATH).'exercise/result.php?id='.$exe_id.'&cidReq='.$course_info['code'].'&show_headers=1&id_session='.$session_id;
5358
                                $percentage_score_result = Display::url(
5359
                                    ExerciseLib::show_score($score, $weighting),
5360
                                    $latest_attempt_url
5361
                                );
5362
                                $my_score = 0;
5363
                                if (!empty($weighting) && intval($weighting) != 0) {
5364
                                    $my_score = $score / $weighting;
5365
                                }
5366
                                //@todo this function slows the page
5367
                                if (is_int($user_list)) {
5368
                                    $user_list = array($user_list);
5369
                                }
5370
                                $position = ExerciseLib::get_exercise_result_ranking(
5371
                                    $my_score,
5372
                                    $exe_id,
5373
                                    $exercices['id'],
5374
                                    $course_info['code'],
5375
                                    $session_id,
5376
                                    $user_list
5377
                                );
5378
5379
                                $graph = self::generate_exercise_result_thumbnail_graph(
5380
                                    $to_graph_exercise_result[$exercices['id']]
5381
                                );
5382
                                $normal_graph = self::generate_exercise_result_graph(
5383
                                    $to_graph_exercise_result[$exercices['id']]
5384
                                );
5385
                            }
5386
                        }
5387
                        $html .= Display::div(
5388
                            $normal_graph,
5389
                            array(
5390
                                'id' => 'main_graph_'.$exercices['id'],
5391
                                'class' => 'dialog',
5392
                                'style' => 'display:none'
5393
                            )
5394
                        );
5395
5396
                        if (empty($graph)) {
5397
                            $graph = '-';
5398
                        } else {
5399
                            $graph = Display::url(
5400
                                '<img src="'.$graph.'" >',
5401
                                $normal_graph,
5402
                                array(
5403
                                    'id' => $exercices['id'],
5404
                                    'class' => 'expand-image',
5405
                                )
5406
                            );
5407
                        }
5408
5409
                        $html .= Display::tag('td', $attempts, array('align'=>'center'));
5410
                        $html .= Display::tag('td', $percentage_score_result, array('align'=>'center'));
5411
                        $html .= Display::tag('td', $position, array('align'=>'center'));
5412
                        $html .= Display::tag('td', $best_score, array('align'=>'center'));
5413
                        $html .= Display::tag('td', $graph, array('align'=>'center'));
5414
                        //$html .= Display::tag('td', $latest_attempt_url,       array('align'=>'center', 'width'=>'25'));
5415
5416
                    } else {
5417
                        // Exercise configuration NO results
5418
                        $html .= Display::tag('td', $attempts, array('align'=>'center'));
5419
                        $html .= Display::tag('td', '-', array('align'=>'center'));
5420
                        $html .= Display::tag('td', '-', array('align'=>'center'));
5421
                        $html .= Display::tag('td', '-', array('align'=>'center'));
5422
                        $html .= Display::tag('td', '-', array('align'=>'center'));
5423
                    }
5424
                    $html .= '</tr>';
5425
                }
5426
            } else {
5427
                $html .= '<tr><td colspan="5" align="center">'.get_lang('NoEx').'</td></tr>';
5428
            }
5429
            $html .= '</tbody></table></div>';
5430
5431
            $columnHeaders = [
5432
                'lp' => get_lang('LearningPath'),
5433
                'time' => get_lang('LatencyTimeSpent'),
5434
                'progress' => get_lang('Progress'),
5435
                'score' => get_lang('Score'),
5436
                'best_score' => get_lang('BestScore'),
5437
                'last_connection' => get_lang('LastConnexion'),
5438
            ];
5439
5440
            $headers = '';
5441
            $trackingColumns = api_get_configuration_value('tracking_columns');
5442
            if (isset($trackingColumns['my_progress_lp'])) {
5443
                foreach ($columnHeaders as $key => $value) {
5444
                    if (!isset($trackingColumns['my_progress_lp'][$key]) ||
5445
                        $trackingColumns['my_progress_lp'][$key] == false
5446
                    ) {
5447
                        unset($columnHeaders[$key]);
5448
                    }
5449
                }
5450
            }
5451
5452
            $columnHeadersKeys = array_keys($columnHeaders);
5453
            foreach ($columnHeaders as $key => $columnName) {
5454
                $headers .= Display::tag(
5455
                    'th',
5456
                    $columnName
5457
                );
5458
            }
5459
5460
            // LP table results
5461
            $html .= '<div class="table-responsive">';
5462
            $html .= '<table class="table table-striped table-hover">';
5463
            $html .= '<thead><tr>';
5464
            $html .= $headers;
5465
            $html .= '</tr></thead><tbody>';
5466
5467
            $list = new LearnpathList(
5468
                api_get_user_id(),
5469
                $course_info['code'],
5470
                $session_id,
5471
                'lp.publicatedOn ASC',
5472
                true,
5473
                null,
5474
                true
5475
            );
5476
5477
            $lp_list = $list->get_flat_list();
5478
5479
            if (!empty($lp_list) > 0) {
5480
                foreach ($lp_list as $lp_id => $learnpath) {
5481
                    $progress = self::get_avg_student_progress(
5482
                        $user_id,
5483
                        $course,
5484
                        array($lp_id),
5485
                        $session_id
5486
                    );
5487
                    $last_connection_in_lp = self::get_last_connection_time_in_lp(
5488
                        $user_id,
5489
                        $course,
5490
                        $lp_id,
5491
                        $session_id
5492
                    );
5493
                    $time_spent_in_lp = self::get_time_spent_in_lp(
5494
                        $user_id,
5495
                        $course,
5496
                        array($lp_id),
5497
                        $session_id
5498
                    );
5499
                    $percentage_score = self::get_avg_student_score(
5500
                        $user_id,
5501
                        $course,
5502
                        array($lp_id),
5503
                        $session_id
5504
                    );
5505
5506
                    $bestScore = self::get_avg_student_score(
5507
                        $user_id,
5508
                        $course,
5509
                        array($lp_id),
5510
                        $session_id,
5511
                        false,
5512
                        false,
5513
                        true
5514
                    );
5515
5516
                    if (is_numeric($progress)) {
5517
                        $progress = $progress.'%';
5518
                    }
5519
                    if (is_numeric($percentage_score)) {
5520
                        $percentage_score = $percentage_score.'%';
5521
                    } else {
5522
                        $percentage_score = '0%';
5523
                    }
5524
5525
                    if (is_numeric($bestScore)) {
5526
                        $bestScore = $bestScore.'%';
5527
                    } else {
5528
                        $bestScore = '-';
5529
                    }
5530
5531
                    $time_spent_in_lp = api_time_to_hms($time_spent_in_lp);
5532
                    $last_connection = '-';
5533
                    if (!empty($last_connection_in_lp)) {
5534
                        $last_connection = api_convert_and_format_date(
5535
                            $last_connection_in_lp,
5536
                            DATE_TIME_FORMAT_LONG
5537
                        );
5538
                    }
5539
5540
                    $url = api_get_path(WEB_CODE_PATH)."lp/lp_controller.php?cidReq={$course_code}&id_session=$session_id&lp_id=$lp_id&action=view";
5541
                    $html .= '<tr class="row_even">';
5542
5543
                    if (in_array('lp', $columnHeadersKeys)) {
5544
                        if ($learnpath['lp_visibility'] == 0) {
5545
                            $html .= Display::tag('td', $learnpath['lp_name']);
5546
                        } else {
5547
                            $html .= Display::tag(
5548
                                'td',
5549
                                Display::url(
5550
                                    $learnpath['lp_name'],
5551
                                    $url,
5552
                                    array('target' => SESSION_LINK_TARGET)
5553
                                )
5554
                            );
5555
                        }
5556
                    }
5557
5558
                    if (in_array('time', $columnHeadersKeys)) {
5559
                        $html .= Display::tag(
5560
                            'td',
5561
                            $time_spent_in_lp,
5562
                            array('align' => 'center')
5563
                        );
5564
                    }
5565
5566
                    if (in_array('progress', $columnHeadersKeys)) {
5567
                        $html .= Display::tag(
5568
                            'td',
5569
                            $progress,
5570
                            array('align' => 'center')
5571
                        );
5572
                    }
5573
5574
                    if (in_array('score', $columnHeadersKeys)) {
5575
                        $html .= Display::tag('td', $percentage_score);
5576
                    }
5577
                    if (in_array('best_score', $columnHeadersKeys)) {
5578
                        $html .= Display::tag('td', $bestScore);
5579
                    }
5580
5581
                    if (in_array('last_connection', $columnHeadersKeys)) {
5582
                        $html .= Display::tag('td', $last_connection, array('align'=>'center', 'width'=>'180px'));
5583
                    }
5584
                    $html .= '</tr>';
5585
                }
5586
            } else {
5587
                $html .= '<tr>
5588
                        <td colspan="4" align="center">
5589
                            '.get_lang('NoLearnpath').'
5590
                        </td>
5591
                      </tr>';
5592
            }
5593
            $html .= '</tbody></table></div>';
5594
5595
            $html .= self::displayUserSkills($user_id, $course_info['id'], $session_id);
5596
        }
5597
5598
        return $html;
5599
    }
5600
5601
    /**
5602
     * Generates an histogram
5603
     * @param array $names list of exercise names
5604
     * @param array $my_results my results 0 to 100
5605
     * @param array $average average scores 0-100
5606
     * @return string
5607
     */
5608
    static function generate_session_exercise_graph($names, $my_results, $average)
5609
    {
5610
        /* Create and populate the pData object */
5611
        $myData = new pData();
5612
        $myData->addPoints($names, 'Labels');
5613
        $myData->addPoints($my_results, 'Serie1');
5614
        $myData->addPoints($average, 'Serie2');
5615
        $myData->setSerieWeight('Serie1', 1);
5616
        $myData->setSerieTicks('Serie2', 4);
5617
        $myData->setSerieDescription('Labels', 'Months');
5618
        $myData->setAbscissa('Labels');
5619
        $myData->setSerieDescription('Serie1', get_lang('MyResults'));
5620
        $myData->setSerieDescription('Serie2', get_lang('AverageScore'));
5621
        $myData->setAxisUnit(0, '%');
5622
        $myData->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
5623
        // Cache definition
5624
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
5625
        $myCache = new pCache(array('CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)));
5626
        $chartHash = $myCache->getHash($myData);
5627
5628
        if ($myCache->isInCache($chartHash)) {
5629
            //if we already created the img
5630
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
5631
            $myCache->saveFromCache($chartHash, $imgPath);
5632
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
5633
        } else {
5634
            /* Define width, height and angle */
5635
            $mainWidth = 860;
5636
            $mainHeight = 500;
5637
            $angle = 50;
5638
5639
            /* Create the pChart object */
5640
            $myPicture = new pImage($mainWidth, $mainHeight, $myData);
5641
5642
            /* Turn of Antialiasing */
5643
            $myPicture->Antialias = false;
5644
5645
            /* Draw the background */
5646
            $settings = array('R' => 255, 'G' => 255, 'B' => 255);
5647
            $myPicture->drawFilledRectangle(0, 0, $mainWidth, $mainHeight, $settings);
5648
5649
            /* Add a border to the picture */
5650
            $myPicture->drawRectangle(
5651
                0,
5652
                0,
5653
                $mainWidth - 1,
5654
                $mainHeight - 1,
5655
                array('R' => 0, 'G' => 0, 'B' => 0)
5656
            );
5657
5658
            /* Set the default font */
5659
            $myPicture->setFontProperties(
5660
                array(
5661
                    'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
5662
                    'FontSize' => 10)
5663
            );
5664
            /* Write the chart title */
5665
            $myPicture->drawText(
5666
                $mainWidth / 2,
5667
                30,
5668
                get_lang('ExercisesInTimeProgressChart'),
5669
                array(
5670
                    'FontSize' => 12,
5671
                    'Align' => TEXT_ALIGN_BOTTOMMIDDLE
5672
                )
5673
            );
5674
5675
            /* Set the default font */
5676
            $myPicture->setFontProperties(
5677
                array(
5678
                    'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
5679
                    'FontSize' => 6
5680
                )
5681
            );
5682
5683
            /* Define the chart area */
5684
            $myPicture->setGraphArea(60, 60, $mainWidth - 60, $mainHeight - 150);
5685
5686
            /* Draw the scale */
5687
            $scaleSettings = array(
5688
                'XMargin' => 10,
5689
                'YMargin' => 10,
5690
                'Floating' => true,
5691
                'GridR' => 200,
5692
                'GridG' => 200,
5693
                'GridB' => 200,
5694
                'DrawSubTicks' => true,
5695
                'CycleBackground' => true,
5696
                'LabelRotation' => $angle,
5697
                'Mode' => SCALE_MODE_ADDALL_START0,
5698
            );
5699
            $myPicture->drawScale($scaleSettings);
5700
5701
            /* Turn on Antialiasing */
5702
            $myPicture->Antialias = true;
5703
5704
            /* Enable shadow computing */
5705
            $myPicture->setShadow(
5706
                true,
5707
                array(
5708
                    'X' => 1,
5709
                    'Y' => 1,
5710
                    'R' => 0,
5711
                    'G' => 0,
5712
                    'B' => 0,
5713
                    'Alpha' => 10
5714
                )
5715
            );
5716
5717
            /* Draw the line chart */
5718
            $myPicture->setFontProperties(
5719
                array(
5720
                    'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
5721
                    'FontSize' => 10
5722
                )
5723
            );
5724
            $myPicture->drawSplineChart();
5725
            $myPicture->drawPlotChart(
5726
                array(
5727
                    'DisplayValues' => true,
5728
                    'PlotBorder' => true,
5729
                    'BorderSize' => 1,
5730
                    'Surrounding' => -60,
5731
                    'BorderAlpha' => 80
5732
                )
5733
            );
5734
5735
            /* Write the chart legend */
5736
            $myPicture->drawLegend(
5737
                $mainWidth / 2 + 50,
5738
                50,
5739
                array(
5740
                    'Style' => LEGEND_BOX,
5741
                    'Mode' => LEGEND_HORIZONTAL,
5742
                    'FontR' => 0,
5743
                    'FontG' => 0,
5744
                    'FontB' => 0,
5745
                    'R' => 220,
5746
                    'G' => 220,
5747
                    'B' => 220,
5748
                    'Alpha' => 100
5749
                )
5750
            );
5751
5752
            $myCache->writeToCache($chartHash, $myPicture);
5753
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
5754
            $myCache->saveFromCache($chartHash, $imgPath);
5755
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
5756
        }
5757
5758
        $html = '<img src="'.$imgPath.'">';
5759
5760
        return $html;
5761
    }
5762
5763
    /**
5764
     * Returns a thumbnail of the function generate_exercise_result_graph
5765
     * @param  array $attempts
5766
     */
5767
    static function generate_exercise_result_thumbnail_graph($attempts)
5768
    {
5769
        //$exercise_title = $attempts['title'];
5770
        $attempts = $attempts['data'];
5771
        $my_exercise_result_array = $exercise_result = array();
5772
        if (empty($attempts)) {
5773
            return null;
5774
        }
5775
5776 View Code Duplication
        foreach ($attempts as $attempt) {
5777
            if (api_get_user_id() == $attempt['exe_user_id']) {
5778
                if ($attempt['exe_weighting'] != 0) {
5779
                    $my_exercise_result_array[] = $attempt['exe_result'] / $attempt['exe_weighting'];
5780
                }
5781
            } else {
5782
                if ($attempt['exe_weighting'] != 0) {
5783
                    $exercise_result[] = $attempt['exe_result'] / $attempt['exe_weighting'];
5784
                }
5785
            }
5786
        }
5787
5788
        //Getting best result
5789
        rsort($my_exercise_result_array);
5790
        $my_exercise_result = 0;
5791
        if (isset($my_exercise_result_array[0])) {
5792
            $my_exercise_result = $my_exercise_result_array[0] * 100;
5793
        }
5794
5795
        $max     = 100;
5796
        $pieces  = 5;
5797
        $part    = round($max / $pieces);
5798
        $x_axis = array();
5799
        $final_array = array();
5800
        $my_final_array = array();
5801
5802 View Code Duplication
        for ($i = 1; $i <= $pieces; $i++) {
5803
            $sum = 1;
5804
            if ($i == 1) {
5805
                $sum = 0;
5806
            }
5807
            $min = ($i - 1) * $part + $sum;
5808
            $max = ($i) * $part;
5809
            $x_axis[] = $min." - ".$max;
5810
            $count = 0;
5811
            foreach ($exercise_result as $result) {
5812
                $percentage = $result * 100;
5813
                //echo $percentage.' - '.$min.' - '.$max."<br />";
5814
                if ($percentage >= $min && $percentage <= $max) {
5815
                    //echo ' is > ';
5816
                    $count++;
5817
                }
5818
            }
5819
            //echo '<br />';
5820
            $final_array[] = $count;
5821
5822
            if ($my_exercise_result >= $min && $my_exercise_result <= $max) {
5823
                $my_final_array[] = 1;
5824
            } else {
5825
                $my_final_array[] = 0;
5826
            }
5827
        }
5828
5829
        //Fix to remove the data of the user with my data
5830 View Code Duplication
        for ($i = 0; $i <= count($my_final_array); $i++) {
5831
            if (!empty($my_final_array[$i])) {
5832
                $my_final_array[$i] = $final_array[$i] + 1; //Add my result
5833
                $final_array[$i] = 0;
5834
            }
5835
        }
5836
5837
        // Dataset definition
5838
        $dataSet = new pData();
5839
        $dataSet->addPoints($final_array, 'Serie1');
5840
        $dataSet->addPoints($my_final_array, 'Serie2');
5841
        $dataSet->normalize(100, "%");
5842
        $dataSet->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
5843
5844
        // Cache definition
5845
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
5846
        $myCache = new pCache(array('CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)));
5847
        $chartHash = $myCache->getHash($dataSet);
5848
        if ($myCache->isInCache($chartHash)) {
5849
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
5850
            $myCache->saveFromCache($chartHash, $imgPath);
5851
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
5852
        } else {
5853
            /* Create the pChart object */
5854
            $widthSize = 80;
5855
            $heightSize = 35;
5856
            $fontSize = 2;
5857
5858
            $myPicture = new pImage($widthSize, $heightSize, $dataSet);
5859
5860
            /* Turn of Antialiasing */
5861
            $myPicture->Antialias = false;
5862
5863
            /* Add a border to the picture */
5864
            $myPicture->drawRectangle(
5865
                0,
5866
                0,
5867
                $widthSize - 1,
5868
                $heightSize - 1,
5869
                array('R' => 0, 'G' => 0, 'B' => 0)
5870
            );
5871
5872
            /* Set the default font */
5873
            $myPicture->setFontProperties(
5874
                array(
5875
                    'FontName' => api_get_path(
5876
                            SYS_FONTS_PATH
5877
                        ).'opensans/OpenSans-Regular.ttf',
5878
                    'FontSize' => $fontSize
5879
                )
5880
            );
5881
5882
            /* Do not write the chart title */
5883
5884
            /* Define the chart area */
5885
            $myPicture->setGraphArea(5, 5, $widthSize - 5, $heightSize - 5);
5886
5887
            /* Draw the scale */
5888
            $scaleSettings = array(
5889
                'GridR' => 200,
5890
                'GridG' => 200,
5891
                'GridB' => 200,
5892
                'DrawSubTicks' => true,
5893
                'CycleBackground' => true,
5894
                'Mode' => SCALE_MODE_MANUAL,
5895
                'ManualScale' => array(
5896
                    '0' => array(
5897
                        'Min' => 0,
5898
                        'Max' => 100
5899
                    )
5900
                )
5901
            );
5902
            $myPicture->drawScale($scaleSettings);
5903
5904
            /* Turn on shadow computing */
5905
            $myPicture->setShadow(
5906
                true,
5907
                array(
5908
                    'X' => 1,
5909
                    'Y' => 1,
5910
                    'R' => 0,
5911
                    'G' => 0,
5912
                    'B' => 0,
5913
                    'Alpha' => 10
5914
                )
5915
            );
5916
5917
            /* Draw the chart */
5918
            $myPicture->setShadow(
5919
                true,
5920
                array(
5921
                    'X' => 1,
5922
                    'Y' => 1,
5923
                    'R' => 0,
5924
                    'G' => 0,
5925
                    'B' => 0,
5926
                    'Alpha' => 10
5927
                )
5928
            );
5929
            $settings = array(
5930
                'DisplayValues' => true,
5931
                'DisplaySize' => $fontSize,
5932
                'DisplayR' => 0,
5933
                'DisplayG' => 0,
5934
                'DisplayB' => 0,
5935
                'DisplayOrientation' => ORIENTATION_HORIZONTAL,
5936
                'Gradient' => false,
5937
                'Surrounding' => 5,
5938
                'InnerSurrounding' => 5
5939
            );
5940
            $myPicture->drawStackedBarChart($settings);
5941
5942
            /* Save and write in cache */
5943
            $myCache->writeToCache($chartHash, $myPicture);
5944
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
5945
            $myCache->saveFromCache($chartHash, $imgPath);
5946
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
5947
        }
5948
5949
        return $imgPath;
5950
    }
5951
5952
    /**
5953
     * Generates a big graph with the number of best results
5954
     * @param	array
5955
     */
5956
    static function generate_exercise_result_graph($attempts)
5957
    {
5958
        $exercise_title = strip_tags($attempts['title']);
5959
        $attempts       = $attempts['data'];
5960
        $my_exercise_result_array = $exercise_result = array();
5961
        if (empty($attempts)) {
5962
            return null;
5963
        }
5964 View Code Duplication
        foreach ($attempts as $attempt) {
5965
            if (api_get_user_id() == $attempt['exe_user_id']) {
5966
                if ($attempt['exe_weighting'] != 0) {
5967
                    $my_exercise_result_array[] = $attempt['exe_result'] / $attempt['exe_weighting'];
5968
                }
5969
            } else {
5970
                if ($attempt['exe_weighting'] != 0) {
5971
                    $exercise_result[] = $attempt['exe_result'] / $attempt['exe_weighting'];
5972
                }
5973
            }
5974
        }
5975
5976
        //Getting best result
5977
        rsort($my_exercise_result_array);
5978
        $my_exercise_result = 0;
5979
        if (isset($my_exercise_result_array[0])) {
5980
            $my_exercise_result = $my_exercise_result_array[0] * 100;
5981
        }
5982
5983
        $max = 100;
5984
        $pieces = 5;
5985
        $part = round($max / $pieces);
5986
        $x_axis = array();
5987
        $final_array = array();
5988
        $my_final_array = array();
5989
5990 View Code Duplication
        for ($i = 1; $i <= $pieces; $i++) {
5991
            $sum = 1;
5992
            if ($i == 1) {
5993
                $sum = 0;
5994
            }
5995
            $min = ($i - 1) * $part + $sum;
5996
            $max = ($i) * $part;
5997
            $x_axis[] = $min." - ".$max;
5998
            $count = 0;
5999
            foreach ($exercise_result as $result) {
6000
                $percentage = $result * 100;
6001
                if ($percentage >= $min && $percentage <= $max) {
6002
                    $count++;
6003
                }
6004
            }
6005
            $final_array[] = $count;
6006
6007
            if ($my_exercise_result >= $min && $my_exercise_result <= $max) {
6008
                $my_final_array[] = 1;
6009
            } else {
6010
                $my_final_array[] = 0;
6011
            }
6012
        }
6013
6014
        //Fix to remove the data of the user with my data
6015
6016 View Code Duplication
        for ($i = 0; $i <= count($my_final_array); $i++) {
6017
            if (!empty($my_final_array[$i])) {
6018
                $my_final_array[$i] = $final_array[$i] + 1; //Add my result
6019
                $final_array[$i] = 0;
6020
            }
6021
        }
6022
6023
        // Dataset definition
6024
        $dataSet = new pData();
6025
        $dataSet->addPoints($final_array, 'Serie1');
6026
        $dataSet->addPoints($my_final_array, 'Serie2');
6027
        $dataSet->addPoints($x_axis, 'Serie3');
6028
6029
        $dataSet->setSerieDescription('Serie1', get_lang('Score'));
6030
        $dataSet->setSerieDescription('Serie2', get_lang('MyResults'));
6031
        $dataSet->setAbscissa('Serie3');
6032
6033
        $dataSet->setXAxisName(get_lang('Score'));
6034
        $dataSet->normalize(100, "%");
6035
6036
        $dataSet->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
6037
6038
        // Cache definition
6039
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
6040
        $myCache = new pCache(array('CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)));
6041
        $chartHash = $myCache->getHash($dataSet);
6042
6043
        if ($myCache->isInCache($chartHash)) {
6044
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
6045
            $myCache->saveFromCache($chartHash, $imgPath);
6046
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
6047
        } else {
6048
            /* Create the pChart object */
6049
            $widthSize = 480;
6050
            $heightSize = 250;
6051
            $fontSize = 8;
6052
            $myPicture = new pImage($widthSize, $heightSize, $dataSet);
6053
6054
            /* Turn of Antialiasing */
6055
            $myPicture->Antialias = false;
6056
6057
            /* Add a border to the picture */
6058
            $myPicture->drawRectangle(0, 0, $widthSize - 1, $heightSize - 1, array('R' => 0, 'G' => 0, 'B' => 0));
6059
6060
            /* Set the default font */
6061
            $myPicture->setFontProperties(
6062
                array(
6063
                    'FontName' => api_get_path(
6064
                            SYS_FONTS_PATH
6065
                        ).'opensans/OpenSans-Regular.ttf',
6066
                    'FontSize' => 10
6067
                )
6068
            );
6069
6070
            /* Write the chart title */
6071
            $myPicture->drawText(
6072
                250,
6073
                20,
6074
                $exercise_title,
6075
                array(
6076
                    'FontSize' => 12,
6077
                    'Align' => TEXT_ALIGN_BOTTOMMIDDLE
6078
                )
6079
            );
6080
6081
            /* Define the chart area */
6082
            $myPicture->setGraphArea(50, 50, $widthSize - 20, $heightSize - 30);
6083
6084
            /* Draw the scale */
6085
            $scaleSettings = array(
6086
                'GridR' => 200,
6087
                'GridG' => 200,
6088
                'GridB' => 200,
6089
                'DrawSubTicks' => true,
6090
                'CycleBackground' => true,
6091
                'Mode' => SCALE_MODE_MANUAL,
6092
                'ManualScale' => array(
6093
                    '0' => array(
6094
                        'Min' => 0,
6095
                        'Max' => 100
6096
                    )
6097
                )
6098
            );
6099
            $myPicture->drawScale($scaleSettings);
6100
6101
            /* Turn on shadow computing */
6102
            $myPicture->setShadow(true, array('X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10));
6103
6104
            /* Draw the chart */
6105
            $myPicture->setShadow(true, array('X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10));
6106
            $settings = array(
6107
                'DisplayValues' => true,
6108
                'DisplaySize' => $fontSize,
6109
                'DisplayR' => 0,
6110
                'DisplayG' => 0,
6111
                'DisplayB' => 0,
6112
                'DisplayOrientation' => ORIENTATION_HORIZONTAL,
6113
                'Gradient' => false,
6114
                'Surrounding' => 30,
6115
                'InnerSurrounding' => 25
6116
            );
6117
            $myPicture->drawStackedBarChart($settings);
6118
6119
            $legendSettings = array(
6120
                'Mode' => LEGEND_HORIZONTAL,
6121
                'Style' => LEGEND_NOBORDER,
6122
            );
6123
            $myPicture->drawLegend($widthSize / 2, 30, $legendSettings);
6124
6125
            /* Write and save into cache */
6126
            $myCache->writeToCache($chartHash, $myPicture);
6127
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
6128
            $myCache->saveFromCache($chartHash, $imgPath);
6129
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
6130
        }
6131
6132
        return $imgPath;
6133
    }
6134
6135
    /**
6136
    * @param FormValidator $form
6137
    * @return mixed
6138
    */
6139
    public static function setUserSearchForm($form)
6140
    {
6141
        global $_configuration;
6142
        $form->addElement('text', 'keyword', get_lang('Keyword'));
6143
        $form->addElement(
6144
            'select',
6145
            'active',
6146
            get_lang('Status'),
6147
            array(1 => get_lang('Active'), 0 => get_lang('Inactive'))
6148
        );
6149
6150
        $form->addElement(
6151
            'select',
6152
            'sleeping_days',
6153
            get_lang('InactiveDays'),
6154
            array(
6155
                '',
6156
                1 => 1,
6157
                5 => 5,
6158
                15 => 15,
6159
                30 => 30,
6160
                60 => 60,
6161
                90 => 90,
6162
                120 => 120,
6163
            )
6164
        );
6165
6166
        $form->addButtonSearch(get_lang('Search'));
6167
6168
        return $form;
6169
    }
6170
6171
    /**
6172
     * Get the progress of a exercise
6173
     * @param   int $sessionId  The session ID (session.id)
6174
     * @param   int $courseId   The course ID (course.id)
6175
     * @param   int $exerciseId The quiz ID (c_quiz.id)
6176
     * @param   string $date_from
6177
     * @param   string $date_to
6178
     * @param   array   $options    An array of options you can pass to the query (limit, where and order)
6179
     * @return array An array with the data of exercise(s) progress
6180
     */
6181
    public static function get_exercise_progress(
6182
        $sessionId = 0,
6183
        $courseId = 0,
6184
        $exerciseId = 0,
6185
        $date_from = null,
6186
        $date_to = null,
6187
        $options = array()
6188
    ) {
6189
        $sessionId  = intval($sessionId);
6190
        $courseId   = intval($courseId);
6191
        $exerciseId = intval($exerciseId);
6192
        $date_from  = Database::escape_string($date_from);
6193
        $date_to    = Database::escape_string($date_to);
6194
        /*
6195
         * This method gets the data by blocks, as previous attempts at one single
6196
         * query made it take ages. The logic of query division is described below
6197
         */
6198
        // Get tables names
6199
        $tuser = Database::get_main_table(TABLE_MAIN_USER);
6200
        $tquiz = Database::get_course_table(TABLE_QUIZ_TEST);
6201
        $tquiz_answer = Database::get_course_table(TABLE_QUIZ_ANSWER);
6202
        $tquiz_question = Database::get_course_table(TABLE_QUIZ_QUESTION);
6203
        $tquiz_rel_question = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
6204
        $ttrack_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
6205
        $ttrack_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
6206
6207
        $sessions = array();
6208
        $courses = array();
6209
        // if session ID is defined but course ID is empty, get all the courses
6210
        // from that session
6211
        if (!empty($sessionId) && empty($courseId)) {
6212
            // $courses is an array of course int id as index and course details hash as value
6213
            $courses = SessionManager::get_course_list_by_session_id($sessionId);
6214
            $sessions[$sessionId] = api_get_session_info($sessionId);
6215
        } elseif (empty($sessionId) && !empty($courseId)) {
6216
            // if, to the contrary, course is defined but not sessions, get the sessions that include this course
6217
            // $sessions is an array like: [0] => ('id' => 3, 'name' => 'Session 35'), [1] => () etc;
6218
            $course = api_get_course_info_by_id($courseId);
6219
            $sessionsTemp = SessionManager::get_session_by_course($courseId);
6220
            $courses[$courseId] = $course;
6221
            foreach ($sessionsTemp as $sessionItem) {
6222
                $sessions[$sessionItem['id']] = $sessionItem;
6223
            }
6224
        } elseif (!empty($courseId) && !empty($sessionId)) {
6225
            //none is empty
6226
            $course = api_get_course_info_by_id($courseId);
6227
            $courses[$courseId] = array($course['code']);
6228
            $courses[$courseId]['code'] = $course['code'];
6229
            $sessions[$sessionId] = api_get_session_info($sessionId);
6230
        } else {
6231
            //both are empty, not enough data, return an empty array
6232
            return array();
6233
        }
6234
        // Now we have two arrays of courses and sessions with enough data to proceed
6235
        // If no course could be found, we shouldn't return anything.
6236
        // Sessions can be empty (then we only return the pure-course-context results)
6237
        if (count($courses) < 1) {
6238
            return array();
6239
        }
6240
6241
        $data = array();
6242
        // The following loop is less expensive than what it seems:
6243
        // - if a course was defined, then we only loop through sessions
6244
        // - if a session was defined, then we only loop through courses
6245
        // - if a session and a course were defined, then we only loop once
6246
        foreach ($courses as $courseIdx => $courseData) {
0 ignored issues
show
Bug introduced by
The expression $courses of type integer|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
6247
            $where = '';
6248
            $whereParams = array();
6249
            $whereSessionParams = '';
6250
            if (count($sessions > 0)) {
6251
                foreach ($sessions as $sessionIdx => $sessionData) {
6252
                    if (!empty($sessionIdx)) {
6253
                        $whereSessionParams .= $sessionIdx.',';
6254
                    }
6255
                }
6256
                $whereSessionParams = substr($whereSessionParams, 0, -1);
6257
            }
6258
6259
            if (!empty($exerciseId)) {
6260
                $exerciseId = intval($exerciseId);
6261
                $where .= ' AND q.id = %d ';
6262
                $whereParams[] = $exerciseId;
6263
            }
6264
6265
            /*
6266
             * This feature has been disabled for now, to avoid having to
6267
             * join two very large tables
6268
            //2 = show all questions (wrong and correct answered)
6269
            if ($answer != 2) {
6270
                $answer = intval($answer);
6271
                //$where .= ' AND qa.correct = %d';
6272
                //$whereParams[] = $answer;
6273
            }
6274
            */
6275
6276
            $limit = '';
6277
            if (!empty($options['limit'])) {
6278
                $limit = " LIMIT ".$options['limit'];
6279
            }
6280
6281
            if (!empty($options['where'])) {
6282
                $where .= ' AND '.Database::escape_string($options['where']);
6283
            }
6284
6285
            $order = '';
6286
            if (!empty($options['order'])) {
6287
                $order = " ORDER BY ".$options['order'];
6288
            }
6289
6290
            if (!empty($date_to) && !empty($date_from)) {
6291
                $where .= sprintf(" AND (te.start_date BETWEEN '%s 00:00:00' AND '%s 23:59:59')", $date_from, $date_to);
6292
            }
6293
6294
            $sql = "SELECT
6295
                te.session_id,
6296
                ta.id as attempt_id,
6297
                te.exe_user_id as user_id,
6298
                te.exe_id as exercise_attempt_id,
6299
                ta.question_id,
6300
                ta.answer as answer_id,
6301
                ta.tms as time,
6302
                te.exe_exo_id as quiz_id,
6303
                CONCAT ('c', q.c_id, '_e', q.id) as exercise_id,
6304
                q.title as quiz_title,
6305
                qq.description as description
6306
                FROM $ttrack_exercises te
6307
                INNER JOIN $ttrack_attempt ta 
6308
                ON ta.exe_id = te.exe_id
6309
                INNER JOIN $tquiz q 
6310
                ON q.id = te.exe_exo_id
6311
                INNER JOIN $tquiz_rel_question rq 
6312
                ON rq.exercice_id = q.id AND rq.c_id = q.c_id
6313
                INNER JOIN $tquiz_question qq
6314
                ON
6315
                    qq.id = rq.question_id AND
6316
                    qq.c_id = rq.c_id AND
6317
                    qq.position = rq.question_order AND
6318
                    ta.question_id = rq.question_id
6319
                WHERE
6320
                    te.c_id = $courseIdx ".(empty($whereSessionParams) ? '' : "AND te.session_id IN ($whereSessionParams)")."
6321
                    AND q.c_id = $courseIdx
6322
                    $where $order $limit";
6323
            $sql_query = vsprintf($sql, $whereParams);
6324
6325
            // Now browse through the results and get the data
6326
            $rs = Database::query($sql_query);
6327
            $userIds = array();
6328
            $questionIds = array();
6329
            $answerIds = array();
6330
            while ($row = Database::fetch_array($rs)) {
6331
                //only show if exercise is visible
6332
                if (api_get_item_visibility($courseData, 'quiz', $row['exercise_id'])) {
6333
                    $userIds[$row['user_id']] = $row['user_id'];
6334
                    $questionIds[$row['question_id']] = $row['question_id'];
6335
                    $answerIds[$row['question_id']][$row['answer_id']] = $row['answer_id'];
6336
                    $row['session'] = $sessions[$row['session_id']];
6337
                    $data[] = $row;
6338
                }
6339
            }
6340
            // Now fill questions data. Query all questions and answers for this test to avoid
6341
            $sqlQuestions = "SELECT tq.c_id, tq.id as question_id, tq.question, tqa.id_auto,
6342
                            tqa.answer, tqa.correct, tq.position, tqa.id_auto as answer_id
6343
                            FROM $tquiz_question tq, $tquiz_answer tqa
6344
                            WHERE
6345
                                tqa.question_id = tq.id AND
6346
                                tqa.c_id = tq.c_id AND
6347
                                tq.c_id = $courseIdx AND
6348
                                tq.id IN (".implode(',', $questionIds).")";
6349
6350
            $resQuestions = Database::query($sqlQuestions);
6351
            $answer = array();
6352
            $question = array();
6353
            while ($rowQuestion = Database::fetch_assoc($resQuestions)) {
6354
                $questionId = $rowQuestion['question_id'];
6355
                $answerId = $rowQuestion['answer_id'];
6356
                $answer[$questionId][$answerId] = array(
6357
                    'position' => $rowQuestion['position'],
6358
                    'question' => $rowQuestion['question'],
6359
                    'answer' => $rowQuestion['answer'],
6360
                    'correct' => $rowQuestion['correct']
6361
                );
6362
                $question[$questionId]['question'] = $rowQuestion['question'];
6363
            }
6364
6365
            // Now fill users data
6366
            $sqlUsers = "SELECT user_id, username, lastname, firstname
6367
                         FROM $tuser
6368
                         WHERE user_id IN (".implode(',', $userIds).")";
6369
            $resUsers = Database::query($sqlUsers);
6370
            while ($rowUser = Database::fetch_assoc($resUsers)) {
6371
                $users[$rowUser['user_id']] = $rowUser;
6372
            }
6373
6374
            foreach ($data as $id => $row) {
6375
                $rowQuestId = $row['question_id'];
6376
                $rowAnsId = $row['answer_id'];
6377
                $data[$id]['session'] = $sessions[$row['session_id']]['name'];
6378
                $data[$id]['firstname'] = $users[$row['user_id']]['firstname'];
6379
                $data[$id]['lastname'] = $users[$row['user_id']]['lastname'];
6380
                $data[$id]['username'] = $users[$row['user_id']]['username'];
6381
                $data[$id]['answer'] = $answer[$rowQuestId][$rowAnsId]['answer'];
6382
                $data[$id]['correct'] = ($answer[$rowQuestId][$rowAnsId]['correct'] == 0 ? get_lang('No') : get_lang('Yes'));
6383
                $data[$id]['question'] = $question[$rowQuestId]['question'];
6384
                $data[$id]['question_id'] = $rowQuestId;
6385
                $data[$id]['description'] = $row['description'];
6386
            }
6387
6388
            /*
6389
            The minimum expected array structure at the end is:
6390
            attempt_id,
6391
            session name,
6392
            exercise_id,
6393
            quiz_title,
6394
            username,
6395
            lastname,
6396
            firstname,
6397
            time,
6398
            question_id,
6399
            question,
6400
            answer,
6401
            */
6402
        }
6403
        return $data;
6404
    }
6405
6406
    /**
6407
     * @param User $user
6408
     * @param string $tool
6409
     * @param Course $course
6410
     * @param Session|null $session Optional.
6411
     * @return \Chamilo\CourseBundle\Entity\CStudentPublication|null
6412
     * @throws \Doctrine\ORM\NonUniqueResultException
6413
     */
6414
    public static function getLastStudentPublication(
6415
        User $user,
6416
        $tool,
6417
        Course $course,
6418
        Session $session = null
6419
    ) {
6420
        return Database::getManager()
6421
            ->createQuery("
6422
                SELECT csp
6423
                FROM ChamiloCourseBundle:CStudentPublication csp
6424
                INNER JOIN ChamiloCourseBundle:CItemProperty cip
6425
                    WITH (
6426
                        csp.iid = cip.ref AND
6427
                        csp.session = cip.session AND
6428
                        csp.cId = cip.course AND
6429
                        csp.userId = cip.lasteditUserId
6430
                    )
6431
                WHERE
6432
                    cip.session = :session AND cip.course = :course AND cip.lasteditUserId = :user AND cip.tool = :tool
6433
                ORDER BY csp.iid DESC
6434
            ")
6435
            ->setMaxResults(1)
6436
            ->setParameters([
6437
                'tool' => $tool,
6438
                'session' => $session,
6439
                'course' => $course,
6440
                'user' => $user
6441
            ])
6442
            ->getOneOrNullResult();
6443
    }
6444
6445
    /**
6446
     * Get the HTML code for show a block with the achieved user skill on course/session
6447
     * @param int $userId
6448
     * @param int $courseId Optional.
6449
     * @param int $sessionId Optional.
6450
     * @return string
6451
     */
6452
    public static function displayUserSkills($userId, $courseId = 0, $sessionId = 0)
6453
    {
6454
        $userId = intval($userId);
6455
        $courseId = intval($courseId);
6456
        $sessionId = intval($sessionId);
6457
6458
        if (api_get_setting('allow_skills_tool') !== 'true') {
6459
            return '';
6460
        }
6461
6462
        $filter = ['user' => $userId];
6463
        $filter['course'] = $courseId ?: null;
6464
        $filter['session'] = $sessionId ?: null;
6465
6466
        $em = Database::getManager();
6467
6468
        $skillsRelUser = $em->getRepository('ChamiloCoreBundle:SkillRelUser')->findBy($filter);
6469
6470
        $html = '
6471
            <div class="table-responsive">
6472
                <table class="table" id="skillList">
6473
                    <thead>
6474
                        <tr>
6475
                            <th>' . get_lang('AchievedSkills').'</th>
6476
                        </tr>
6477
                    </thead>
6478
                    <tbody>
6479
                        <tr>
6480
                            <td>
6481
        ';
6482
6483
        if (count($skillsRelUser)) {
6484
            $html .= '<div class="scrollbar-inner badges-sidebar">
6485
                        <ul class="list-unstyled list-badges">
6486
            ';
6487
6488
            foreach ($skillsRelUser as $userSkill) {
6489
                $skill = $userSkill->getSkill();
6490
6491
                $html .= '<li class="thumbnail">
6492
                            <a href="' . api_get_path(WEB_PATH).'badge/'.$userSkill->getId().'/user/'.$userId.'" target="_blank">
6493
                                <img class="img-responsive" title="' . $skill->getName().'" src="'.$skill->getWebIconPath().'" width="64" height="64">
6494
                                <div class="caption">
6495
                                    <p class="text-center">' . $skill->getName().'</p>
6496
                                </div>
6497
                            </a>
6498
                        </li>
6499
                ';
6500
            }
6501
6502
            $html .= '</ul></div>
6503
            ';
6504
        } else {
6505
            $html .= get_lang('WithoutAchievedSkills');
6506
        }
6507
6508
        $html .= '</td>
6509
                        </tr>
6510
                    </tbody>
6511
                </table>
6512
            </div>
6513
        ';
6514
6515
        return $html;
6516
    }
6517
}
6518
6519
/**
6520
 * @todo move into a proper file
6521
 * @package chamilo.tracking
6522
 */
6523
class TrackingCourseLog
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
6524
{
6525
    /**
6526
     * @return mixed
6527
     */
6528
    public static function count_item_resources()
6529
    {
6530
        $session_id = api_get_session_id();
6531
        $course_id = api_get_course_int_id();
6532
6533
        $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
6534
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
6535
6536
        $sql = "SELECT count(tool) AS total_number_of_items
6537
                FROM $table_item_property track_resource, $table_user user
6538
                WHERE
6539
                    track_resource.c_id = $course_id AND
6540
                    track_resource.insert_user_id = user.user_id AND
6541
                    session_id ".(empty($session_id) ? ' IS NULL ' : " = $session_id ");
6542
6543
        if (isset($_GET['keyword'])) {
6544
            $keyword = Database::escape_string(trim($_GET['keyword']));
6545
            $sql .= " AND (
6546
                        user.username LIKE '%".$keyword."%' OR
6547
                        lastedit_type LIKE '%".$keyword."%' OR
6548
                        tool LIKE '%".$keyword."%'
6549
                    )";
6550
        }
6551
6552
        $sql .= " AND tool IN (
6553
                    'document',
6554
                    'learnpath',
6555
                    'quiz',
6556
                    'glossary',
6557
                    'link',
6558
                    'course_description',
6559
                    'announcement',
6560
                    'thematic',
6561
                    'thematic_advance',
6562
                    'thematic_plan'
6563
                )";
6564
        $res = Database::query($sql);
6565
        $obj = Database::fetch_object($res);
6566
6567
        return $obj->total_number_of_items;
6568
    }
6569
6570
    /**
6571
     * @param $from
6572
     * @param $number_of_items
6573
     * @param $column
6574
     * @param $direction
6575
     * @return array
6576
     */
6577
    public static function get_item_resources_data($from, $number_of_items, $column, $direction)
6578
    {
6579
        $session_id = api_get_session_id();
6580
        $course_id = api_get_course_int_id();
6581
6582
        $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
6583
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
6584
        $table_session = Database::get_main_table(TABLE_MAIN_SESSION);
6585
        $session_id = intval($session_id);
6586
6587
        $sql = "SELECT
6588
                    tool as col0,
6589
                    lastedit_type as col1,
6590
                    ref as ref,
6591
                    user.username as col3,
6592
                    insert_date as col5,
6593
                    visibility as col6,
6594
                    user.user_id as user_id
6595
                FROM $table_item_property track_resource, $table_user user
6596
                WHERE
6597
                  track_resource.c_id = $course_id AND
6598
                  track_resource.insert_user_id = user.user_id AND
6599
                  session_id ".(empty($session_id) ? ' IS NULL ' : " = $session_id ");
6600
6601
        if (isset($_GET['keyword'])) {
6602
            $keyword = Database::escape_string(trim($_GET['keyword']));
6603
            $sql .= " AND (
6604
                        user.username LIKE '%".$keyword."%' OR
6605
                        lastedit_type LIKE '%".$keyword."%' OR
6606
                        tool LIKE '%".$keyword."%'
6607
                     ) ";
6608
        }
6609
6610
        $sql .= " AND tool IN (
6611
                    'document',
6612
                    'learnpath',
6613
                    'quiz',
6614
                    'glossary',
6615
                    'link',
6616
                    'course_description',
6617
                    'announcement',
6618
                    'thematic',
6619
                    'thematic_advance',
6620
                    'thematic_plan'
6621
                )";
6622
6623
        if ($column == 0) {
6624
            $column = '0';
6625
        }
6626
        if ($column != '' && $direction != '') {
6627
            if ($column != 2 && $column != 4) {
6628
                $sql .= " ORDER BY col$column $direction";
6629
            }
6630
        } else {
6631
            $sql .= " ORDER BY col5 DESC ";
6632
        }
6633
6634
        $from = intval($from);
6635
        $number_of_items = intval($number_of_items);
6636
6637
        $sql .= " LIMIT $from, $number_of_items ";
6638
6639
        $res = Database::query($sql);
6640
        $resources = array();
6641
        $thematic_tools = array('thematic', 'thematic_advance', 'thematic_plan');
6642
        while ($row = Database::fetch_array($res)) {
6643
            $ref = $row['ref'];
6644
            $table_name = self::get_tool_name_table($row['col0']);
6645
            $table_tool = Database::get_course_table($table_name['table_name']);
6646
6647
            $id = $table_name['id_tool'];
6648
            $recorset = false;
6649
6650
            if (in_array($row['col0'], array('thematic_plan', 'thematic_advance'))) {
6651
                $tbl_thematic = Database::get_course_table(TABLE_THEMATIC);
6652
                $sql = "SELECT thematic_id FROM $table_tool
6653
                        WHERE c_id = $course_id AND id = $ref";
6654
                $rs_thematic  = Database::query($sql);
6655 View Code Duplication
                if (Database::num_rows($rs_thematic)) {
6656
                    $row_thematic = Database::fetch_array($rs_thematic);
6657
                    $thematic_id = $row_thematic['thematic_id'];
6658
6659
                    $sql = "SELECT session.id, session.name, user.username
6660
                            FROM $tbl_thematic t, $table_session session, $table_user user
6661
                            WHERE
6662
                              t.c_id = $course_id AND
6663
                              t.session_id = session.id AND
6664
                              session.id_coach = user.user_id AND
6665
                              t.id = $thematic_id";
6666
                    $recorset = Database::query($sql);
6667
                }
6668
            } else {
6669
                $sql = "SELECT session.id, session.name, user.username
6670
                          FROM $table_tool tool, $table_session session, $table_user user
6671
                          WHERE
6672
                              tool.c_id = $course_id AND
6673
                              tool.session_id = session.id AND
6674
                              session.id_coach = user.user_id AND
6675
                              tool.$id = $ref";
6676
                $recorset = Database::query($sql);
6677
            }
6678
6679
            if (!empty($recorset)) {
6680
                $obj = Database::fetch_object($recorset);
6681
6682
                $name_session = '';
6683
                $coach_name = '';
6684
                if (!empty($obj)) {
6685
                    $name_session = $obj->name;
6686
                    $coach_name   = $obj->username;
6687
                }
6688
6689
                $url_tool = api_get_path(WEB_CODE_PATH).$table_name['link_tool'];
6690
                $row[0] = '';
6691
                if ($row['col6'] != 2) {
6692
                    if (in_array($row['col0'], $thematic_tools)) {
6693
                        $exp_thematic_tool = explode('_', $row['col0']);
6694
                        $thematic_tool_title = '';
6695
                        if (is_array($exp_thematic_tool)) {
6696
                            foreach ($exp_thematic_tool as $exp) {
6697
                                $thematic_tool_title .= api_ucfirst($exp);
6698
                            }
6699
                        } else {
6700
                            $thematic_tool_title = api_ucfirst($row['col0']);
6701
                        }
6702
6703
                        $row[0] = '<a href="'.$url_tool.'?'.api_get_cidreq().'&action=thematic_details">'.get_lang($thematic_tool_title).'</a>';
6704
                    } else {
6705
                        $row[0] = '<a href="'.$url_tool.'?'.api_get_cidreq().'">'.get_lang('Tool'.api_ucfirst($row['col0'])).'</a>';
6706
                    }
6707
                } else {
6708
                    $row[0] = api_ucfirst($row['col0']);
6709
                }
6710
                $row[1] = get_lang($row[1]);
6711
                $row[6] = api_convert_and_format_date($row['col5'], null, date_default_timezone_get());
6712
                $row[5] = '';
6713
                //@todo Improve this code please
6714
                switch ($table_name['table_name']) {
6715 View Code Duplication
                    case 'document':
6716
                        $sql = "SELECT tool.title as title FROM $table_tool tool
6717
                                WHERE c_id = $course_id AND id = $ref";
6718
                        $rs_document = Database::query($sql);
6719
                        $obj_document = Database::fetch_object($rs_document);
6720
                        if ($obj_document) {
6721
                            $row[5] = $obj_document->title;
6722
                        }
6723
                        break;
6724 View Code Duplication
                    case 'announcement':
6725
                        $sql = "SELECT title FROM $table_tool
6726
                                WHERE c_id = $course_id AND id = $ref";
6727
                        $rs_document = Database::query($sql);
6728
                        $obj_document = Database::fetch_object($rs_document);
6729
                        if ($obj_document) {
6730
                            $row[5] = $obj_document->title;
6731
                        }
6732
                        break;
6733
                    case 'glossary':
6734
                        $sql = "SELECT name FROM $table_tool
6735
                                WHERE c_id = $course_id AND glossary_id = $ref";
6736
                        $rs_document = Database::query($sql);
6737
                        $obj_document = Database::fetch_object($rs_document);
6738
                        if ($obj_document) {
6739
                            $row[5] = $obj_document->name;
6740
                        }
6741
                        break;
6742
                    case 'lp':
6743
                        $sql = "SELECT name
6744
                                FROM $table_tool WHERE c_id = $course_id AND id = $ref";
6745
                        $rs_document = Database::query($sql);
6746
                        $obj_document = Database::fetch_object($rs_document);
6747
                        $row[5] = $obj_document->name;
6748
                        break;
6749 View Code Duplication
                    case 'quiz':
6750
                        $sql = "SELECT title FROM $table_tool
6751
                                WHERE c_id = $course_id AND id = $ref";
6752
                        $rs_document = Database::query($sql);
6753
                        $obj_document = Database::fetch_object($rs_document);
6754
                        if ($obj_document) {
6755
                            $row[5] = $obj_document->title;
6756
                        }
6757
                        break;
6758 View Code Duplication
                    case 'course_description':
6759
                        $sql = "SELECT title FROM $table_tool
6760
                                WHERE c_id = $course_id AND id = $ref";
6761
                        $rs_document = Database::query($sql);
6762
                        $obj_document = Database::fetch_object($rs_document);
6763
                        if ($obj_document) {
6764
                            $row[5] = $obj_document->title;
6765
                        }
6766
                        break;
6767 View Code Duplication
                    case 'thematic':
6768
                        $rs = Database::query("SELECT title FROM $table_tool WHERE c_id = $course_id AND id = $ref");
6769
                        if (Database::num_rows($rs) > 0) {
6770
                            $obj = Database::fetch_object($rs);
6771
                            if ($obj) {
6772
                                $row[5] = $obj->title;
6773
                            }
6774
                        }
6775
                        break;
6776 View Code Duplication
                    case 'thematic_advance':
6777
                        $rs = Database::query("SELECT content FROM $table_tool WHERE c_id = $course_id AND id = $ref");
6778
                        if (Database::num_rows($rs) > 0) {
6779
                            $obj = Database::fetch_object($rs);
6780
                            if ($obj) {
6781
                                $row[5] = $obj->content;
6782
                            }
6783
                        }
6784
                        break;
6785 View Code Duplication
                    case 'thematic_plan':
6786
                        $rs = Database::query("SELECT title FROM $table_tool WHERE c_id = $course_id AND id = $ref");
6787
                        if (Database::num_rows($rs) > 0) {
6788
                            $obj = Database::fetch_object($rs);
6789
                            if ($obj) {
6790
                                $row[5] = $obj->title;
6791
                            }
6792
                        }
6793
                        break;
6794
                    default:
6795
                        break;
6796
                }
6797
6798
                $row2 = $name_session;
6799
                if (!empty($coach_name)) {
6800
                    $row2 .= '<br />'.get_lang('Coach').': '.$coach_name;
6801
                }
6802
                $row[2] = $row2;
6803
                if (!empty($row['col3'])) {
6804
                    $userInfo = api_get_user_info($row['user_id']);
6805
                    $row['col3'] = Display::url(
6806
                        $row['col3'],
6807
                        $userInfo['profile_url']
6808
                    );
6809
                    $row[3] = $row['col3'];
6810
6811
                    $ip = TrackingUserLog::get_ip_from_user_event($row['user_id'], $row['col5'], true);
6812
                    if (empty($ip)) {
6813
                        $ip = get_lang('Unknown');
6814
                    }
6815
                    $row[4] = $ip;
6816
                }
6817
6818
                $resources[] = $row;
6819
            }
6820
        }
6821
6822
        return $resources;
6823
    }
6824
6825
    /**
6826
     * @param string $tool
6827
     *
6828
     * @return array
6829
     */
6830
    public static function get_tool_name_table($tool)
6831
    {
6832
        switch ($tool) {
6833
            case 'document':
6834
                $table_name = TABLE_DOCUMENT;
6835
                $link_tool = 'document/document.php';
6836
                $id_tool = 'id';
6837
                break;
6838
            case 'learnpath':
6839
                $table_name = TABLE_LP_MAIN;
6840
                $link_tool = 'lp/lp_controller.php';
6841
                $id_tool = 'id';
6842
                break;
6843
            case 'quiz':
6844
                $table_name = TABLE_QUIZ_TEST;
6845
                $link_tool = 'exercise/exercise.php';
6846
                $id_tool = 'id';
6847
                break;
6848
            case 'glossary':
6849
                $table_name = TABLE_GLOSSARY;
6850
                $link_tool = 'glossary/index.php';
6851
                $id_tool = 'glossary_id';
6852
                break;
6853
            case 'link':
6854
                $table_name = TABLE_LINK;
6855
                $link_tool = 'link/link.php';
6856
                $id_tool = 'id';
6857
                break;
6858
            case 'course_description':
6859
                $table_name = TABLE_COURSE_DESCRIPTION;
6860
                $link_tool = 'course_description/';
6861
                $id_tool = 'id';
6862
                break;
6863
            case 'announcement':
6864
                $table_name = TABLE_ANNOUNCEMENT;
6865
                $link_tool = 'announcements/announcements.php';
6866
                $id_tool = 'id';
6867
                break;
6868
            case 'thematic':
6869
                $table_name = TABLE_THEMATIC;
6870
                $link_tool = 'course_progress/index.php';
6871
                $id_tool = 'id';
6872
                break;
6873
            case 'thematic_advance':
6874
                $table_name = TABLE_THEMATIC_ADVANCE;
6875
                $link_tool = 'course_progress/index.php';
6876
                $id_tool = 'id';
6877
                break;
6878
            case 'thematic_plan':
6879
                $table_name = TABLE_THEMATIC_PLAN;
6880
                $link_tool = 'course_progress/index.php';
6881
                $id_tool = 'id';
6882
                break;
6883
            default:
6884
                $table_name = $tool;
6885
            break;
6886
        }
6887
6888
        return array(
6889
            'table_name' => $table_name,
6890
            'link_tool' => $link_tool,
6891
            'id_tool' => $id_tool
6892
        );
6893
    }
6894
6895
    /**
6896
     * @return string
6897
     */
6898
    public static function display_additional_profile_fields()
6899
    {
6900
        // getting all the extra profile fields that are defined by the platform administrator
6901
        $extra_fields = UserManager::get_extra_fields(0, 50, 5, 'ASC');
6902
6903
        // creating the form
6904
        $return = '<form action="courseLog.php" method="get" name="additional_profile_field_form" id="additional_profile_field_form">';
6905
6906
        // the select field with the additional user profile fields (= this is where we select the field of which we want to see
6907
        // the information the users have entered or selected.
6908
        $return .= '<select class="chzn-select" name="additional_profile_field[]" multiple>';
6909
        $return .= '<option value="-">'.get_lang('SelectFieldToAdd').'</option>';
6910
        $extra_fields_to_show = 0;
6911
        foreach ($extra_fields as $key=>$field) {
6912
            // show only extra fields that are visible + and can be filtered, added by J.Montoya
6913
            if ($field[6] == 1 && $field[8] == 1) {
6914
                if (isset($_GET['additional_profile_field']) && $field[0] == $_GET['additional_profile_field']) {
6915
                    $selected = 'selected="selected"';
6916
                } else {
6917
                    $selected = '';
6918
                }
6919
                $extra_fields_to_show++;
6920
                $return .= '<option value="'.$field[0].'" '.$selected.'>'.$field[3].'</option>';
6921
            }
6922
        }
6923
        $return .= '</select>';
6924
6925
        // the form elements for the $_GET parameters (because the form is passed through GET
6926
        foreach ($_GET as $key=>$value) {
6927
            if ($key <> 'additional_profile_field') {
6928
                $return .= '<input type="hidden" name="'.Security::remove_XSS($key).'" value="'.Security::remove_XSS($value).'" />';
6929
            }
6930
        }
6931
        // the submit button
6932
        $return .= '<button class="save" type="submit">'.get_lang('AddAdditionalProfileField').'</button>';
6933
        $return .= '</form>';
6934
        if ($extra_fields_to_show > 0) {
6935
            return $return;
6936
        } else {
6937
            return '';
6938
        }
6939
    }
6940
6941
    /**
6942
     * This function gets all the information of a certrain ($field_id)
6943
     * additional profile field for a specific list of users is more efficent
6944
     * than get_addtional_profile_information_of_field() function
6945
     * It gets the information of all the users so that it can be displayed
6946
     * in the sortable table or in the csv or xls export
6947
     *
6948
     * @author    Julio Montoya <[email protected]>
6949
     * @param    int field id
6950
     * @param    array list of user ids
6951
     * @return    array
6952
     * @since    Nov 2009
6953
     * @version    1.8.6.2
6954
     */
6955
    public static function get_addtional_profile_information_of_field_by_user($field_id, $users)
6956
    {
6957
        // Database table definition
6958
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
6959
        $table_user_field_values = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
6960
        $extraField = Database::get_main_table(TABLE_EXTRA_FIELD);
6961
        $result_extra_field = UserManager::get_extra_field_information($field_id);
0 ignored issues
show
Deprecated Code introduced by
The method UserManager::get_extra_field_information() has been deprecated.

This method has been deprecated.

Loading history...
6962
        $return = [];
6963
        if (!empty($users)) {
6964
            if ($result_extra_field['field_type'] == UserManager::USER_FIELD_TYPE_TAG) {
6965
                foreach ($users as $user_id) {
6966
                    $user_result = UserManager::get_user_tags($user_id, $field_id);
6967
                    $tag_list = array();
6968
                    foreach ($user_result as $item) {
6969
                        $tag_list[] = $item['tag'];
6970
                    }
6971
                    $return[$user_id][] = implode(', ', $tag_list);
6972
                }
6973
            } else {
6974
                $new_user_array = array();
6975
                foreach ($users as $user_id) {
6976
                    $new_user_array[] = "'".$user_id."'";
6977
                }
6978
                $users = implode(',', $new_user_array);
6979
                $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
6980
                // Selecting only the necessary information NOT ALL the user list
6981
                $sql = "SELECT user.user_id, v.value
6982
                        FROM $table_user user
6983
                        INNER JOIN $table_user_field_values v
6984
                        ON (user.user_id = v.item_id)
6985
                        INNER JOIN $extraField f
6986
                        ON (f.id = v.field_id)
6987
                        WHERE
6988
                            f.extra_field_type = $extraFieldType AND
6989
                            v.field_id=".intval($field_id)." AND
6990
                            user.user_id IN ($users)";
6991
6992
                $result = Database::query($sql);
6993
                while ($row = Database::fetch_array($result)) {
6994
                    // get option value for field type double select by id
6995
                    if (!empty($row['value'])) {
6996
                        if ($result_extra_field['field_type'] ==
6997
                            ExtraField::FIELD_TYPE_DOUBLE_SELECT
6998
                        ) {
6999
                            $id_double_select = explode(';', $row['value']);
7000
                            if (is_array($id_double_select)) {
7001
                                $value1 = $result_extra_field['options'][$id_double_select[0]]['option_value'];
7002
                                $value2 = $result_extra_field['options'][$id_double_select[1]]['option_value'];
7003
                                $row['value'] = ($value1.';'.$value2);
7004
                            }
7005
                        }
7006
                    }
7007
                    // get other value from extra field
7008
                    $return[$row['user_id']][] = $row['value'];
7009
                }
7010
            }
7011
        }
7012
        return $return;
7013
    }
7014
7015
    /**
7016
     * count the number of students in this course (used for SortableTable)
7017
     * Deprecated
7018
     */
7019
    public function count_student_in_course()
7020
    {
7021
        global $nbStudents;
7022
        return $nbStudents;
7023
    }
7024
7025
    public function sort_users($a, $b)
7026
    {
7027
        return strcmp(trim(api_strtolower($a[$_SESSION['tracking_column']])), trim(api_strtolower($b[$_SESSION['tracking_column']])));
7028
    }
7029
7030
    public function sort_users_desc($a, $b)
7031
    {
7032
        return strcmp(trim(api_strtolower($b[$_SESSION['tracking_column']])), trim(api_strtolower($a[$_SESSION['tracking_column']])));
7033
    }
7034
7035
    /**
7036
     * Get number of users for sortable with pagination
7037
     * @return int
7038
     */
7039
    public static function get_number_of_users()
7040
    {
7041
        global $user_ids;
7042
        return count($user_ids);
7043
    }
7044
7045
    /**
7046
     * Get data for users list in sortable with pagination
7047
     * @param $from
7048
     * @param $number_of_items
7049
     * @param $column
7050
     * @param $direction
7051
     * @param $includeInvitedUsers boolean Whether include the invited users
7052
     * @return array
7053
     */
7054
    public static function get_user_data($from, $number_of_items, $column, $direction, $includeInvitedUsers = false)
7055
    {
7056
        global $user_ids, $course_code, $export_csv, $is_western_name_order, $csv_content, $session_id;
7057
7058
        $course_code = Database::escape_string($course_code);
7059
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
7060
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
7061
7062
        $access_url_id = api_get_current_access_url_id();
7063
7064
        // get all users data from a course for sortable with limit
7065
        if (is_array($user_ids)) {
7066
            $user_ids = array_map('intval', $user_ids);
7067
            $condition_user = " WHERE user.user_id IN (".implode(',', $user_ids).") ";
7068
        } else {
7069
            $user_ids = intval($user_ids);
7070
            $condition_user = " WHERE user.user_id = $user_ids ";
7071
        }
7072
7073 View Code Duplication
        if (!empty($_GET['user_keyword'])) {
7074
            $keyword = trim(Database::escape_string($_GET['user_keyword']));
7075
            $condition_user .= " AND (
7076
                user.firstname LIKE '%".$keyword."%' OR
7077
                user.lastname LIKE '%".$keyword."%'  OR
7078
                user.username LIKE '%".$keyword."%'  OR
7079
                user.email LIKE '%".$keyword."%'
7080
             ) ";
7081
        }
7082
7083
        $url_table = null;
7084
        $url_condition = null;
7085
        if (api_is_multiple_url_enabled()) {
7086
            $url_table = ", ".$tbl_url_rel_user." as url_users";
7087
            $url_condition = " AND user.user_id = url_users.user_id AND access_url_id='$access_url_id'";
7088
        }
7089
7090
        $invitedUsersCondition = '';
7091
7092
        if (!$includeInvitedUsers) {
7093
            $invitedUsersCondition = " AND user.status != ".INVITEE;
7094
        }
7095
7096
        $sql = "SELECT  user.user_id as user_id,
7097
                    user.official_code  as col0,
7098
                    user.lastname       as col1,
7099
                    user.firstname      as col2,
7100
                    user.username       as col3
7101
                FROM $tbl_user as user $url_table
7102
                $condition_user $url_condition $invitedUsersCondition";
7103
7104
        if (!in_array($direction, array('ASC', 'DESC'))) {
7105
            $direction = 'ASC';
7106
        }
7107
7108
        $column = intval($column);
7109
        $from = intval($from);
7110
        $number_of_items = intval($number_of_items);
7111
7112
        $sql .= " ORDER BY col$column $direction ";
7113
        $sql .= " LIMIT $from,$number_of_items";
7114
7115
        $res = Database::query($sql);
7116
        $users = array();
7117
7118
        $course_info = api_get_course_info($course_code);
7119
        $total_surveys = 0;
7120
        $total_exercises = ExerciseLib::get_all_exercises(
7121
            $course_info,
7122
            $session_id,
7123
            false,
7124
            null,
7125
            false,
7126
            3
7127
        );
7128
7129
        if (empty($session_id)) {
7130
            $survey_user_list = array();
7131
            $survey_list = SurveyManager::get_surveys($course_code, $session_id);
7132
7133
            $total_surveys = count($survey_list);
7134 View Code Duplication
            foreach ($survey_list as $survey) {
0 ignored issues
show
Bug introduced by
The expression $survey_list of type false|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
7135
                $user_list = SurveyManager::get_people_who_filled_survey(
7136
                    $survey['survey_id'],
7137
                    false,
7138
                    $course_info['real_id']
7139
                );
7140
7141
                foreach ($user_list as $user_id) {
7142
                    isset($survey_user_list[$user_id]) ? $survey_user_list[$user_id]++ : $survey_user_list[$user_id] = 1;
7143
                }
7144
            }
7145
        }
7146
7147
        while ($user = Database::fetch_array($res, 'ASSOC')) {
7148
            $courseInfo = api_get_course_info($course_code);
7149
            $courseId = $courseInfo['real_id'];
7150
7151
            $user['official_code'] = $user['col0'];
7152
            $user['lastname'] = $user['col1'];
7153
            $user['firstname'] = $user['col2'];
7154
            $user['username'] = $user['col3'];
7155
7156
            $user['time'] = api_time_to_hms(
7157
                Tracking::get_time_spent_on_the_course(
7158
                    $user['user_id'],
7159
                    $courseId,
7160
                    $session_id
7161
                )
7162
            );
7163
7164
            $avg_student_score = Tracking::get_avg_student_score(
7165
                $user['user_id'],
7166
                $course_code,
7167
                array(),
7168
                $session_id
7169
            );
7170
7171
            $avg_student_progress = Tracking::get_avg_student_progress(
7172
                $user['user_id'],
7173
                $course_code,
7174
                array(),
7175
                $session_id
7176
            );
7177
7178
            if (empty($avg_student_progress)) {
7179
                $avg_student_progress = 0;
7180
            }
7181
            $user['average_progress'] = $avg_student_progress.'%';
7182
7183
            $total_user_exercise = Tracking::get_exercise_student_progress(
7184
                $total_exercises,
7185
                $user['user_id'],
7186
                $courseId,
7187
                $session_id
7188
            );
7189
7190
            $user['exercise_progress'] = $total_user_exercise;
7191
7192
            $total_user_exercise = Tracking::get_exercise_student_average_best_attempt(
7193
                $total_exercises,
7194
                $user['user_id'],
7195
                $courseId,
7196
                $session_id
7197
            );
7198
7199
            $user['exercise_average_best_attempt'] = $total_user_exercise;
7200
7201
            if (is_numeric($avg_student_score)) {
7202
                $user['student_score']  = $avg_student_score.'%';
7203
            } else {
7204
                $user['student_score']  = $avg_student_score;
7205
            }
7206
7207
            $user['count_assignments'] = Tracking::count_student_assignments(
7208
                $user['user_id'],
7209
                $course_code,
7210
                $session_id
7211
            );
7212
            $user['count_messages'] = Tracking::count_student_messages(
7213
                $user['user_id'],
7214
                $course_code,
7215
                $session_id
7216
            );
7217
            $user['first_connection'] = Tracking::get_first_connection_date_on_the_course(
7218
                $user['user_id'],
7219
                $courseId,
7220
                $session_id
7221
            );
7222
            $user['last_connection'] = Tracking::get_last_connection_date_on_the_course(
7223
                $user['user_id'],
7224
                $courseInfo,
7225
                $session_id
7226
            );
7227
7228
            if (empty($session_id)) {
7229
                $user['survey'] = (isset($survey_user_list[$user['user_id']]) ? $survey_user_list[$user['user_id']] : 0).' / '.$total_surveys;
7230
            }
7231
7232
            $user['link'] = '<center>
7233
                             <a href="../mySpace/myStudents.php?student='.$user['user_id'].'&details=true&course='.$course_code.'&origin=tracking_course&id_session='.$session_id.'">
7234
                             '.Display::return_icon('2rightarrow.png').'
7235
                             </a>
7236
                         </center>';
7237
7238
            // store columns in array $users
7239
            $is_western_name_order = api_is_western_name_order();
7240
            $user_row = array();
7241
            $user_row['official_code'] = $user['official_code']; //0
7242 View Code Duplication
            if ($is_western_name_order) {
7243
                $user_row['firstname'] = $user['firstname'];
7244
                $user_row['lastname'] = $user['lastname'];
7245
            } else {
7246
                $user_row['lastname'] = $user['lastname'];
7247
                $user_row['firstname'] = $user['firstname'];
7248
            }
7249
            $user_row['username'] = $user['username'];
7250
            $user_row['time'] = $user['time'];
7251
            $user_row['average_progress'] = $user['average_progress'];
7252
            $user_row['exercise_progress'] = $user['exercise_progress'];
7253
            $user_row['exercise_average_best_attempt'] = $user['exercise_average_best_attempt'];
7254
            $user_row['student_score'] = $user['student_score'];
7255
            $user_row['count_assignments'] = $user['count_assignments'];
7256
            $user_row['count_messages'] = $user['count_messages'];
7257
7258
            $userGroupManager = new UserGroup();
7259
            $user_row['classes'] = $userGroupManager->getLabelsFromNameList($user['user_id'], UserGroup::NORMAL_CLASS);
7260
7261
            if (empty($session_id)) {
7262
                $user_row['survey'] = $user['survey'];
7263
            }
7264
7265
            $user_row['first_connection'] = $user['first_connection'];
7266
            $user_row['last_connection'] = $user['last_connection'];
7267
7268
            // we need to display an additional profile field
7269
            if (isset($_GET['additional_profile_field'])) {
7270
                $data = \System\Session::read('additional_user_profile_info');
7271
                $extraFieldInfo = \System\Session::read('extra_field_info');
7272
                foreach ($_GET['additional_profile_field'] as $fieldId) {
7273
                    if (isset($data[$fieldId]) && isset($data[$fieldId][$user['user_id']])) {
7274
                        if (is_array($data[$fieldId][$user['user_id']])) {
7275
                            $user_row[$extraFieldInfo[$fieldId]['variable']] = implode(
7276
                                ', ',
7277
                                $data[$fieldId][$user['user_id']]
7278
                            );
7279
                        } else {
7280
                            $user_row[$extraFieldInfo[$fieldId]['variable']] = $data[$fieldId][$user['user_id']];
7281
                        }
7282
                    } else {
7283
                        $user_row[$extraFieldInfo[$fieldId]['variable']] = '';
7284
                    }
7285
                }
7286
            }
7287
7288
            $user_row['link'] = $user['link'];
7289
7290
            if ($export_csv) {
7291
                if (empty($session_id)) {
7292
                    unset($user_row['classes']);
7293
                    unset($user_row['link']);
7294
                } else {
7295
                    unset($user_row['classes']);
7296
                    unset($user_row['link']);
7297
                }
7298
7299
                $csv_content[] = $user_row;
7300
            }
7301
7302
            $users[] = array_values($user_row);
7303
        }
7304
7305
        \System\Session::erase('additional_user_profile_info');
7306
        \System\Session::erase('extra_field_info');
7307
7308
        return $users;
7309
    }
7310
}
7311
7312
/**
7313
 * @package chamilo.tracking
7314
 */
7315
class TrackingUserLog
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
7316
{
7317
    /**
7318
     * Gets the IP of a given user, using the last login before the given date
7319
     * @param int User ID
7320
     * @param string Datetime
7321
     * @param bool Whether to return the IP as a link or just as an IP
7322
     * @param string If defined and return_as_link if true, will be used as the text to be shown as the link
7323
     * @return string IP address (or false on error)
7324
     * @assert (0,0) === false
7325
     */
7326
    public static function get_ip_from_user_event(
7327
        $user_id,
7328
        $event_date,
7329
        $return_as_link = false,
7330
        $body_replace = null
7331
    ) {
7332
        if (empty($user_id) || empty($event_date)) {
7333
            return false;
7334
        }
7335
        $user_id = intval($user_id);
7336
        $event_date = Database::escape_string($event_date);
7337
        $table_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
7338
        $sql_ip = "SELECT login_date, user_ip 
7339
                   FROM $table_login
7340
                   WHERE login_user_id = $user_id AND login_date < '$event_date'
7341
                   ORDER BY login_date DESC LIMIT 1";
7342
        $ip = '';
7343
        $res_ip = Database::query($sql_ip);
7344
        if ($res_ip !== false && Database::num_rows($res_ip) > 0) {
7345
            $row_ip = Database::fetch_row($res_ip);
7346
            if ($return_as_link) {
7347
                $ip = Display::url(
7348
                    (empty($body_replace) ? $row_ip[1] : $body_replace), 'http://www.whatsmyip.org/ip-geo-location/?ip='.$row_ip[1],
7349
                    array('title' => get_lang('TraceIP'), 'target' => '_blank')
7350
                );
7351
            } else {
7352
                $ip = $row_ip[1];
7353
            }
7354
        }
7355
7356
        return $ip;
7357
    }
7358
}
7359
7360
/**
7361
 * @package chamilo.tracking
7362
 */
7363
class TrackingUserLogCSV
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
7364
{
7365
    /**
7366
     * Displays the number of logins every month for a specific user in a specific course.
7367
     * @param $view
7368
     * @param int $user_id
7369
     * @param int $course_id
7370
     * @param int $session_id
7371
     * @return array
7372
     */
7373
    public function display_login_tracking_info($view, $user_id, $course_id, $session_id = 0)
7374
    {
7375
        $MonthsLong = $GLOBALS['MonthsLong'];
7376
        $track_access_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
7377
7378
        // protected data
7379
        $user_id    = intval($user_id);
7380
        $session_id = intval($session_id);
7381
        $course_id  = intval($course_id);
7382
7383
        $tempView = $view;
7384
        if (substr($view, 0, 1) == '1') {
7385
            $new_view = substr_replace($view, '0', 0, 1);
7386
            $title[1] = get_lang('LoginsAndAccessTools').get_lang('LoginsDetails');
7387
            $sql = "SELECT UNIX_TIMESTAMP(access_date), count(access_date)
7388
                    FROM $track_access_table
7389
                    WHERE access_user_id = $user_id
7390
                    AND c_id = $course_id
7391
                    AND access_session_id = $session_id
7392
                    GROUP BY YEAR(access_date),MONTH(access_date)
7393
                    ORDER BY YEAR(access_date),MONTH(access_date) ASC";
7394
            //$results = getManyResults2Col($sql);
7395
            $results = getManyResults3Col($sql);
7396
            $title_line = get_lang('LoginsTitleMonthColumn').';'.get_lang('LoginsTitleCountColumn')."\n";
7397
            $line = '';
7398
            $total = 0;
7399 View Code Duplication
            if (is_array($results)) {
7400
                for ($j = 0; $j < count($results); $j++) {
7401
                    $line .= $results[$j][0].';'.$results[$j][1]."\n";
7402
                    $total = $total + $results[$j][1];
7403
                }
7404
                $line .= get_lang('Total').";".$total."\n";
7405
            } else {
7406
                $line = get_lang('NoResult')."</center></td>";
7407
            }
7408
        } else {
7409
            $new_view = substr_replace($view, '1', 0, 1);
7410
        }
7411
        return array($title_line, $line);
7412
    }
7413
7414
    /**
7415
     * Displays the exercise results for a specific user in a specific course.
7416
     * @param   string $view
7417
     * @param   int $user_id    User ID
0 ignored issues
show
Bug introduced by
There is no parameter named $user_id. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
7418
     * @param   string  $courseCode Course code
7419
     * @return array
7420
     * @todo remove globals
7421
     */
7422
    public function display_exercise_tracking_info($view, $userId, $courseCode)
7423
    {
7424
        global $TABLECOURSE_EXERCICES, $TABLETRACK_EXERCICES, $TABLETRACK_HOTPOTATOES, $dateTimeFormatLong;
7425
        $courseId = api_get_course_int_id($courseCode);
7426
        $userId = intval($userId);
7427
        if (substr($view, 1, 1) == '1') {
7428
            $new_view = substr_replace($view, '0', 1, 1);
7429
            $title[1] = get_lang('ExercicesDetails');
7430
            $line = '';
7431
            $sql = "SELECT ce.title, te.exe_result , te.exe_weighting, UNIX_TIMESTAMP(te.exe_date)
7432
                    FROM $TABLECOURSE_EXERCICES AS ce , $TABLETRACK_EXERCICES AS te
7433
                    WHERE te.c_id = $courseId
7434
                        AND te.exe_user_id = $userId
7435
                        AND te.exe_exo_id = ce.id
7436
                    ORDER BY ce.title ASC, te.exe_date ASC";
7437
7438
            $hpsql = "SELECT te.exe_name, te.exe_result , te.exe_weighting, UNIX_TIMESTAMP(te.exe_date)
7439
                        FROM $TABLETRACK_HOTPOTATOES AS te
7440
                        WHERE te.exe_user_id = '$userId' AND te.c_id = $courseId
7441
                        ORDER BY te.c_id ASC, te.exe_date ASC";
7442
7443
            $hpresults = StatsUtils::getManyResultsXCol($hpsql, 4);
7444
            $NoTestRes = 0;
7445
            $NoHPTestRes = 0;
7446
            $results = StatsUtils::getManyResultsXCol($sql, 4);
7447
            $title_line = get_lang('ExercicesTitleExerciceColumn').";".get_lang('Date').';'.get_lang('ExercicesTitleScoreColumn')."\n";
7448
7449 View Code Duplication
            if (is_array($results)) {
7450
                for ($i = 0; $i < sizeof($results); $i++) {
7451
                    $display_date = api_convert_and_format_date($results[$i][3], null, date_default_timezone_get());
7452
                    $line .= $results[$i][0].";".$display_date.";".$results[$i][1]." / ".$results[$i][2]."\n";
7453
                }
7454
            } else {
7455
                // istvan begin
7456
                $NoTestRes = 1;
7457
            }
7458
7459
            // The Result of Tests
7460
            if (is_array($hpresults)) {
7461
                for ($i = 0; $i < sizeof($hpresults); $i++) {
7462
                    $title = GetQuizName($hpresults[$i][0], '');
7463
                    if ($title == '') {
7464
                        $title = basename($hpresults[$i][0]);
7465
                    }
7466
                    $display_date = api_convert_and_format_date($hpresults[$i][3], null, date_default_timezone_get());
7467
                    $line .= $title.';'.$display_date.';'.$hpresults[$i][1].'/'.$hpresults[$i][2]."\n";
7468
                }
7469
            } else {
7470
                $NoHPTestRes = 1;
7471
            }
7472
7473
            if ($NoTestRes == 1 && $NoHPTestRes == 1) {
7474
                $line = get_lang('NoResult');
7475
            }
7476
        } else {
7477
            $new_view = substr_replace($view, '1', 1, 1);
7478
        }
7479
        return array($title_line, $line);
7480
    }
7481
7482
    /**
7483
     * Displays the student publications for a specific user in a specific course.
7484
     * @todo remove globals
7485
     */
7486
    public function display_student_publications_tracking_info($view, $user_id, $course_id)
7487
    {
7488
        global $TABLETRACK_UPLOADS, $TABLECOURSE_WORK;
7489
        $_course = api_get_course_info();
7490
        $user_id = intval($user_id);
7491
        $course_id = intval($course_id);
7492
7493
        if (substr($view, 2, 1) == '1') {
7494
            $sql = "SELECT u.upload_date, w.title, w.author, w.url
7495
                    FROM $TABLETRACK_UPLOADS u , $TABLECOURSE_WORK w
7496
                    WHERE
7497
                        u.upload_work_id = w.id AND
7498
                        u.upload_user_id = '$user_id' AND
7499
                        u.c_id = '$course_id'
7500
                    ORDER BY u.upload_date DESC";
7501
            $results = StatsUtils::getManyResultsXCol($sql, 4);
7502
7503
            $title[1] = get_lang('WorksDetails');
7504
            $line = '';
7505
            $title_line = get_lang('WorkTitle').";".get_lang('WorkAuthors').";".get_lang('Date')."\n";
7506
7507
            if (is_array($results)) {
7508
                for ($j = 0; $j < count($results); $j++) {
7509
                    $pathToFile = api_get_path(WEB_COURSE_PATH).$_course['path']."/".$results[$j][3];
7510
                    $beautifulDate = api_convert_and_format_date($results[$j][0], null, date_default_timezone_get());
7511
                    $line .= $results[$j][1].";".$results[$j][2].";".$beautifulDate."\n";
7512
                }
7513
7514
            } else {
7515
                $line = get_lang('NoResult');
7516
            }
7517
        }
7518
7519
        return array($title_line, $line);
7520
    }
7521
7522
    /**
7523
     * Displays the links followed for a specific user in a specific course.
7524
     * @todo remove globals
7525
     */
7526
    public function display_links_tracking_info($view, $userId, $courseCode)
7527
    {
7528
        global $TABLETRACK_LINKS, $TABLECOURSE_LINKS;
7529
        $courseId = api_get_course_int_id($courseCode);
7530
        $userId = intval($userId);
7531
        $line = null;
7532 View Code Duplication
        if (substr($view, 3, 1) == '1') {
7533
            $new_view = substr_replace($view, '0', 3, 1);
7534
            $title[1] = get_lang('LinksDetails');
7535
            $sql = "SELECT cl.title, cl.url
7536
                        FROM $TABLETRACK_LINKS AS sl, $TABLECOURSE_LINKS AS cl
7537
                        WHERE sl.links_link_id = cl.id
7538
                            AND sl.c_id = $courseId
7539
                            AND sl.links_user_id = $userId
7540
                        GROUP BY cl.title, cl.url";
7541
            $results = StatsUtils::getManyResults2Col($sql);
7542
            $title_line = get_lang('LinksTitleLinkColumn')."\n";
7543
            if (is_array($results)) {
7544
                for ($j = 0; $j < count($results); $j++) {
7545
                    $line .= $results[$j][0]."\n";
7546
                }
7547
            } else {
7548
                $line = get_lang('NoResult');
7549
            }
7550
        } else {
7551
            $new_view = substr_replace($view, '1', 3, 1);
7552
        }
7553
        return array($title_line, $line);
7554
    }
7555
7556
    /**
7557
     * Displays the documents downloaded for a specific user in a specific course.
7558
     * @param     string    kind of view inside tracking info
7559
     * @param    int        User id
7560
     * @param    string    Course code
7561
     * @param    int        Session id (optional, default = 0)
7562
     * @return     void
7563
     */
7564
    public function display_document_tracking_info($view, $user_id, $courseCode, $session_id = 0)
7565
    {
7566
        // protect data
7567
        $user_id = intval($user_id);
7568
        $courseId = api_get_course_int_id($courseCode);
7569
        $session_id = intval($session_id);
7570
7571
        $downloads_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
7572
7573 View Code Duplication
        if (substr($view, 4, 1) == '1') {
7574
            $new_view = substr_replace($view, '0', 4, 1);
7575
            $title[1] = get_lang('DocumentsDetails');
7576
7577
            $sql = "SELECT down_doc_path
7578
                        FROM $downloads_table
7579
                        WHERE c_id = $courseId
7580
                            AND down_user_id = $user_id
7581
                            AND down_session_id = $session_id
7582
                        GROUP BY down_doc_path";
7583
7584
            $results = StatsUtils::getManyResults1Col($sql);
7585
            $title_line = get_lang('DocumentsTitleDocumentColumn')."\n";
7586
            $line = null;
7587
            if (is_array($results)) {
7588
                for ($j = 0; $j < count($results); $j++) {
7589
                    $line .= $results[$j]."\n";
7590
                }
7591
            } else {
7592
                $line = get_lang('NoResult');
7593
            }
7594
        } else {
7595
            $new_view = substr_replace($view, '1', 4, 1);
7596
        }
7597
        return array($title_line, $line);
7598
    }
7599
7600
    /**
7601
     * @param $userId
7602
     * @param $courseInfo
7603
     * @param int $sessionId
7604
     * @return array
7605
     */
7606
    public static function getToolInformation(
7607
        $userId,
7608
        $courseInfo,
7609
        $sessionId = 0
7610
    ) {
7611
        $csvContent = array();
7612
        $courseToolInformation = null;
7613
        $headerTool = array(
7614
            array(get_lang('Title')),
7615
            array(get_lang('CreatedAt')),
7616
            array(get_lang('UpdatedAt')),
7617
        );
7618
7619
        $headerListForCSV = array();
7620
        foreach ($headerTool as $item) {
7621
            $headerListForCSV[] = $item[0];
7622
        }
7623
7624
        $courseForumInformationArray = getForumCreatedByUser(
7625
            $userId,
7626
            $courseInfo['real_id'],
7627
            $sessionId
7628
        );
7629
7630
        if (!empty($courseForumInformationArray)) {
7631
            $csvContent[] = array();
7632
            $csvContent[] = get_lang('Forums');
7633
            $csvContent[] = $headerListForCSV;
7634
            foreach ($courseForumInformationArray as $row) {
7635
                $csvContent[] = $row;
7636
            }
7637
7638
            $courseToolInformation .= Display::page_subheader2(
7639
                get_lang('Forums')
7640
            );
7641
            $courseToolInformation .= Display::return_sortable_table(
7642
                $headerTool,
7643
                $courseForumInformationArray
7644
            );
7645
        }
7646
7647
        $courseWorkInformationArray = getWorkCreatedByUser(
7648
            $userId,
7649
            $courseInfo['real_id'],
7650
            $sessionId
7651
        );
7652
7653
        if (!empty($courseWorkInformationArray)) {
7654
            $csvContent[] = null;
7655
            $csvContent[] = get_lang('Works');
7656
            $csvContent[] = $headerListForCSV;
7657
7658
            foreach ($courseWorkInformationArray as $row) {
7659
                $csvContent[] = $row;
7660
            }
7661
            $csvContent[] = null;
7662
7663
            $courseToolInformation .= Display::page_subheader2(
7664
                get_lang('Works')
7665
            );
7666
            $courseToolInformation .= Display::return_sortable_table(
7667
                $headerTool,
7668
                $courseWorkInformationArray
7669
            );
7670
        }
7671
        $courseToolInformationTotal = null;
7672
7673
        if (!empty($courseToolInformation)) {
7674
            $sessionTitle = null;
7675
            if (!empty($sessionId)) {
7676
                $sessionTitle = ' ('.api_get_session_name($sessionId).')';
7677
            }
7678
7679
            $courseToolInformationTotal .= Display::page_subheader(
7680
                $courseInfo['title'].$sessionTitle
7681
            );
7682
            $courseToolInformationTotal .= $courseToolInformation;
7683
        }
7684
7685
        return array(
7686
            'array' => $csvContent,
7687
            'html' => $courseToolInformationTotal
7688
        );
7689
    }
7690
}
7691