Passed
Push — 1.10.x ( a1d2e8...1c366c )
by
unknown
49:29
created

Tracking::get_avg_student_progress()   F

Complexity

Conditions 21
Paths 1546

Size

Total Lines 148
Code Lines 81

Duplication

Lines 6
Ratio 4.05 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 6
loc 148
rs 2
cc 21
eloc 81
nc 1546
nop 6

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
5
use CpChart\Classes\pCache as pCache;
6
use CpChart\Classes\pData as pData;
7
use CpChart\Classes\pImage as pImage;
8
9
/**
10
 *  Class Tracking
11
 *
12
 *  @author  Julio Montoya <[email protected]>
13
 *  @package chamilo.library
14
 */
15
class Tracking
16
{
17
    public static function get_group_reporting(
18
        $course_id,
19
        $group_id = null,
20
        $type = 'all',
21
        $start = 0,
22
        $limit = 1000,
23
        $sidx = 1,
24
        $sord = 'desc',
25
        $where_condition = array()
26
    ) {
27
        if (empty($course_id)) {
28
            return null;
29
        }
30
        $course_info = api_get_course_info_by_id($course_id);
31
        $table_group = Database :: get_course_table(TABLE_GROUP);
32
        $course_id = intval($course_id);
33
34
        $select = ' * ';
35
        if ($type == 'count') {
36
            $select = ' count(id) as count ';
37
        }
38
39
        $default_where = array('c_id = ? ' => array($course_id));
40
41
        $result = Database::select($select, $table_group, array(
42
                'limit' => " $start, $limit",
43
                'where' => $default_where,
44
                'order' => "$sidx $sord")
45
        );
46
47
        if ($type == 'count') {
48
            return $result[0]['count'];
49
        }
50
51
        $parsed_result = array();
52
        if (!empty($result)) {
53
            foreach ($result as $group) {
54
                $users = GroupManager::get_users($group['id'], true);
55
56
                $time = 0;
57
                $avg_student_score = 0;
58
                $avg_student_progress = 0;
59
                $work = 0;
60
                $messages = 0;
61
62
                foreach ($users as $user_data) {
63
                    $time += Tracking::get_time_spent_on_the_course($user_data['user_id'], $course_info['code'], 0);
64
                    $avg_student_score += Tracking::get_avg_student_score($user_data['user_id'], $course_info['code'], array(), 0);
65
                    $avg_student_progress += Tracking::get_avg_student_progress($user_data['user_id'], $course_info['code'], array(), 0);
66
                    $work += Tracking::count_student_assignments($user_data['user_id'], $course_info['code'], 0);
67
                    $messages += Tracking::count_student_messages($user_data['user_id'], $course_info['code'], 0);
68
                }
69
70
                $group_item = array(
71
                    'id' => $group['id'],
72
                    'name' => $group['name'],
73
                    'time' => api_time_to_hms($time),
74
                    'progress' => $avg_student_progress,
75
                    'score' => $avg_student_score,
76
                    'works' => $work,
77
                    'messages' => $messages,
78
                );
79
                $parsed_result[] = $group_item;
80
            }
81
        }
82
        return $parsed_result;
83
    }
84
85
    /**
86
     * @param int $user_id
87
     * @param array $courseInfo
88
     * @param int $session_id
89
     * @param string $origin
90
     * @param bool $export_csv
91
     * @param int $lp_id
92
     * @param int $lp_item_id
93
     * @param int $extendId
94
     * @param int $extendAttemptId
95
     * @param string $extendedAttempt
96
     * @param string $extendedAll
97
     * @param string $type classic or simple
98
     * @param boolean $allowExtend Optional. Allow or not extend te results
99
     * @return null|string
100
     */
101
    public static function getLpStats(
102
        $user_id,
103
        $courseInfo,
104
        $session_id,
105
        $origin,
106
        $export_csv,
107
        $lp_id,
108
        $lp_item_id = null,
109
        $extendId = null,
110
        $extendAttemptId = null,
111
        $extendedAttempt = null,
112
        $extendedAll = null,
113
        $type = 'classic',
114
        $allowExtend =  true
115
    ) {
116
        if (empty($courseInfo) || empty($lp_id)) {
117
            return null;
118
        }
119
120
        $lp_id = intval($lp_id);
121
        $lp_item_id = intval($lp_item_id);
122
        $user_id = intval($user_id);
123
        $session_id = intval($session_id);
124
        $origin = Security::remove_XSS($origin);
125
126
        $list = learnpath :: get_flat_ordered_items_list($lp_id, 0, $courseInfo['real_id']);
127
128
        $is_allowed_to_edit = api_is_allowed_to_edit(null, true);
129
        $course_id = $courseInfo['real_id'];
130
        $courseCode = $courseInfo['code'];
131
        $session_condition = api_get_session_condition($session_id);
132
133
        // Extend all button
134
        $output = null;
135
        $extend_all = 0;
136
137
        if ($origin == 'tracking') {
138
            $url_suffix = '&session_id=' . $session_id . '&course=' . $courseCode . '&student_id=' . $user_id . '&lp_id=' . $lp_id . '&origin=' . $origin;
139
        } else {
140
            $url_suffix = '&lp_id=' . $lp_id;
141
        }
142
143
        if (!empty($extendedAll)) {
144
            $extend_all_link = Display::url(
145
                Display::return_icon('view_less_stats.gif', get_lang('HideAllAttempts')),
146
                api_get_self() . '?action=stats' . $url_suffix
147
            );
148
149
            $extend_all = 1;
150
        } else {
151
            $extend_all_link = Display::url(
152
                Display::return_icon('view_more_stats.gif', get_lang('ShowAllAttempts')),
153
                api_get_self() . '?action=stats&extend_all=1' . $url_suffix
154
            );
155
        }
156
157
        if ($origin != 'tracking') {
158
            $output .= '<div class="section-status">';
159
            $output .= Display::page_header(get_lang('ScormMystatus'));
160
            $output .= '</div>';
161
        }
162
163
        $actionColumn = null;
164
        if ($type == 'classic') {
165
            $actionColumn = ' <th>' . get_lang('Actions') . '</th>';
166
        }
167
        $output .= '<div class="table-responsive">';
168
        $output .= '<table class="table tracking">
169
            <thead>
170
            <tr class="table-header">
171
                <th width="16">' . ($allowExtend == true ? $extend_all_link : '&nbsp;') . '</th>
172
                <th colspan="4">
173
                    ' . get_lang('ScormLessonTitle') .'
174
                </th>
175
                <th colspan="2">
176
                    ' . get_lang('ScormStatus') . '
177
                </th>
178
                <th colspan="2">
179
                    ' . get_lang('ScormScore') . '
180
                </th>
181
                <th colspan="2">
182
                    ' . get_lang('ScormTime') . '
183
                </th>
184
                '.$actionColumn.'
185
                </tr>
186
            </thead>
187
            <tbody>
188
        ';
189
190
        // Going through the items using the $items[] array instead of the database order ensures
191
        // we get them in the same order as in the imsmanifest file, which is rather random when using
192
        // the database table.
193
194
        $TBL_LP_ITEM = Database :: get_course_table(TABLE_LP_ITEM);
195
        $TBL_LP_ITEM_VIEW = Database :: get_course_table(TABLE_LP_ITEM_VIEW);
196
        $TBL_LP_VIEW = Database :: get_course_table(TABLE_LP_VIEW);
197
        $tbl_quiz_questions = Database :: get_course_table(TABLE_QUIZ_QUESTION);
198
        $TBL_QUIZ = Database :: get_course_table(TABLE_QUIZ_TEST);
199
        $tbl_stats_exercices = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
200
        $tbl_stats_attempts = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
201
202
        $sql = "SELECT max(view_count)
203
                FROM $TBL_LP_VIEW
204
                WHERE
205
                    c_id = $course_id AND
206
                    lp_id = $lp_id AND
207
                    user_id = $user_id
208
                    $session_condition";
209
        $res = Database::query($sql);
210
        $view = '';
211
        if (Database :: num_rows($res) > 0) {
212
            $myrow = Database :: fetch_array($res);
213
            $view = $myrow[0];
214
        }
215
216
        $counter = 0;
217
        $total_time = 0;
218
        $h = get_lang('h');
219
220
        if (!empty($export_csv)) {
221
            $csv_content[] = array(
222
                get_lang('ScormLessonTitle'),
223
                get_lang('ScormStatus'),
224
                get_lang('ScormScore'),
225
                get_lang('ScormTime')
226
            );
227
        }
228
229
        $result_disabled_ext_all = true;
230
        $chapterTypes = learnpath::getChapterTypes();
231
232
        // Show lp items
233
        if (is_array($list) && count($list) > 0) {
234
            foreach ($list as $my_item_id) {
235
                $extend_this = 0;
236
                $order = 'DESC';
237
                if ((!empty($extendId) && $extendId == $my_item_id) || $extend_all) {
238
                    $extend_this = 1;
239
                    $order = 'ASC';
240
                }
241
242
                // Prepare statement to go through each attempt.
243
                $viewCondition = null;
244
                if (!empty($view)) {
245
                    $viewCondition =  " AND v.view_count = $view  ";
246
                }
247
248
                $sql = "SELECT
249
                    iv.status as mystatus,
250
                    v.view_count as mycount,
251
                    iv.score as myscore,
252
                    iv.total_time as mytime,
253
                    i.id as myid,
254
                    i.lp_id as mylpid,
255
                    iv.lp_view_id as mylpviewid,
256
                    i.title as mytitle,
257
                    i.max_score as mymaxscore,
258
                    iv.max_score as myviewmaxscore,
259
                    i.item_type as item_type,
260
                    iv.view_count as iv_view_count,
261
                    iv.id as iv_id,
262
                    path
263
                FROM $TBL_LP_ITEM as i
264
                INNER JOIN $TBL_LP_ITEM_VIEW as iv
265
                ON (i.id = iv.lp_item_id AND i.c_id = iv.c_id)
266
                INNER JOIN $TBL_LP_VIEW as v
267
                ON (iv.lp_view_id = v.id AND v.c_id = iv.c_id)
268
                WHERE
269
                    v.c_id = $course_id AND
270
                    i.id = $my_item_id AND
271
                    i.lp_id = $lp_id  AND
272
                    v.user_id = $user_id AND
273
                    v.session_id = $session_id
274
                    $viewCondition
275
                ORDER BY iv.view_count $order ";
276
277
                $result = Database::query($sql);
278
                $num = Database :: num_rows($result);
279
                $time_for_total = 'NaN';
280
281
                // Extend all
282
                if (($extend_this || $extend_all) && $num > 0) {
283
                    $row = Database :: fetch_array($result);
284
                    $result_disabled_ext_all = false;
285 View Code Duplication
                    if ($row['item_type'] == 'quiz') {
286
                        // Check results_disabled in quiz table.
287
                        $my_path = Database::escape_string($row['path']);
288
289
                        $sql = "SELECT results_disabled
290
                                FROM $TBL_QUIZ
291
                                WHERE
292
                                    c_id = $course_id AND
293
                                    id ='" . $my_path . "'";
294
                        $res_result_disabled = Database::query($sql);
295
                        $row_result_disabled = Database::fetch_row($res_result_disabled);
296
297
                        if (Database::num_rows($res_result_disabled) > 0 &&
298
                            (int) $row_result_disabled[0] === 1
299
                        ) {
300
                            $result_disabled_ext_all = true;
301
                        }
302
                    }
303
304
                    // If there are several attempts, and the link to extend has been clicked, show each attempt...
305
                    if (($counter % 2) == 0) {
306
                        $oddclass = 'row_odd';
307
                    } else {
308
                        $oddclass = 'row_even';
309
                    }
310
311
                    $extend_link = '';
312 View Code Duplication
                    if (!empty($inter_num)) {
313
                        $extend_link = Display::url(
314
                              Display::return_icon('visible.gif', get_lang('HideAttemptView')),
315
                              api_get_self() . '?action=stats&fold_id=' . $my_item_id . $url_suffix
316
                        );
317
                    }
318
                    $title = $row['mytitle'];
319
320
                    if (empty($title)) {
321
                        $title = rl_get_resource_name($courseInfo['code'], $lp_id, $row['myid']);
322
                    }
323
324
                    if (in_array($row['item_type'], $chapterTypes)) {
325
                        $title = "<h4> $title </h4>";
326
                    }
327
                    $lesson_status = $row['mystatus'];
328
                    $title = Security::remove_XSS($title);
329
                    $counter++;
330
331
                    $action = null;
332
                    if ($type == 'classic') {
333
                        $action =  '<td></td>';
334
                    }
335
336
                    if (in_array($row['item_type'], $chapterTypes)) {
337
                        $output .= '<tr class="'.$oddclass.'">
338
                                <td>'.$extend_link.'</td>
339
                                <td colspan="4">
340
                                   '.$title.'
341
                                </td>
342
                                <td colspan="2">'.learnpathItem::humanize_status($lesson_status, true, $type).'</td>
343
                                <td colspan="2"></td>
344
                                <td colspan="2"></td>
345
                                '.$action.'
346
                            </tr>';
347
                        continue;
348
                    } else {
349
                        $output .= '<tr class="'.$oddclass.'">
350
                                <td>'.$extend_link.'</td>
351
                                <td colspan="4">
352
                                   '.$title.'
353
                                </td>
354
                                <td colspan="2"></td>
355
                                <td colspan="2"></td>
356
                                <td colspan="2"></td>
357
                                '.$action.'
358
                            </tr>';
359
                    }
360
361
                    $attemptCount = 1;
362
363
                    do {
364
                        // Check if there are interactions below.
365
                        $extend_attempt_link = '';
366
                        $extend_this_attempt = 0;
367
368
                        if ((learnpath::get_interactions_count_from_db($row['iv_id'], $course_id) > 0 ||
369
                            learnpath::get_objectives_count_from_db($row['iv_id'], $course_id) > 0) &&
370
                            !$extend_all
371
                        ) {
372 View Code Duplication
                            if ($extendAttemptId == $row['iv_id']) {
373
                                // The extend button for this attempt has been clicked.
374
                                $extend_this_attempt = 1;
375
                                $extend_attempt_link = Display::url(
376
                                    Display::return_icon('visible.gif', get_lang('HideAttemptView')),
377
                                    api_get_self() . '?action=stats&extend_id=' . $my_item_id . '&fold_attempt_id=' . $row['iv_id'] . $url_suffix
378
                                );
379
                            } else { // Same case if fold_attempt_id is set, so not implemented explicitly.
380
                                // The extend button for this attempt has not been clicked.
381
                                $extend_attempt_link = Display::url(
382
                                    Display::return_icon('invisible.gif', get_lang('ExtendAttemptView')),
383
                                    api_get_self() . '?action=stats&extend_id=' . $my_item_id . '&extend_attempt_id=' . $row['iv_id'] . $url_suffix
384
                                );
385
                            }
386
                        }
387
388
                        if (($counter % 2) == 0) {
389
                            $oddclass = 'row_odd';
390
                        } else {
391
                            $oddclass = 'row_even';
392
                        }
393
394
                        $lesson_status = $row['mystatus'];
395
                        $score = $row['myscore'];
396
                        $time_for_total = $row['mytime'];
397
                        $time = learnpathItem :: getScormTimeFromParameter('js', $row['mytime']);
398
399
                        if ($score == 0) {
400
                            $maxscore = $row['mymaxscore'];
401
                        } else {
402
                            if ($row['item_type'] == 'sco') {
403 View Code Duplication
                                if (!empty($row['myviewmaxscore']) && $row['myviewmaxscore'] > 0) {
404
                                    $maxscore = $row['myviewmaxscore'];
405
                                } elseif ($row['myviewmaxscore'] === '') {
406
                                    $maxscore = 0;
407
                                } else {
408
                                    $maxscore = $row['mymaxscore'];
409
                                }
410
                            } else {
411
                                $maxscore = $row['mymaxscore'];
412
                            }
413
                        }
414
415
                        // Remove "NaN" if any (@todo: locate the source of these NaN)
416
                        $time = str_replace('NaN', '00' . $h . '00\'00"', $time);
417
418
                        if ($row['item_type'] != 'dokeos_chapter') {
419
                            if (!$is_allowed_to_edit && $result_disabled_ext_all) {
420
                                $view_score = Display::return_icon('invisible.gif', get_lang('ResultsHiddenByExerciseSetting'));
421
                            } else {
422
                                switch ($row['item_type']) {
423 View Code Duplication
                                    case 'sco':
424
                                        if ($maxscore == 0) {
425
                                            $view_score = $score;
426
                                        } else {
427
                                            $view_score = ExerciseLib::show_score($score, $maxscore, false);
428
                                        }
429
                                        break;
430 View Code Duplication
                                    case 'document':
431
                                        $view_score = ($score == 0 ? '/' : ExerciseLib::show_score($score, $maxscore, false));
432
                                        break;
433
                                    default:
434
                                        $view_score = ExerciseLib::show_score($score, $maxscore, false);
435
                                        break;
436
                                }
437
                            }
438
439
                            $action = null;
440
                            if ($type == 'classic') {
441
                                $action = '<td></td>';
442
                            }
443
444
                            $output .= '<tr class="' . $oddclass . '">
445
                                    <td></td>
446
                                    <td>' . $extend_attempt_link . '</td>
447
                                    <td colspan="3">' . get_lang('Attempt') . ' ' . $attemptCount . '</td>
448
                                    <td colspan="2">' . learnpathItem::humanize_status($lesson_status, true, $type) . '</td>
449
                                    <td colspan="2">' . $view_score . '</td>
450
                                    <td colspan="2">' . $time . '</td>
451
                                    '.$action.'
452
                                </tr>';
453
                            $attemptCount++;
454
                            if (!empty($export_csv)) {
455
                                $temp = array();
456
                                $temp[] = $title = Security::remove_XSS($title);
457
                                $temp[] = Security::remove_XSS(learnpathItem::humanize_status($lesson_status, false, $type));
458
459 View Code Duplication
                                if ($row['item_type'] == 'quiz') {
460
                                    if (!$is_allowed_to_edit && $result_disabled_ext_all) {
461
                                        $temp[] = '/';
462
                                    } else {
463
                                        $temp[] = ($score == 0 ? '0/' . $maxscore : ($maxscore == 0 ? $score : $score . '/' . float_format($maxscore, 1)));
464
                                    }
465
                                } else {
466
                                    $temp[] = ($score == 0 ? '/' : ($maxscore == 0 ? $score : $score . '/' . float_format($maxscore, 1)));
467
                                }
468
                                $temp[] = $time;
469
                                $csv_content[] = $temp;
470
                            }
471
                        }
472
473
                        $counter++;
474
475
                        $action = null;
476
                        if ($type == 'classic') {
477
                            $action = '<td></td>';
478
                        }
479
480
                        if ($extend_this_attempt || $extend_all) {
481
                            $list1 = learnpath :: get_iv_interactions_array($row['iv_id']);
482
                            foreach ($list1 as $id => $interaction) {
483
                                if (($counter % 2) == 0) {
484
                                    $oddclass = 'row_odd';
485
                                } else {
486
                                    $oddclass = 'row_even';
487
                                }
488
                                $student_response = urldecode($interaction['student_response']);
489
                                $content_student_response = explode('__|', $student_response);
490
491
                                if (count($content_student_response) > 0) {
492
                                    if (count($content_student_response) >= 3) {
493
                                        // Pop the element off the end of array.
494
                                        array_pop($content_student_response);
495
                                    }
496
                                    $student_response = implode(',', $content_student_response);
497
                                }
498
499
                                $output .= '<tr class="'.$oddclass.'">
500
                                        <td></td>
501
                                        <td></td>
502
                                        <td></td>
503
                                        <td>'.$interaction['order_id'] . '</td>
504
                                        <td>'.$interaction['id'] . '</td>
505
                                        <td colspan="2">' . $interaction['type'].'</td>
506
                                        <td>'.$student_response . '</td>
507
                                        <td>'.$interaction['result'] . '</td>
508
                                        <td>'.$interaction['latency'] . '</td>
509
                                        <td>'.$interaction['time'] . '</td>
510
                                        '.$action.'
511
                                    </tr>';
512
                                $counter++;
513
                            }
514
                            $list2 = learnpath :: get_iv_objectives_array($row['iv_id']);
515
516 View Code Duplication
                            foreach ($list2 as $id => $interaction) {
517
                                if (($counter % 2) == 0) {
518
                                    $oddclass = 'row_odd';
519
                                } else {
520
                                    $oddclass = 'row_even';
521
                                }
522
                                $output .= '<tr class="'.$oddclass.'">
523
                                        <td></td>
524
                                        <td></td>
525
                                        <td></td>
526
                                        <td>' . $interaction['order_id'] . '</td>
527
                                        <td colspan="2">' . $interaction['objective_id'] . '</td>
528
                                        <td colspan="2">' . $interaction['status'] .'</td>
529
                                        <td>' . $interaction['score_raw'] . '</td>
530
                                        <td>' . $interaction['score_max'] . '</td>
531
                                        <td>' . $interaction['score_min'] . '</td>
532
                                        '.$action.'
533
                                     </tr>';
534
                                $counter++;
535
                            }
536
                        }
537
                    } while ($row = Database :: fetch_array($result));
538
                } elseif ($num > 0) {
539
                    // Not extended.
540
541
                    $row = Database :: fetch_array($result, 'ASSOC');
542
                    $my_id = $row['myid'];
543
                    $my_lp_id = $row['mylpid'];
544
                    $my_lp_view_id = $row['mylpviewid'];
545
                    $my_path = $row['path'];
546
547
                    $result_disabled_ext_all = false;
548
549 View Code Duplication
                    if ($row['item_type'] == 'quiz') {
550
                        // Check results_disabled in quiz table.
551
                        $my_path = Database::escape_string($my_path);
552
                        $sql = "SELECT results_disabled
553
                                FROM $TBL_QUIZ
554
                                WHERE c_id = $course_id AND id ='" . $my_path . "'";
555
                        $res_result_disabled = Database::query($sql);
556
                        $row_result_disabled = Database::fetch_row($res_result_disabled);
557
558
                        if (Database::num_rows($res_result_disabled) > 0 &&
559
                            (int) $row_result_disabled[0] === 1
560
                        ) {
561
                            $result_disabled_ext_all = true;
562
                        }
563
                    }
564
565
                    // Check if there are interactions below
566
                    $extend_this_attempt = 0;
567
568
                    $inter_num = learnpath::get_interactions_count_from_db($row['iv_id'], $course_id);
569
                    $objec_num = learnpath::get_objectives_count_from_db($row['iv_id'], $course_id);
570
571
                    $extend_attempt_link = '';
572
                    if ($inter_num > 0 || $objec_num > 0) {
573 View Code Duplication
                        if (!empty($extendAttemptId) && $extendAttemptId == $row['iv_id']) {
574
                            // The extend button for this attempt has been clicked.
575
                            $extend_this_attempt = 1;
576
                            $extend_attempt_link = Display::url(
577
                                Display::return_icon('visible.gif', get_lang('HideAttemptView')),
578
                                api_get_self() . '?action=stats&extend_id=' . $my_item_id . '&fold_attempt_id=' . $row['iv_id'] . $url_suffix
579
                            );
580
                        } else {
581
                            // Same case if fold_attempt_id is set, so not implemented explicitly.
582
                            // The extend button for this attempt has not been clicked.
583
                            $extend_attempt_link = Display::url(
584
                                Display::return_icon('invisible.gif', get_lang('ExtendAttemptView')),
585
                                api_get_self() . '?action=stats&extend_id=' . $my_item_id . '&extend_attempt_id=' . $row['iv_id'] . $url_suffix
586
                            );
587
                        }
588
                    }
589
590
                    if (($counter % 2) == 0) {
591
                        $oddclass = 'row_odd';
592
                    } else {
593
                        $oddclass = 'row_even';
594
                    }
595
596
                    $extend_link = '';
597
                    if ($inter_num > 1) {
598
                        $extend_link = Display::url(
599
                            Display::return_icon('invisible.gif', get_lang('ExtendAttemptView')),
600
                            api_get_self() . '?action=stats&extend_id=' . $my_item_id . '&extend_attempt_id=' . $row['iv_id'] . $url_suffix
601
                        );
602
                    }
603
604
                    $lesson_status = $row['mystatus'];
605
                    $score = $row['myscore'];
606
                    $subtotal_time = $row['mytime'];
607
608
                    while ($tmp_row = Database :: fetch_array($result)) {
609
                        $subtotal_time += $tmp_row['mytime'];
610
                    }
611
612
                    $title = $row['mytitle'];
613
614
                    // Selecting the exe_id from stats attempts tables in order to look the max score value.
615
616
                    $sql = 'SELECT * FROM ' . $tbl_stats_exercices . '
617
                             WHERE
618
                                exe_exo_id="' . $row['path'] . '" AND
619
                                exe_user_id="' . $user_id . '" AND
620
                                orig_lp_id = "' . $lp_id . '" AND
621
                                orig_lp_item_id = "' . $row['myid'] . '" AND
622
                                c_id = ' . $course_id . ' AND
623
                                status <> "incomplete" AND
624
                                session_id = ' . $session_id . '
625
                             ORDER BY exe_date DESC
626
                             LIMIT 1';
627
628
                    $resultLastAttempt = Database::query($sql);
629
                    $num = Database :: num_rows($resultLastAttempt);
630
                    $id_last_attempt = null;
631
                    if ($num > 0) {
632
                        while ($rowLA = Database :: fetch_array($resultLastAttempt)) {
633
                            $id_last_attempt = $rowLA['exe_id'];
634
                        }
635
                    }
636
637
                    if ($score == 0) {
638
                        $maxscore = $row['mymaxscore'];
639
                    } else {
640
                        if ($row['item_type'] == 'sco') {
641 View Code Duplication
                            if (!empty($row['myviewmaxscore']) and $row['myviewmaxscore'] > 0) {
642
                                $maxscore = $row['myviewmaxscore'];
643
                            } elseif ($row['myviewmaxscore'] === '') {
644
                                $maxscore = 0;
645
                            } else {
646
                                $maxscore = $row['mymaxscore'];
647
                            }
648
                        } else {
649
                            if ($row['item_type'] == 'quiz') {
650
                                // Get score and total time from last attempt of a exercise en lp.
651
                                $sql = "SELECT score
652
                                        FROM $TBL_LP_ITEM_VIEW
653
                                        WHERE
654
                                            c_id = $course_id AND
655
                                            lp_item_id = '" . (int) $my_id . "' AND
656
                                            lp_view_id = '" . (int) $my_lp_view_id . "'
657
                                        ORDER BY view_count DESC limit 1";
658
                                $res_score = Database::query($sql);
659
                                $row_score = Database::fetch_array($res_score);
660
661
                                $sql = "SELECT SUM(total_time) as total_time
662
                                        FROM $TBL_LP_ITEM_VIEW
663
                                        WHERE
664
                                            c_id = $course_id AND
665
                                            lp_item_id = '" . (int) $my_id . "' AND
666
                                            lp_view_id = '" . (int) $my_lp_view_id . "'";
667
                                $res_time = Database::query($sql);
668
                                $row_time = Database::fetch_array($res_time);
669
670
                                if (Database::num_rows($res_score) > 0 &&
671
                                    Database::num_rows($res_time) > 0
672
                                ) {
673
                                    $score = (float) $row_score['score'];
674
                                    $subtotal_time = (int) $row_time['total_time'];
675
                                } else {
676
                                    $score = 0;
677
                                    $subtotal_time = 0;
678
                                }
679
                                // Selecting the max score from an attempt.
680
                                $sql = "SELECT SUM(t.ponderation) as maxscore
681
                                        FROM (
682
                                            SELECT DISTINCT
683
                                                question_id, marks, ponderation
684
                                            FROM $tbl_stats_attempts as at
685
                                            INNER JOIN  $tbl_quiz_questions as q
686
                                            ON (q.id = at.question_id AND q.c_id = $course_id)
687
                                            WHERE exe_id ='$id_last_attempt'
688
                                        ) as t";
689
690
                                $result = Database::query($sql);
691
                                $row_max_score = Database :: fetch_array($result);
692
                                $maxscore = $row_max_score['maxscore'];
693
                            } else {
694
                                $maxscore = $row['mymaxscore'];
695
                            }
696
                        }
697
                    }
698
699
                    $time_for_total = $subtotal_time;
700
                    $time = learnpathItem::getScormTimeFromParameter('js', $subtotal_time);
701
                    if (empty($title)) {
702
                        $title = rl_get_resource_name($courseInfo['code'], $lp_id, $row['myid']);
703
                    }
704
705
                    $action = null;
706
                    if ($type == 'classic') {
707
                        $action = '<td></td>';
708
                    }
709
710
                    if (in_array($row['item_type'], $chapterTypes)) {
711
                        $title = Security::remove_XSS($title);
712
                        $output .= '<tr class="'.$oddclass.'">
713
                                <td>'.$extend_link.'</td>
714
                                <td colspan="4">
715
                                <h4>'.$title.'</h4>
716
                                </td>
717
                                <td colspan="2">'.learnpathitem::humanize_status($lesson_status).'</td>
718
                                <td colspan="2"></td>
719
                                <td colspan="2"></td>
720
                                '.$action.'
721
                            </tr>';
722
                    } else {
723
                        $correct_test_link = '-';
724
                        if ($row['item_type'] == 'quiz') {
725
                            $my_url_suffix = '&course=' . $courseCode . '&student_id=' . $user_id . '&lp_id=' . intval($row['mylpid']) . '&origin=' . $origin;
726
                            $sql = 'SELECT * FROM ' . $tbl_stats_exercices . '
727
                                     WHERE
728
                                        exe_exo_id="' . $row['path'] . '" AND
729
                                        exe_user_id="' . $user_id . '" AND
730
                                        orig_lp_id = "' . $lp_id . '" AND
731
                                        orig_lp_item_id = "' . $row['myid'] . '" AND
732
                                        c_id = ' . $course_id . ' AND
733
                                        status <> "incomplete" AND
734
                                        session_id = ' . $session_id . '
735
                                     ORDER BY exe_date DESC ';
736
737
                            $resultLastAttempt = Database::query($sql);
738
                            $num = Database :: num_rows($resultLastAttempt);
739
                            if ($num > 0) {
740
                                if ($extendedAttempt == 1 &&
741
                                    $lp_id == $my_lp_id &&
742
                                    $lp_item_id == $my_id
743
                                ) {
744
                                    $correct_test_link = Display::url(
745
                                        Display::return_icon('view_less_stats.gif', get_lang('HideAllAttempts')),
746
                                        api_get_self() . '?action=stats' . $my_url_suffix . '&session_id=' . $session_id . '&lp_item_id=' . $my_id
747
                                    );
748 View Code Duplication
                                } else {
749
                                    $correct_test_link = Display::url(
750
                                        Display::return_icon('view_more_stats.gif', get_lang('ShowAllAttemptsByExercise')),
751
                                        api_get_self() . '?action=stats&extend_attempt=1' . $my_url_suffix . '&session_id=' . $session_id . '&lp_item_id=' . $my_id
752
                                    );
753
                                }
754
                            }
755
                        }
756
757
                        $title = Security::remove_XSS($title);
758
759
                        $action = null;
760
                        if ($type == 'classic') {
761
                            $action =  '<td>' . $correct_test_link . '</td>';
762
                        }
763
764
                        if ($lp_id == $my_lp_id && false) {
765
766
                            $output .= '<tr class =' . $oddclass . '>
767
                                    <td>' . $extend_link . '</td>
768
                                    <td colspan="4">' . $title . '</td>
769
                                    <td colspan="2">&nbsp;</td>
770
                                    <td colspan="2">&nbsp;</td>
771
                                    <td colspan="2">&nbsp;</td>
772
                                    '.$action.'
773
                                </tr>';
774
                            $output .= '</tr>';
775
                        } else {
776
                            if ($lp_id == $my_lp_id && $lp_item_id == $my_id) {
777
                                $output .= "<tr class='$oddclass'>";
778
                            } else {
779
                                $output .= "<tr class='$oddclass'>";
780
                            }
781
782
                            $scoreItem = null;
783
                            if ($row['item_type'] == 'quiz') {
784
                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
785
                                    $scoreItem .= Display::return_icon(
786
                                        'invisible.gif',
787
                                        get_lang('ResultsHiddenByExerciseSetting')
788
                                    );
789
                                } else {
790
                                    $scoreItem .= ExerciseLib::show_score($score, $maxscore, false);
791
                                }
792
                            } else {
793
                                $scoreItem .= $score == 0 ? '/' : ($maxscore == 0 ? $score : $score . '/' . $maxscore);
794
                            }
795
796
                            $output .= '
797
                                <td>'.$extend_link.'</td>
798
                                <td colspan="4">' . $title . '</td>
799
                                <td colspan="2">' . learnpathitem::humanize_status($lesson_status) .'</td>
800
                                <td colspan="2">'.$scoreItem.'</td>
801
                                <td colspan="2">'.$time.'</td>
802
                                '.$action.'
803
                             ';
804
                            $output .= '</tr>';
805
                        }
806
807
                        if (!empty($export_csv)) {
808
                            $temp = array();
809
                            $temp[] = api_html_entity_decode($title, ENT_QUOTES);
810
                            $temp[] = api_html_entity_decode($lesson_status, ENT_QUOTES);
811
812 View Code Duplication
                            if ($row['item_type'] == 'quiz') {
813
                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
814
                                    $temp[] = '/';
815
                                } else {
816
                                    $temp[] = ($score == 0 ? '0/' . $maxscore : ($maxscore == 0 ? $score : $score . '/' . float_format($maxscore, 1)));
817
                                }
818
                            } else {
819
                                $temp[] = ($score == 0 ? '/' : ($maxscore == 0 ? $score : $score . '/' . float_format($maxscore, 1)));
820
                            }
821
                            $temp[] = $time;
822
                            $csv_content[] = $temp;
823
                        }
824
                    }
825
826
                    $counter++;
827
828
                    $action = null;
829
                    if ($type == 'classic') {
830
                        $action =  '<td></td>';
831
                    }
832
833
                    if ($extend_this_attempt || $extend_all) {
834
                        $list1 = learnpath :: get_iv_interactions_array($row['iv_id']);
835
                        foreach ($list1 as $id => $interaction) {
836
                            if (($counter % 2) == 0) {
837
                                $oddclass = 'row_odd';
838
                            } else {
839
                                $oddclass = 'row_even';
840
                            }
841
                            $output .= '<tr class="'.$oddclass.'">
842
                                    <td></td>
843
                                    <td></td>
844
                                    <td></td>
845
                                    <td>'.$interaction['order_id'].'</td>
846
                                    <td>'.$interaction['id'].'</td>
847
                                    <td colspan="2">' . $interaction['type'].'</td>
848
                                    <td>'.urldecode($interaction['student_response']).'</td>
849
                                    <td>'.$interaction['result'].'</td>
850
                                    <td>'.$interaction['latency'].'</td>
851
                                    <td>'.$interaction['time'].'</td>
852
                                    '.$action.'
853
                               </tr>';
854
                            $counter++;
855
                        }
856
                        $list2 = learnpath :: get_iv_objectives_array($row['iv_id']);
857 View Code Duplication
                        foreach ($list2 as $id => $interaction) {
858
                            if (($counter % 2) == 0) {
859
                                $oddclass = 'row_odd';
860
                            } else {
861
                                $oddclass = 'row_even';
862
                            }
863
                            $output .= '<tr class="'.$oddclass.'">
864
                                    <td></td>
865
                                    <td></td>
866
                                    <td></td>
867
                                    <td>' . $interaction['order_id'] . '</td>
868
                                    <td colspan="2">'.$interaction['objective_id'] . '</td>
869
                                    <td colspan="2">' . $interaction['status'] . '</td>
870
                                    <td>' . $interaction['score_raw'].'</td>
871
                                    <td>' . $interaction['score_max'] .'</td>
872
                                    <td>' . $interaction['score_min'].'</td>
873
                                    '.$action.'
874
                               </tr>';
875
                            $counter++;
876
                        }
877
                    }
878
879
                    // Attempts listing by exercise.
880
                    if ($lp_id == $my_lp_id && $lp_item_id== $my_id && $extendedAttempt) {
881
                        // Get attempts of a exercise.
882
                        if (!empty($lp_id) &&
883
                            !empty($lp_item_id) &&
884
                            $row['item_type'] === 'quiz'
885
                        ) {
886
                            $sql = "SELECT path FROM $TBL_LP_ITEM
887
                                    WHERE
888
                                        c_id = $course_id AND
889
                                        id = '$lp_item_id' AND
890
                                        lp_id = '$lp_id'";
891
                            $res_path = Database::query($sql);
892
                            $row_path = Database::fetch_array($res_path);
893
894
                            if (Database::num_rows($res_path) > 0) {
895
                                $sql = 'SELECT * FROM ' . $tbl_stats_exercices . '
896
                                        WHERE
897
                                            exe_exo_id="' . (int) $row_path['path'] . '" AND
898
                                            status <> "incomplete" AND
899
                                            exe_user_id="' . $user_id . '" AND
900
                                            orig_lp_id = "' . (int) $lp_id . '" AND
901
                                            orig_lp_item_id = "' . (int) $lp_item_id . '" AND
902
                                            c_id = ' . $course_id . '  AND
903
                                            session_id = ' . $session_id . '
904
                                        ORDER BY exe_date';
905
                                $res_attempts = Database::query($sql);
906
                                $num_attempts = Database::num_rows($res_attempts);
907
                                if ($num_attempts > 0) {
908
                                    $n = 1;
909
                                    while ($row_attempts = Database :: fetch_array($res_attempts)) {
910
                                        $my_score = $row_attempts['exe_result'];
911
                                        $my_maxscore = $row_attempts['exe_weighting'];
912
                                        $my_exe_id = $row_attempts['exe_id'];
913
                                        $my_orig_lp = $row_attempts['orig_lp_id'];
914
                                        $my_orig_lp_item = $row_attempts['orig_lp_item_id'];
915
                                        $my_exo_exe_id = $row_attempts['exe_exo_id'];
916
                                        $mktime_start_date = api_strtotime($row_attempts['start_date'], 'UTC');
917
                                        $mktime_exe_date = api_strtotime($row_attempts['exe_date'], 'UTC');
918
                                        if ($mktime_start_date && $mktime_exe_date) {
919
                                            $mytime = ((int) $mktime_exe_date - (int) $mktime_start_date);
920
                                            $time_attemp = learnpathItem :: getScormTimeFromParameter('js', $mytime);
921
                                            $time_attemp = str_replace('NaN', '00' . $h . '00\'00"', $time_attemp);
922
                                        } else {
923
                                            $time_attemp = ' - ';
924
                                        }
925
                                        if (!$is_allowed_to_edit && $result_disabled_ext_all) {
926
                                            $view_score = Display::return_icon('invisible.gif', get_lang('ResultsHiddenByExerciseSetting'));
927
                                        } else {
928
                                            // Show only float when need it
929
                                            if ($my_score == 0) {
930
                                                $view_score = ExerciseLib::show_score(0, $my_maxscore, false);
931
                                            } else {
932
                                                if ($my_maxscore == 0) {
933
                                                    $view_score = $my_score;
934
                                                } else {
935
                                                    $view_score = ExerciseLib::show_score($my_score, $my_maxscore, false);
936
                                                }
937
                                            }
938
                                        }
939
                                        $my_lesson_status = $row_attempts['status'];
940
941
                                        if ($my_lesson_status == '') {
942
                                            $my_lesson_status = learnpathitem::humanize_status('completed');
943
                                        } elseif ($my_lesson_status == 'incomplete') {
944
                                            $my_lesson_status = learnpathitem::humanize_status('incomplete');
945
                                        }
946
947
                                        $output .= '<tr class="' . $oddclass . '" >
948
                                        <td></td>
949
                                        <td>' . $extend_attempt_link . '</td>
950
                                        <td colspan="3">' . get_lang('Attempt').' '. $n.'</td>
951
                                        <td colspan="2">' . $my_lesson_status . '</td>
952
                                        <td colspan="2">'.$view_score . '</td>
953
                                        <td colspan="2">'.$time_attemp . '</td>';
954
                                        if ($action == 'classic') {
955
                                            if ($origin != 'tracking') {
956 View Code Duplication
                                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
957
                                                    $output .= '<td>
958
                                                            <img src="' . Display::returnIconPath('quiz_na.gif').'" alt="' . get_lang('ShowAttempt') . '" title="' . get_lang('ShowAttempt') . '">
959
                                                            </td>';
960
                                                } else {
961
                                                    $output .= '<td>
962
                                                            <a href="../exercice/exercise_show.php?origin=' . $origin . '&id=' . $my_exe_id . '&cidReq=' . $courseCode . '" target="_parent">
963
                                                            <img src="' . Display::returnIconPath('quiz.gif').'" alt="' . get_lang('ShowAttempt') . '" title="' . get_lang('ShowAttempt') . '">
964
                                                            </a></td>';
965
                                                }
966 View Code Duplication
                                            } else {
967
                                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
968
                                                    $output .= '<td>
969
                                                                <img src="' . Display::returnIconPath('quiz_na.gif').'" alt="' . get_lang('ShowAndQualifyAttempt') . '" title="' . get_lang('ShowAndQualifyAttempt') . '"></td>';
970
                                                } else {
971
                                                    $output .= '<td>
972
                                                                    <a href="../exercice/exercise_show.php?cidReq=' . $courseCode . '&origin=correct_exercise_in_lp&id=' . $my_exe_id . '" target="_parent">
973
                                                                    <img src="' . Display::returnIconPath('quiz.gif').'" alt="' . get_lang('ShowAndQualifyAttempt') . '" title="' . get_lang('ShowAndQualifyAttempt') . '"></a></td>';
974
                                                }
975
                                            }
976
                                        }
977
                                        $output .= '</tr>';
978
                                        $n++;
979
                                    }
980
                                }
981
                                $output .= '<tr><td colspan="12">&nbsp;</td></tr>';
982
                            }
983
                        }
984
                    }
985
                }
986
987
                $total_time += $time_for_total;
988
                // QUIZZ IN LP
989
                $a_my_id = array();
990
                if (!empty($my_lp_id)) {
991
                    $a_my_id[] = $my_lp_id;
992
                }
993
            }
994
        }
995
996
        // NOT Extend all "left green cross"
997
        if (!empty($a_my_id)) {
998
            if ($extendedAttempt) {
999
                // "Right green cross" extended
1000
                $total_score = self::get_avg_student_score(
1001
                    $user_id,
1002
                    $course_id,
1003
                    $a_my_id,
1004
                    $session_id,
1005
                    false,
1006
                    false
1007
                );
1008
            } else {
1009
                // "Left green cross" extended
1010
                $total_score = self::get_avg_student_score(
1011
                    $user_id,
1012
                    $course_id,
1013
                    $a_my_id,
1014
                    $session_id,
1015
                    false,
1016
                    true
1017
                );
1018
            }
1019
        } else {
1020
            // Extend all "left green cross"
1021
            $total_score = self::get_avg_student_score(
1022
                $user_id,
1023
                $course_id,
1024
                array($lp_id),
1025
                $session_id,
1026
                false,
1027
                false
1028
            );
1029
        }
1030
1031
        $total_time = learnpathItem::getScormTimeFromParameter('js', $total_time);
1032
        $total_time = str_replace('NaN', '00' . $h . '00\'00"', $total_time);
1033
1034
        if (!$is_allowed_to_edit && $result_disabled_ext_all) {
1035
            $final_score = Display::return_icon('invisible.gif', get_lang('ResultsHiddenByExerciseSetting'));
1036
        } else {
1037
            if (is_numeric($total_score)) {
1038
                $final_score = $total_score . '%';
1039
            } else {
1040
                $final_score = $total_score;
1041
            }
1042
        }
1043
1044
        $progress = learnpath::getProgress($lp_id, $user_id, $course_id, $session_id);
1045
1046
        if (($counter % 2) == 0) {
1047
            $oddclass = 'row_odd';
1048
        } else {
1049
            $oddclass = 'row_even';
1050
        }
1051
1052
        $action = null;
1053
        if ($type == 'classic') {
1054
            $action =  '<td></td>';
1055
        }
1056
1057
        $output .= '<tr class="'.$oddclass.'">
1058
                <td></td>
1059
                <td colspan="4">
1060
                    <i>' . get_lang('AccomplishedStepsTotal') .'</i>
1061
                </td>
1062
                <td colspan="2">'.$progress.'%</td>
1063
                <td colspan="2">
1064
                    ' . $final_score.'
1065
                </td>
1066
                <td colspan="2">' . $total_time . '</div>
1067
                '.$action.'
1068
           </tr>';
1069
1070
        $output .= '
1071
                    </tbody>
1072
                </table>
1073
            </div>
1074
        ';
1075
1076
        if (!empty($export_csv)) {
1077
            $temp = array(
1078
                '',
1079
                '',
1080
                '',
1081
                ''
1082
            );
1083
            $csv_content[] = $temp;
1084
            $temp = array(
1085
                get_lang('AccomplishedStepsTotal'),
1086
                '',
1087
                $final_score,
1088
                $total_time
1089
            );
1090
            $csv_content[] = $temp;
1091
            ob_end_clean();
1092
            Export :: arrayToCsv($csv_content, 'reporting_learning_path_details');
1093
            exit;
1094
        }
1095
        return $output;
1096
    }
1097
1098
    /**
1099
     * @param int $userId
1100
     *
1101
     * @return array
1102
     */
1103
    public static function getStats($userId)
1104
    {
1105
        $courses = array();
1106
        $assignedCourses = array();
1107
        if (api_is_drh() && api_drh_can_access_all_session_content()) {
1108
            $studentList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1109
                'drh_all',
1110
                $userId,
1111
                false,
1112
                null,
1113
                null,
1114
                null,
1115
                null,
1116
                null,
1117
                null,
1118
                null,
1119
                array(),
1120
                array(),
1121
                STUDENT
1122
            );
1123
            $students = array();
1124
            foreach ($studentList as $studentData) {
0 ignored issues
show
Bug introduced by
The expression $studentList 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...
1125
                $students[] = $studentData['user_id'];
1126
            }
1127
1128
            $teacherList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1129
                'drh_all',
1130
                $userId,
1131
                false,
1132
                null,
1133
                null,
1134
                null,
1135
                null,
1136
                null,
1137
                null,
1138
                null,
1139
                array(),
1140
                array(),
1141
                COURSEMANAGER
1142
            );
1143
            $teachers = array();
1144
            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...
1145
                $teachers[] = $teacherData['user_id'];
1146
            }
1147
1148
            $humanResources = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1149
                'drh_all',
1150
                $userId,
1151
                false,
1152
                null,
1153
                null,
1154
                null,
1155
                null,
1156
                null,
1157
                null,
1158
                null,
1159
                array(),
1160
                array(),
1161
                DRH
1162
            );
1163
1164
            $humanResourcesList = array();
1165
            foreach ($humanResources as $item) {
0 ignored issues
show
Bug introduced by
The expression $humanResources 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...
1166
                $humanResourcesList[] = $item['user_id'];
1167
            }
1168
1169
            $platformCourses = SessionManager::getAllCoursesFollowedByUser(
1170
                $userId,
1171
                null,
1172
                null,
1173
                null,
1174
                null,
1175
                null
1176
            );
1177
            foreach ($platformCourses as $course) {
1178
                $courses[$course['code']] = $course['code'];
1179
            }
1180
            $sessions = SessionManager::get_sessions_followed_by_drh($userId);
1181
        } else {
1182
1183
            $studentList = UserManager::getUsersFollowedByUser(
1184
                $userId,
1185
                STUDENT,
1186
                false,
1187
                false,
1188
                false,
1189
                null,
1190
                null,
1191
                null,
1192
                null,
1193
                null,
1194
                null,
1195
                COURSEMANAGER
1196
            );
1197
1198
            $students = array();
1199
            foreach ($studentList as $studentData) {
1200
                $students[] = $studentData['user_id'];
1201
            }
1202
1203
            $teacherList = UserManager::getUsersFollowedByUser(
1204
                $userId,
1205
                COURSEMANAGER,
1206
                false,
1207
                false,
1208
                false,
1209
                null,
1210
                null,
1211
                null,
1212
                null,
1213
                null,
1214
                null,
1215
                COURSEMANAGER
1216
            );
1217
1218
            $teachers = array();
1219
            foreach ($teacherList as $teacherData) {
1220
                $teachers[] = $teacherData['user_id'];
1221
            }
1222
1223
            $humanResources = UserManager::getUsersFollowedByUser(
1224
                $userId,
1225
                DRH,
1226
                false,
1227
                false,
1228
                false,
1229
                null,
1230
                null,
1231
                null,
1232
                null,
1233
                null,
1234
                null,
1235
                COURSEMANAGER
1236
            );
1237
1238
            $humanResourcesList = array();
1239
            foreach ($humanResources as $item) {
1240
                $humanResourcesList[] = $item['user_id'];
1241
            }
1242
1243
            $platformCourses = CourseManager::getCoursesFollowedByUser(
1244
                $userId,
1245
                COURSEMANAGER,
1246
                null,
1247
                null,
1248
                null,
1249
                null,
1250
                false,
1251
                null,
1252
                null,
1253
                true
1254
            );
1255
1256
            foreach ($platformCourses as $course) {
1257
                $assignedCourses[$course['code']] = $course['code'];
1258
            }
1259
1260
            $platformCourses = CourseManager::getCoursesFollowedByUser(
1261
                $userId,
1262
                COURSEMANAGER
1263
            );
1264
            foreach ($platformCourses as $course) {
1265
                $courses[$course['code']] = $course['code'];
1266
            }
1267
1268
            $sessions = SessionManager::getSessionsFollowedByUser(
1269
                $userId,
1270
                COURSEMANAGER
1271
            );
1272
        }
1273
1274
        return array(
1275
            'drh' => $humanResourcesList,
1276
            'teachers' => $teachers,
1277
            'students' => $students,
1278
            'courses' => $courses,
1279
            'sessions' => $sessions,
1280
            'assignedCourses' => $assignedCourses
1281
        );
1282
    }
1283
1284
    /**
1285
     * Calculates the time spent on the platform by a user
1286
     * @param   int|array User id
1287
     * @param   string type of time filter: 'last_week' or 'custom'
1288
     * @param   string  start date date('Y-m-d H:i:s')
1289
     * @param   string  end date date('Y-m-d H:i:s')
1290
     * @return timestamp $nb_seconds
1291
     */
1292
    public static function get_time_spent_on_the_platform(
1293
        $userId,
1294
        $timeFilter = 'last_7_days',
1295
        $start_date = null,
1296
        $end_date = null
1297
    ) {
1298
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1299
        $condition_time = '';
1300
1301
        if (is_array($userId)) {
1302
            $userList = array_map('intval', $userId);
1303
            $userCondition = " login_user_id IN ('".implode("','", $userList)."')";
1304
        } else {
1305
            $userCondition = " login_user_id = ".intval($userId);
1306
        }
1307
1308
        if (empty($timeFilter)) {
1309
            $timeFilter = 'last_week';
1310
        }
1311
1312
        $today = date('Y-m-d H:i:s');
1313
1314
        switch ($timeFilter) {
1315 View Code Duplication
            case 'last_7_days':
1316
                $new_date = date('Y-m-d H:i:s', strtotime('-7 day'));
1317
                $condition_time = ' AND (login_date >= "'.$new_date.'" AND logout_date <= "'.$today.'") ';
1318
                break;
1319 View Code Duplication
            case 'last_30_days':
1320
                $new_date = date('Y-m-d H:i:s', strtotime('-30 day'));
1321
                $condition_time = ' AND (login_date >= "'.$new_date.'" AND logout_date <= "'.$today.'") ';
1322
               break;
1323
            case 'custom':
1324
                if (!empty($start_date) && !empty($end_date)) {
1325
                    $start_date = Database::escape_string($start_date);
1326
                    $end_date = Database::escape_string($end_date);
1327
                    $condition_time = ' AND (login_date >= "'.$start_date.'" AND logout_date <= "'.$end_date.'" ) ';
1328
                }
1329
                break;
1330
        }
1331
1332
    	$sql = 'SELECT SUM(TIMESTAMPDIFF(SECOND, login_date, logout_date)) diff
1333
    	        FROM '.$tbl_track_login.'
1334
                WHERE '.$userCondition.$condition_time;
1335
    	$rs = Database::query($sql);
1336
        $row = Database::fetch_array($rs, 'ASSOC');
1337
        $diff = $row['diff'];
1338
1339
        if ($diff >= 0) {
1340
            return $diff;
1341
        } else {
1342
            return -1;
1343
        }
1344
    }
1345
1346
    /**
1347
     * Calculates the time spent on the course
1348
     * @param integer $user_id
1349
     * @param integer  $courseId
1350
     * @param int Session id (optional)
1351
     *
1352
     * @return int Time in seconds
1353
     */
1354
    public static function get_time_spent_on_the_course($user_id, $courseId, $session_id = 0)
1355
    {
1356
        $courseId = intval($courseId);
1357
    	$session_id  = intval($session_id);
1358
1359
    	$tbl_track_course = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1360
    	if (is_array($user_id)) {
1361
    	    $user_id = array_map('intval', $user_id);
1362
    		$condition_user = " AND user_id IN (".implode(',',$user_id).") ";
1363
    	} else {
1364
    		$user_id = intval($user_id);
1365
    		$condition_user = " AND user_id = $user_id ";
1366
    	}
1367
1368
    	$sql = "SELECT
1369
    	        SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as nb_seconds
1370
                FROM $tbl_track_course
1371
                WHERE UNIX_TIMESTAMP(logout_course_date) > UNIX_TIMESTAMP(login_course_date) ";
1372
1373
        if ($courseId != 0) {
1374
            $sql .= "AND c_id = '$courseId' ";
1375
        }
1376
1377
        if ($session_id != -1) {
1378
            $sql .= "AND session_id = '$session_id' ";
1379
        }
1380
1381
        $sql .= $condition_user;
1382
1383
        $rs = Database::query($sql);
1384
    	$row = Database::fetch_array($rs);
1385
1386
    	return $row['nb_seconds'];
1387
    }
1388
1389
    /**
1390
     * Get first connection date for a student
1391
     * @param    int $student_id
1392
     *
1393
     * @return    string|bool Date format long without day or false if there are no connections
1394
     */
1395 View Code Duplication
    public static function get_first_connection_date($student_id)
1396
    {
1397
    	$tbl_track_login = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1398
    	$sql = 'SELECT login_date
1399
    	        FROM ' . $tbl_track_login . '
1400
                WHERE login_user_id = ' . intval($student_id) . '
1401
                ORDER BY login_date ASC
1402
                LIMIT 0,1';
1403
1404
    	$rs = Database::query($sql);
1405
    	if (Database::num_rows($rs)>0) {
1406
    		if ($first_login_date = Database::result($rs, 0, 0)) {
1407
                return api_convert_and_format_date(
1408
                    $first_login_date,
1409
                    DATE_FORMAT_SHORT,
1410
                    date_default_timezone_get()
1411
                );
1412
    		}
1413
    	}
1414
1415
    	return false;
1416
    }
1417
1418
    /**
1419
     * Get las connection date for a student
1420
     * @param int $student_id
1421
     * @param bool $warning_message Show a warning message (optional)
1422
     * @param bool $return_timestamp True for returning results in timestamp (optional)
1423
     * @return string|int|bool Date format long without day, false if there are no connections or
1424
     * timestamp if parameter $return_timestamp is true
1425
     */
1426
    public static function get_last_connection_date($student_id, $warning_message = false, $return_timestamp = false)
1427
    {
1428
    	$table = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1429
    	$sql = 'SELECT login_date
1430
    	        FROM ' . $table . '
1431
                WHERE login_user_id = ' . intval($student_id) . '
1432
                ORDER BY login_date
1433
                DESC LIMIT 0,1';
1434
1435
    	$rs = Database::query($sql);
1436
    	if (Database::num_rows($rs) > 0) {
1437
    		if ($last_login_date = Database::result($rs, 0, 0)) {
1438
    			$last_login_date = api_get_local_time($last_login_date);
1439
    			if ($return_timestamp) {
1440
    				return api_strtotime($last_login_date,'UTC');
1441
    			} else {
1442
    				if (!$warning_message) {
1443
    					return api_format_date($last_login_date, DATE_FORMAT_SHORT);
1444
    				} else {
1445
    					$timestamp = api_strtotime($last_login_date,'UTC');
1446
    					$currentTimestamp = time();
1447
1448
    					//If the last connection is > than 7 days, the text is red
1449
    					//345600 = 7 days in seconds
1450
    					if ($currentTimestamp - $timestamp > 604800) {
1451
    						return '<span style="color: #F00;">' . api_format_date($last_login_date, DATE_FORMAT_SHORT) . '</span>';
1452
    					} else {
1453
    						return api_format_date($last_login_date, DATE_FORMAT_SHORT);
1454
    					}
1455
    				}
1456
    			}
1457
    		}
1458
    	}
1459
    	return false;
1460
    }
1461
1462
    /**
1463
     * Get las connection date for a student
1464
     * @param array $studentList Student id array
1465
     * @param int $days
1466
     * @param bool $getCount
1467
     * @return int
1468
     */
1469
    public static function getInactiveUsers($studentList, $days, $getCount = true)
1470
    {
1471
        if (empty($studentList)) {
1472
            return 0;
1473
        }
1474
        $days = intval($days);
1475
        $date = api_get_utc_datetime(strtotime($days.' days ago'));
1476
        $studentList = array_map('intval', $studentList);
1477
1478
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1479
        $select = " SELECT login_user_id ";
1480
        if ($getCount) {
1481
            $select = " SELECT count(DISTINCT login_user_id) as count";
1482
        }
1483
        $sql = "$select
1484
                FROM $tbl_track_login
1485
                WHERE
1486
                    login_user_id IN (' ". implode("','", $studentList) . "' ) AND
1487
                    login_date < '$date'
1488
                ";
1489
        $rs = Database::query($sql);
1490 View Code Duplication
        if (Database::num_rows($rs) > 0) {
1491
            if ($getCount) {
1492
                $count = Database::fetch_array($rs);
1493
                return $count['count'];
1494
            }
1495
            return Database::store_result($rs, 'ASSOC');
1496
        }
1497
        return false;
1498
    }
1499
1500
    /**
1501
     * Get first user's connection date on the course
1502
     * @param     int         User id
1503
     * @param    int        $courseId
1504
     * @param    int            Session id (optional, default=0)
1505
     * @return    string|bool    Date with format long without day or false if there is no date
1506
     */
1507
    public static function get_first_connection_date_on_the_course(
1508
        $student_id,
1509
        $courseId,
1510
        $session_id = 0,
1511
        $convert_date = true
1512
    ) {
1513
    	$student_id  = intval($student_id);
1514
        $courseId = intval($courseId);
1515
    	$session_id  = intval($session_id);
1516
1517
    	$tbl_track_login = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1518
    	$sql = 'SELECT login_course_date
1519
    	        FROM '.$tbl_track_login.'
1520
                WHERE
1521
                    user_id = '.$student_id.' AND
1522
                    c_id = '.$courseId.' AND
1523
                    session_id = '.$session_id.'
1524
                ORDER BY login_course_date ASC LIMIT 0,1';
1525
    	$rs = Database::query($sql);
1526
    	if (Database::num_rows($rs) > 0) {
1527
    		if ($first_login_date = Database::result($rs, 0, 0)) {
1528
    			if ($convert_date) {
1529
    				return api_convert_and_format_date($first_login_date, DATE_FORMAT_SHORT);
1530
    			} else {
1531
    				return $first_login_date;
1532
    			}
1533
    		}
1534
    	}
1535
1536
    	return false;
1537
    }
1538
1539
    /**
1540
     * Get last user's connection date on the course
1541
     * @param     int         User id
1542
     * @param    array        $courseInfo real_id and code are used
1543
     * @param    int            Session id (optional, default=0)
1544
     * @return    string|bool    Date with format long without day or false if there is no date
1545
     */
1546
    public static function get_last_connection_date_on_the_course(
1547
        $student_id,
1548
        $courseInfo,
1549
        $session_id = 0,
1550
        $convert_date = true
1551
    ) {
1552
    	// protect data
1553
    	$student_id  = intval($student_id);
1554
        $courseId = $courseInfo['real_id'];
1555
    	$session_id  = intval($session_id);
1556
1557
    	$tbl_track_e_access = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
1558
    	$sql = 'SELECT access_date
1559
                FROM '.$tbl_track_e_access.'
1560
                WHERE   access_user_id = '.$student_id.' AND
1561
                        c_id = "'.$courseId.'" AND
1562
                        access_session_id = '.$session_id.'
1563
                ORDER BY access_date DESC
1564
                LIMIT 0,1';
1565
1566
    	$rs = Database::query($sql);
1567
    	if (Database::num_rows($rs) > 0) {
1568
    		if ($last_login_date = Database::result($rs, 0, 0)) {
1569
                if (empty($last_login_date) || $last_login_date == '0000-00-00 00:00:00') {
1570
                    return false;
1571
                }
1572
                //see #5736
1573
                $last_login_date_timestamp = api_strtotime($last_login_date);
1574
    			$now = time();
1575
    			//If the last connection is > than 7 days, the text is red
1576
    			//345600 = 7 days in seconds
1577
    			if ($now - $last_login_date_timestamp > 604800) {
1578
    				if ($convert_date) {
1579
                        $last_login_date = api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
1580
                        $icon = api_is_allowed_to_edit() ?
1581
                            '<a href="'.api_get_path(REL_CODE_PATH).'announcements/announcements.php?action=add&remind_inactive='.$student_id.'&cidReq='.$courseInfo['code'].'" title="'.get_lang('RemindInactiveUser').'">
1582
                              '.Display::return_icon('messagebox_warning.gif').'
1583
                             </a>'
1584
                            : null;
1585
    					return $icon. Display::label($last_login_date, 'warning');
1586
    				} else {
1587
    					return $last_login_date;
1588
    				}
1589
    			} else {
1590
    				if ($convert_date) {
1591
    					return api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
1592
    				} else {
1593
    					return $last_login_date;
1594
    				}
1595
    			}
1596
    		}
1597
    	}
1598
    	return false;
1599
    }
1600
1601
    /**
1602
     * Get count of the connections to the course during a specified period
1603
     * @param   int  $courseId
1604
     * @param   int     Session id (optional)
1605
     * @param   int     Datetime from which to collect data (defaults to 0)
1606
     * @param   int     Datetime to which to collect data (defaults to now)
1607
     * @return  int     count connections
1608
     */
1609
    public static function get_course_connections_count($courseId, $session_id = 0, $start = 0, $stop = null)
1610
    {
1611
    	if ($start < 0) {
1612
    		$start = 0;
1613
    	}
1614
    	if (!isset($stop) or ($stop < 0)) {
1615
    		$stop = api_get_utc_datetime();
1616
    	}
1617
1618
        $start = Database::escape_string($start);
1619
        $stop = Database::escape_string($stop);
1620
1621
    	$month_filter = " AND login_course_date > '$start' AND login_course_date < '$stop' ";
1622
1623
        $courseId = intval($courseId);
1624
    	$session_id  = intval($session_id);
1625
    	$count = 0;
1626
1627
    	$tbl_track_e_course_access = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1628
    	$sql = "SELECT count(*) as count_connections
1629
                FROM $tbl_track_e_course_access
1630
                WHERE
1631
                    c_id = $courseId AND
1632
                    session_id = $session_id
1633
                    $month_filter";
1634
    	$rs = Database::query($sql);
1635
    	if (Database::num_rows($rs)>0) {
1636
    		$row = Database::fetch_object($rs);
1637
    		$count = $row->count_connections;
1638
    	}
1639
1640
    	return $count;
1641
    }
1642
1643
    /**
1644
     * Get count courses per student
1645
     * @param     int        Student id
1646
     * @param    bool    Include sessions (optional)
1647
     * @return  int        count courses
1648
     */
1649
    public static function count_course_per_student($user_id, $include_sessions = true)
1650
    {
1651
    	$user_id = intval($user_id);
1652
    	$tbl_course_rel_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
1653
    	$tbl_session_course_rel_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1654
1655
    	$sql = 'SELECT DISTINCT c_id
1656
                FROM ' . $tbl_course_rel_user . '
1657
                WHERE user_id = ' . $user_id.' AND relation_type<>'.COURSE_RELATION_TYPE_RRHH;
1658
    	$rs = Database::query($sql);
1659
    	$nb_courses = Database::num_rows($rs);
1660
1661
    	if ($include_sessions) {
1662
    		$sql = 'SELECT DISTINCT c_id
1663
                    FROM ' . $tbl_session_course_rel_user . '
1664
                    WHERE user_id = ' . $user_id;
1665
    		$rs = Database::query($sql);
1666
    		$nb_courses += Database::num_rows($rs);
1667
    	}
1668
1669
    	return $nb_courses;
1670
    }
1671
1672
    /**
1673
     * Gets the score average from all tests in a course by student
1674
     *
1675
     * @param $student_id
1676
     * @param $course_code
1677
     * @param int $exercise_id
1678
     * @param null $session_id
1679
     * @param int $active_filter    2 for consider all tests
1680
     *                              1 for active <> -1
1681
     *                              0 for active <> 0
1682
     * @param int $into_lp  1 for all exercises
1683
     *                      0 for without LP
1684
     * @internal param \Student $mixed id
1685
     * @internal param \Course $string code
1686
     * @internal param \Exercise $int id (optional), filtered by exercise
1687
     * @internal param \Session $int id (optional), if param $session_id is null
1688
     * it'll return results including sessions, 0 = session is not filtered
1689
     * @return   string    value (number %) Which represents a round integer about the score average.
1690
     */
1691
    public static function get_avg_student_exercise_score(
1692
        $student_id,
1693
        $course_code,
1694
        $exercise_id = 0,
1695
        $session_id = null,
1696
        $active_filter = 1,
1697
        $into_lp = 0
1698
    ) {
1699
        $course_code = Database::escape_string($course_code);
1700
    	$course_info = api_get_course_info($course_code);
1701
    	if (!empty($course_info)) {
1702
    		// table definition
1703
    		$tbl_course_quiz     = Database::get_course_table(TABLE_QUIZ_TEST);
1704
    		$tbl_stats_exercise  = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1705
1706
    		// Compose a filter based on optional exercise given
1707
    		$condition_quiz = "";
1708
    		if (!empty($exercise_id)) {
1709
    			$exercise_id = intval($exercise_id);
1710
    			$condition_quiz =" AND id = $exercise_id ";
1711
    		}
1712
1713
    		// Compose a filter based on optional session id given
1714
    		$condition_session = "";
1715
    		if (isset($session_id)) {
1716
    			$session_id = intval($session_id);
1717
    			$condition_session = " AND session_id = $session_id ";
1718
    		}
1719
            if ($active_filter == 1) {
1720
                $condition_active = 'AND active <> -1';
1721
            } elseif ($active_filter == 0) {
1722
                $condition_active = 'AND active <> 0';
1723
            } else {
1724
                $condition_active = '';
1725
            }
1726
            $condition_into_lp = '';
1727
            $select_lp_id = '';
1728
            if ($into_lp == 0) {
1729
                $condition_into_lp = 'AND orig_lp_id = 0 AND orig_lp_item_id = 0';
1730
            } else {
1731
                $select_lp_id = ', orig_lp_id as lp_id ';
1732
            }
1733
1734
    		$sql = "SELECT count(id) FROM $tbl_course_quiz
1735
    				WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz ";
1736
    		$count_quiz = Database::fetch_row(Database::query($sql));
0 ignored issues
show
Bug introduced by
It seems like \Database::query($sql) can be null; however, fetch_row() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1737
1738
    		if (!empty($count_quiz[0]) && !empty($student_id)) {
1739
    			if (is_array($student_id)) {
1740
                    $student_id = array_map('intval', $student_id);
1741
    				$condition_user = " AND exe_user_id IN (".implode(',', $student_id).") ";
1742
    			} else {
1743
                    $student_id = intval($student_id);
1744
    				$condition_user = " AND exe_user_id = '$student_id' ";
1745
    			}
1746
1747 View Code Duplication
    			if (empty($exercise_id)) {
1748
    				$sql = "SELECT id FROM $tbl_course_quiz
1749
    						WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz";
1750
                    $result = Database::query($sql);
1751
                    $exercise_list = array();
1752
    				$exercise_id = null;
1753
                    if (Database::num_rows($result)) {
1754
                        while ($row = Database::fetch_array($result)) {
1755
                            $exercise_list[] = $row['id'];
1756
                        }
1757
                    }
1758
                    if (!empty($exercise_list)) {
1759
                        $exercise_id = implode("','",$exercise_list);
1760
                    }
1761
    			}
1762
1763
    			$count_quiz = Database::fetch_row(Database::query($sql));
0 ignored issues
show
Bug introduced by
It seems like \Database::query($sql) can be null; however, fetch_row() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1764
1765
    			$sql = "SELECT
1766
    			        SUM(exe_result/exe_weighting*100) as avg_score,
1767
    			        COUNT(*) as num_attempts
1768
    			        $select_lp_id
1769
                        FROM $tbl_stats_exercise
1770
                        WHERE
1771
                            exe_exo_id IN ('".$exercise_id."')
1772
                            $condition_user AND
1773
                            status = '' AND
1774
                            c_id = {$course_info['real_id']}
1775
                            $condition_session
1776
                            $condition_into_lp
1777
                        ORDER BY exe_date DESC";
1778
1779
    			$res = Database::query($sql);
1780
    			$row = Database::fetch_array($res);
1781
    			$quiz_avg_score = null;
1782
1783
    			if (!empty($row['avg_score'])) {
1784
    				$quiz_avg_score = round($row['avg_score'],2);
1785
    			}
1786
1787
    			if(!empty($row['num_attempts'])) {
1788
    				$quiz_avg_score = round($quiz_avg_score / $row['num_attempts'], 2);
1789
    			}
1790
    			if (is_array($student_id)) {
1791
    				$quiz_avg_score = round($quiz_avg_score / count($student_id), 2);
1792
    			}
1793
                if ($into_lp == 0) {
1794
                    return $quiz_avg_score;
1795
                } else {
1796
                    if (!empty($row['lp_id'])) {
1797
                        $tbl_lp = Database::get_course_table(TABLE_LP_MAIN);
1798
                        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
1799
                        $sql = "SELECT lp.name
1800
                                FROM $tbl_lp as lp, $tbl_course as c
1801
                                WHERE
1802
                                    c.code = '$course_code' AND
1803
                                    lp.id = ".$row['lp_id']." AND
1804
                                    lp.c_id = c.id
1805
                                LIMIT 1;
1806
                        ";
1807
                        $result = Database::query($sql);
1808
                        $row_lp = Database::fetch_row($result);
1809
                        $lp_name = $row_lp[0];
1810
                        return array($quiz_avg_score, $lp_name);
1811
                    } else {
1812
                        return array($quiz_avg_score, null);
1813
                    }
1814
                }
1815
    		}
1816
    	}
1817
    	return null;
1818
    }
1819
1820
    /**
1821
     * Get count student's exercise COMPLETED attempts
1822
     * @param int $student_id
1823
     * @param int $courseId
1824
     * @param int $exercise_id
1825
     * @param int $lp_id
1826
     * @param int $lp_item_id
1827
     * @param int $session_id
1828
     * @param int $find_all_lp  0 = just LP specified
1829
     *                          1 = LP specified or whitout LP,
1830
     *                          2 = all rows
1831
     * @internal param \Student $int id
1832
     * @internal param \Course $string code
1833
     * @internal param \Exercise $int id
1834
     * @internal param \Learning $int path id (optional),
1835
     * for showing attempts inside a learning path $lp_id and $lp_item_id params are required.
1836
     * @internal param \Learning $int path item id (optional),
1837
     * for showing attempts inside a learning path $lp_id and $lp_item_id params are required.
1838
     * @return  int     count of attempts
1839
     */
1840
    public static function count_student_exercise_attempts(
1841
        $student_id,
1842
        $courseId,
1843
        $exercise_id,
1844
        $lp_id = 0,
1845
        $lp_item_id = 0,
1846
        $session_id = 0,
1847
        $find_all_lp = 0
1848
    ) {
1849
        $courseId = intval($courseId);
1850
    	$student_id  = intval($student_id);
1851
    	$exercise_id = intval($exercise_id);
1852
    	$session_id  = intval($session_id);
1853
1854
    	$lp_id = intval($lp_id);
1855
        $lp_item_id = intval($lp_item_id);
1856
    	$tbl_stats_exercises = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1857
1858
    	$sql = "SELECT COUNT(ex.exe_id) as essais FROM $tbl_stats_exercises AS ex
1859
                WHERE  ex.c_id = $courseId
1860
                AND ex.exe_exo_id = $exercise_id
1861
                AND status = ''
1862
                AND exe_user_id= $student_id
1863
                AND session_id = $session_id ";
1864
1865
        if ($find_all_lp == 1) {
1866
            $sql .= "AND (orig_lp_id = $lp_id OR orig_lp_id = 0)
1867
                AND (orig_lp_item_id = $lp_item_id OR orig_lp_item_id = 0)";
1868
        } elseif ($find_all_lp == 0) {
1869
            $sql .= "AND orig_lp_id = $lp_id
1870
                AND orig_lp_item_id = $lp_item_id";
1871
        }
1872
1873
    	$rs = Database::query($sql);
1874
    	$row = Database::fetch_row($rs);
1875
    	$count_attempts = $row[0];
1876
1877
    	return $count_attempts;
1878
    }
1879
1880
    /**
1881
     * Get count student's exercise progress
1882
     *
1883
     * @param array  $exercise_list
1884
     * @param int    $user_id
1885
     * @param int    $courseId
1886
     * @param int    $session_id
1887
    */
1888
    public static function get_exercise_student_progress($exercise_list, $user_id, $courseId, $session_id)
1889
    {
1890
        $courseId = intval($courseId);
1891
        $user_id = intval($user_id);
1892
        $session_id = intval($session_id);
1893
1894
        if (empty($exercise_list)) {
1895
            return '0%';
1896
        }
1897
        $tbl_stats_exercises = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1898
        $exercise_list = array_keys($exercise_list);
1899
        $exercise_list = array_map('intval', $exercise_list);
1900
1901
        $exercise_list_imploded = implode("' ,'", $exercise_list);
1902
1903
        $sql = "SELECT COUNT(DISTINCT ex.exe_exo_id)
1904
                FROM $tbl_stats_exercises AS ex
1905
                WHERE
1906
                    ex.c_id = $courseId AND
1907
                    ex.session_id  = $session_id AND
1908
                    ex.exe_user_id = $user_id AND
1909
                    ex.exe_exo_id IN ('$exercise_list_imploded') ";
1910
1911
        $rs = Database::query($sql);
1912
        $count = 0;
1913
        if ($rs) {
1914
            $row = Database::fetch_row($rs);
1915
            $count = $row[0];
1916
        }
1917
        $count = ($count != 0 ) ? 100*round(intval($count)/count($exercise_list), 2) .'%' : '0%';
1918
        return $count;
1919
    }
1920
1921
    /**
1922
     * @param array $exercise_list
1923
     * @param int $user_id
1924
     * @param int $courseId
1925
     * @param int $session_id
1926
     * @return string
1927
     */
1928 View Code Duplication
    public static function get_exercise_student_average_best_attempt($exercise_list, $user_id, $courseId, $session_id)
1929
    {
1930
        $result = 0;
1931
        if (!empty($exercise_list)) {
1932
            foreach ($exercise_list as $exercise_data) {
1933
                $exercise_id = $exercise_data['id'];
1934
                $best_attempt = Event::get_best_attempt_exercise_results_per_user(
1935
                    $user_id,
1936
                    $exercise_id,
1937
                    $courseId,
1938
                    $session_id
1939
                );
1940
1941
                if (!empty($best_attempt) && !empty($best_attempt['exe_weighting'])) {
1942
                    $result += $best_attempt['exe_result']/$best_attempt['exe_weighting'];
1943
                }
1944
            }
1945
            $result = $result / count($exercise_list);
1946
            $result = round($result, 2) * 100;
1947
        }
1948
1949
        return $result.'%';
1950
    }
1951
1952
    /**
1953
     * get teacher progress by course and session
1954
     * @param int course id
1955
     * @param int session id
1956
     * @return array
1957
     */
1958
    static function get_teachers_progress_by_course($courseId, $sessionId)
1959
    {
1960
        $course = api_get_course_info_by_id($courseId);
1961
        $sessionId = intval($sessionId);
1962
        $courseId = intval($courseId);
1963
1964
        $sessionCourseUserTable = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1965
        $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
1966
1967
        //get teachers
1968
        $sql = "SELECT scu.session_id, scu.user_id, s.name
1969
                FROM $sessionCourseUserTable scu, $sessionTable s
1970
                WHERE
1971
                    scu.session_id = s.id
1972
                    AND scu.status = 2
1973
                    AND scu.visibility = 1
1974
                    AND scu.c_id = '%s'
1975
                    AND scu.session_id = %s";
1976
        $query = sprintf($sql, intval($courseId), $sessionId);
1977
        $rs = Database::query($query);
1978
        $teachers = array();
1979
        while ($teacher = Database::fetch_array($rs,'ASSOC')) {
1980
            $teachers[] = $teacher;
1981
        }
1982
        $data = array();
1983
        foreach ($teachers as $teacher) {
1984
            //total documents added
1985
            $sql = "SELECT count(*) as total
1986
                    FROM c_item_property
1987
                    WHERE lastedit_type = 'DocumentAdded'
1988
                    AND c_id = %s
1989
                    AND insert_user_id = %s
1990
                    AND session_id = %s";
1991
            $query = sprintf($sql,
1992
                $courseId,
1993
                $teacher['user_id'],
1994
                $teacher['session_id']
1995
            );
1996
1997
            $rs = Database::query($query);
1998
            $totalDocuments = 0;
1999
            if ($rs) {
2000
                $row = Database::fetch_row($rs);
2001
                $totalDocuments = $row[0];
2002
            }
2003
            //total links added
2004
            $sql = "SELECT count(*) as total
2005
                    FROM c_item_property
2006
                    WHERE lastedit_type = 'LinkAdded'
2007
                    AND c_id = %s
2008
                    AND insert_user_id = %s
2009
                    AND session_id = %s";
2010
            $query = sprintf($sql,
2011
                $courseId,
2012
                $teacher['user_id'],
2013
                $teacher['session_id']
2014
            );
2015
            $rs = Database::query($query);
2016
2017
            $totalLinks = 0;
2018
            if ($rs) {
2019
                $row = Database::fetch_row($rs);
2020
                $totalLinks = $row[0];
2021
            }
2022
            //total forums added
2023
            $sql = "SELECT count(*) as total
2024
                    FROM c_item_property
2025
                    WHERE lastedit_type = 'ForumthreadVisible'
2026
                    AND c_id = %s
2027
                    AND insert_user_id = %s
2028
                    AND session_id = %s";
2029
            $query = sprintf($sql,
2030
                $courseId,
2031
                $teacher['user_id'],
2032
                $teacher['session_id']
2033
            );
2034
            $rs = Database::query($query);
2035
2036
            $totalForums = 0;
2037
            if ($rs) {
2038
                $row = Database::fetch_row($rs);
2039
                $totalForums = $row[0];
2040
            }
2041
            //total wikis added
2042
            $sql = "SELECT COUNT(DISTINCT(ref)) as total
2043
                    FROM c_item_property
2044
                    WHERE lastedit_type = 'WikiAdded'
2045
                    AND c_id = %s
2046
                    AND insert_user_id = %s
2047
                    AND session_id = %s";
2048
            $query = sprintf($sql,
2049
                $courseId,
2050
                $teacher['user_id'],
2051
                $teacher['session_id']
2052
            );
2053
            $rs = Database::query($query);
2054
2055
            $totalWikis = 0;
2056
            if ($rs) {
2057
                $row = Database::fetch_row($rs);
2058
                $totalWikis = $row[0];
2059
            }
2060
            //total works added
2061
            $sql = "SELECT COUNT(*) as total
2062
                    FROM c_item_property
2063
                    WHERE lastedit_type = 'DirectoryCreated'
2064
                    AND tool = 'work'
2065
                    AND c_id = %s
2066
                    AND insert_user_id = %s
2067
                    AND session_id = %s";
2068
            $query = sprintf($sql,
2069
                $courseId,
2070
                $teacher['user_id'],
2071
                $teacher['session_id']
2072
            );
2073
            $rs = Database::query($query);
2074
2075
            $totalWorks = 0;
2076
            if ($rs) {
2077
                $row = Database::fetch_row($rs);
2078
                $totalWorks = $row[0];
2079
            }
2080
            //total announcements added
2081
            $sql = "SELECT COUNT(*) as total
2082
                    FROM c_item_property
2083
                    WHERE lastedit_type = 'AnnouncementAdded'
2084
                    AND c_id = %s
2085
                    AND insert_user_id = %s
2086
                    AND session_id = %s";
2087
            $query = sprintf($sql,
2088
                $courseId,
2089
                $teacher['user_id'],
2090
                $teacher['session_id']
2091
            );
2092
            $rs = Database::query($query);
2093
2094
            $totalAnnouncements = 0;
2095
            if ($rs) {
2096
                $row = Database::fetch_row($rs);
2097
                $totalAnnouncements = $row[0];
2098
            }
2099
            $tutor = api_get_user_info($teacher['user_id']);
2100
            $data[] = array(
2101
                'course' => $course['title'],
2102
                'session' => $teacher['name'],
2103
                'tutor' => $tutor['username'] . ' - ' . $tutor['lastname'] . ' ' . $tutor['firstname'],
2104
                'documents' => $totalDocuments,
2105
                'links' => $totalLinks,
2106
                'forums' => $totalForums,
2107
                'works' => $totalWorks,
2108
                'wikis' => $totalWikis,
2109
                'announcements' => $totalAnnouncements,
2110
            );
2111
        }
2112
2113
        return $data;
2114
    }
2115
2116
    /**
2117
     * Returns the average student progress in the learning paths of the given
2118
     * course.
2119
     * @param int|array $studentId
2120
     * @param string    $courseCode
2121
     * @param array     $lpIdList Limit average to listed lp ids
2122
     * @param int       $sessionId     Session id (optional),
2123
     * if parameter $session_id is null(default) it'll return results including
2124
     * sessions, 0 = session is not filtered
2125
     * @param bool      $returnArray Will return an array of the type:
2126
     * [sum_of_progresses, number] if it is set to true
2127
     * @param boolean $onlySeriousGame Optional. Limit average to lp on seriousgame mode
2128
     * @return double   Average progress of the user in this course
2129
     */
2130
    public static function get_avg_student_progress(
2131
        $studentId,
2132
        $courseCode = null,
2133
        $lpIdList = array(),
2134
        $sessionId = null,
2135
        $returnArray = false,
2136
        $onlySeriousGame = false
2137
    ) {
2138
        // If there is at least one learning path and one student.
2139
        if (empty($studentId)) {
2140
            return false;
2141
        }
2142
2143
        $sessionId = intval($sessionId);
2144
        $courseInfo = api_get_course_info($courseCode);
2145
2146
        if (empty($courseInfo)) {
2147
            return false;
2148
        }
2149
2150
        $lPTable = Database::get_course_table(TABLE_LP_MAIN);
2151
        $lpViewTable = Database::get_course_table(TABLE_LP_VIEW);
2152
        $lpConditions = [];
2153
        $lpConditions['c_id = ? '] = $courseInfo['real_id'];
2154
2155
        if ($sessionId > 0) {
2156
            $lpConditions['AND (session_id = ? OR session_id = 0 OR session_id IS NULL)'] = $sessionId;
2157
        } else {
2158
            $lpConditions['AND session_id = ?'] = $sessionId;
2159
        }
2160
2161
        if (is_array($lpIdList) && count($lpIdList) > 0) {
2162
            $placeHolders = [];
2163
            for ($i = 0; $i < count($lpIdList); $i++) {
2164
                $placeHolders[] = '?';
2165
            }
2166
            $lpConditions['AND id IN(' . implode(', ', $placeHolders) . ') '] = $lpIdList;
2167
        }
2168
2169
        if ($onlySeriousGame) {
2170
            $lpConditions['AND seriousgame_mode = ? '] = true;
2171
        }
2172
2173
        $resultLP = Database::select(
2174
            'id',
2175
            $lPTable,
2176
            ['where' => $lpConditions]
2177
        );
2178
        $filteredLP = array_keys($resultLP);
2179
2180
        if (empty($filteredLP)) {
2181
            return false;
2182
        }
2183
2184
        $conditions = [
2185
            " c_id = {$courseInfo['real_id']} ",
2186
            " lp_view.lp_id IN(" . implode(', ', $filteredLP) . ") "
2187
        ];
2188
2189
        if (is_array($studentId)) {
2190
            $studentId = array_map('intval', $studentId);
2191
            $conditions[] = " lp_view.user_id IN (" . implode(',', $studentId) . ")  ";
2192
2193
            $groupBy = 'GROUP BY lp_id';
2194
        } else {
2195
            $studentId = intval($studentId);
2196
            $conditions[] = " lp_view.user_id = '$studentId' ";
2197
2198
            if (empty($lpIdList)) {
2199
                $lpList = new LearnpathList($studentId, $courseCode, $sessionId);
2200
                $lpList = $lpList->get_flat_list();
2201
                if (!empty($lpList)) {
2202
                    /** @var  $lp */
2203
                    foreach ($lpList as $lpId => $lp) {
2204
                        $lpIdList[] = $lpId;
2205
                    }
2206
                }
2207
            }
2208
2209
            $groupBy = 'GROUP BY user_id';
2210
        }
2211
2212
        if (!empty($sessionId)) {
2213
            $conditions[] = " session_id = $sessionId ";
2214
        }
2215
2216
        $conditionToString = implode('AND', $conditions);
2217
        // Get last view for each student (in case of multi-attempt)
2218
        // Also filter on LPs of this session
2219
        /*$sql = " SELECT
2220
                    MAX(view_count),
2221
                    AVG(progress) average,
2222
                    SUM(progress) sum_progress,
2223
                    count(progress) count_progress
2224
                FROM $lpViewTable lp_view
2225
                WHERE
2226
                  $conditionToString
2227
                $groupBy";*/
2228
2229
        $sql = "
2230
            SELECT
2231
                    lp_id,
2232
                    view_count,
2233
                    progress
2234
            FROM $lpViewTable lp_view
2235
            WHERE
2236
              $conditionToString
2237
            $groupBy
2238
            ORDER BY view_count DESC
2239
            ";
2240
2241
        $result = Database::query($sql);
2242
2243
        $progress = array();
2244
        $viewCount = array();
2245 View Code Duplication
        while ($row = Database::fetch_array($result, 'ASSOC')) {
2246
            if (!isset($viewCount[$row['lp_id']])) {
2247
                $progress[$row['lp_id']] = $row['progress'];
2248
            }
2249
            $viewCount[$row['lp_id']] = $row['view_count'];
2250
        }
2251
2252
        // Fill with lp ids
2253
        if (!empty($lpIdList)) {
2254
            foreach ($lpIdList as $lpId) {
2255
                if (!isset($progress[$lpId])) {
2256
                    $progress[$lpId] = 0;
2257
                }
2258
            }
2259
        }
2260
2261
        if (!empty($progress)) {
2262
            $sum = array_sum($progress);
2263
            $average = $sum / count($progress);
2264
        } else {
2265
            $average = 0;
2266
            $sum = 0;
2267
        }
2268
2269
        if ($returnArray) {
2270
            return [
2271
                $sum,
2272
                count($progress)
2273
            ];
2274
        }
2275
2276
        return round($average, 1);
2277
    }
2278
2279
    /**
2280
     * This function gets:
2281
     * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores.
2282
     * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores.
2283
     * 3. And finally it will return the average between 1. and 2.
2284
     * @todo improve performance, when loading 1500 users with 20 lps the script dies
2285
     * This function does not take the results of a Test out of a LP
2286
     *
2287
     * @param   mixed       $student_id Array of user ids or an user id
2288
     * @param   string      $course_code
2289
     * @param   array       $lp_ids List of LP ids
2290
     * @param   int         $session_id Session id (optional),
2291
     * if param $session_id is null(default) it'll return results
2292
     * including sessions, 0 = session is not filtered
2293
     * @param   bool        $return_array Returns an array of the
2294
     * type [sum_score, num_score] if set to true
2295
     * @param   bool        $get_only_latest_attempt_results get only the latest attempts or ALL attempts
2296
     *
2297
     * @return  string      Value (number %) Which represents a round integer explain in got in 3.
2298
     */
2299
    public static function get_avg_student_score(
2300
        $student_id,
2301
        $course_code,
2302
        $lp_ids = array(),
2303
        $session_id = null,
2304
        $return_array = false,
2305
        $get_only_latest_attempt_results = false
2306
    ) {
2307
        $debug = false;
2308
        if (empty($lp_ids)) {
2309
            $debug = false;
2310
        }
2311
2312
        if ($debug) echo '<h1>Tracking::get_avg_student_score</h1>';
2313
        $tbl_stats_exercices = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2314
        $tbl_stats_attempts = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
2315
2316
        $course = api_get_course_info($course_code);
2317
2318
        if (!empty($course)) {
2319
2320
            // Get course tables names
2321
            $tbl_quiz_questions = Database :: get_course_table(TABLE_QUIZ_QUESTION);
2322
            $lp_table = Database:: get_course_table(TABLE_LP_MAIN);
2323
            $lp_item_table = Database:: get_course_table(TABLE_LP_ITEM);
2324
            $lp_view_table = Database:: get_course_table(TABLE_LP_VIEW);
2325
            $lp_item_view_table = Database :: get_course_table(TABLE_LP_ITEM_VIEW);
2326
2327
            $course_id = $course['real_id'];
2328
2329
            // Compose a filter based on optional learning paths list given
2330
            $condition_lp = "";
2331 View Code Duplication
            if (count($lp_ids) > 0) {
2332
                $condition_lp =" AND id IN(".implode(',',$lp_ids).") ";
2333
            }
2334
2335
            // Compose a filter based on optional session id
2336
            $session_id = intval($session_id);
2337
            if (count($lp_ids) > 0) {
2338
                $condition_session = " AND session_id = $session_id ";
2339
            } else {
2340
                $condition_session = " WHERE session_id = $session_id ";
2341
            }
2342
2343
            // Check the real number of LPs corresponding to the filter in the
2344
            // database (and if no list was given, get them all)
2345
2346
            if (empty($session_id)) {
2347
                $sql = "SELECT DISTINCT(id), use_max_score
2348
                        FROM $lp_table
2349
                        WHERE c_id = $course_id AND (session_id = 0 OR session_id IS NULL ) $condition_lp ";
2350
            } else {
2351
                $sql = "SELECT DISTINCT(id), use_max_score
2352
                        FROM $lp_table
2353
                        WHERE c_id = $course_id $condition_lp ";
2354
            }
2355
2356
            $res_row_lp   = Database::query($sql);
2357
            $count_row_lp = Database::num_rows($res_row_lp);
2358
2359
            $lp_list = $use_max_score = array();
2360
            while ($row_lp = Database::fetch_array($res_row_lp)) {
2361
                $lp_list[] = $row_lp['id'];
2362
                $use_max_score[$row_lp['id']] = $row_lp['use_max_score'];
2363
            }
2364
2365
            if ($debug) {
2366
                echo 'Use max score or not list '; var_dump($use_max_score);
1 ignored issue
show
Security Debugging Code introduced by
var_dump($use_max_score); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
2367
            }
2368
2369
            // prepare filter on users
2370 View Code Duplication
            if (is_array($student_id)) {
2371
                array_walk($student_id, 'intval');
2372
                $condition_user1 =" AND user_id IN (".implode(',', $student_id).") ";
2373
            } else {
2374
                $condition_user1 =" AND user_id = $student_id ";
2375
            }
2376
2377
            if ($count_row_lp > 0 && !empty($student_id)) {
2378
2379
                // Getting latest LP result for a student
2380
                //@todo problem when a  course have more than 1500 users
2381
                $sql = "SELECT MAX(view_count) as vc, id, progress, lp_id, user_id
2382
                        FROM $lp_view_table
2383
                        WHERE
2384
                            c_id = $course_id AND
2385
                            lp_id IN (".implode(',', $lp_list).")
2386
                            $condition_user1 AND
2387
                            session_id = $session_id
2388
                        GROUP BY lp_id, user_id";
2389
                if ($debug) echo $sql;
2390
2391
                $rs_last_lp_view_id = Database::query($sql);
2392
2393
                $global_result = 0;
2394
2395
                if (Database::num_rows($rs_last_lp_view_id) > 0) {
2396
                    // Cycle through each line of the results (grouped by lp_id, user_id)
2397
                    while ($row_lp_view = Database::fetch_array($rs_last_lp_view_id)) {
2398
                        $count_items = 0;
2399
                        $lp_partial_total = 0;
2400
2401
                        $list = array();
2402
                        $lp_view_id = $row_lp_view['id'];
2403
                        $lp_id      = $row_lp_view['lp_id'];
2404
                        $user_id    = $row_lp_view['user_id'];
2405
                        if ($debug) echo '<h2>LP id '.$lp_id.'</h2>';
2406
2407
                        if ($get_only_latest_attempt_results) {
2408
                            //Getting lp_items done by the user
2409
                            $sql = "SELECT DISTINCT lp_item_id
2410
                                    FROM $lp_item_view_table
2411
                                    WHERE
2412
                                        c_id = $course_id AND
2413
                                        lp_view_id = $lp_view_id
2414
                                    ORDER BY lp_item_id";
2415
                            $res_lp_item = Database::query($sql);
2416
2417
                            while ($row_lp_item = Database::fetch_array($res_lp_item,'ASSOC')) {
2418
                                $my_lp_item_id = $row_lp_item['lp_item_id'];
2419
2420
                                // Getting the most recent attempt
2421
                                $sql = "SELECT  lp_iv.id as lp_item_view_id,
2422
                                                lp_iv.score as score,
2423
                                                lp_i.max_score,
2424
                                                lp_iv.max_score as max_score_item_view,
2425
                                                lp_i.path,
2426
                                                lp_i.item_type,
2427
                                                lp_i.id as iid
2428
                                        FROM $lp_item_view_table as lp_iv
2429
                                            INNER JOIN $lp_item_table as lp_i
2430
                                            ON  lp_i.id = lp_iv.lp_item_id AND
2431
                                                lp_iv.c_id = $course_id AND
2432
                                                lp_i.c_id  = $course_id AND
2433
                                                (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."')
2434
                                        WHERE
2435
                                            lp_item_id = $my_lp_item_id AND
2436
                                            lp_view_id = $lp_view_id
2437
                                        ORDER BY view_count DESC
2438
                                        LIMIT 1";
2439
                                $res_lp_item_result = Database::query($sql);
2440
                                while ($row_max_score = Database::fetch_array($res_lp_item_result,'ASSOC')) {
2441
                                    $list[]= $row_max_score;
2442
                                }
2443
                            }
2444
                        } else {
2445
                            // For the currently analysed view, get the score and
2446
                            // max_score of each item if it is a sco or a TOOL_QUIZ
2447
                            $sql = "SELECT
2448
                                        lp_iv.id as lp_item_view_id,
2449
                                        lp_iv.score as score,
2450
                                        lp_i.max_score,
2451
                                        lp_iv.max_score as max_score_item_view,
2452
                                        lp_i.path,
2453
                                        lp_i.item_type,
2454
                                        lp_i.id as iid
2455
                                      FROM $lp_item_view_table as lp_iv
2456
                                      INNER JOIN $lp_item_table as lp_i
2457
                                      ON lp_i.id = lp_iv.lp_item_id AND
2458
                                         lp_iv.c_id = $course_id AND
2459
                                         lp_i.c_id  = $course_id AND
2460
                                         (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."')
2461
                                      WHERE lp_view_id = $lp_view_id ";
2462
                            if ($debug) echo $sql.'<br />';
2463
                            $res_max_score = Database::query($sql);
2464
2465
                            while ($row_max_score = Database::fetch_array($res_max_score,'ASSOC')) {
2466
                                $list[]= $row_max_score;
2467
                            }
2468
                        }
2469
2470
                        // Go through each scorable element of this view
2471
2472
                        $score_of_scorm_calculate = 0;
2473
2474
                        foreach ($list as $row_max_score) {
2475
                            // Came from the original lp_item
2476
                            $max_score = $row_max_score['max_score'];
2477
                            // Came from the lp_item_view
2478
                            $max_score_item_view = $row_max_score['max_score_item_view'];
2479
                            $score = $row_max_score['score'];
2480
2481
                            if ($debug) echo '<h3>Item Type: ' .$row_max_score['item_type'].'</h3>';
2482
2483
                            if ($row_max_score['item_type'] == 'sco') {
2484
                                /* Check if it is sco (easier to get max_score)
2485
                                   when there's no max score, we assume 100 as the max score,
2486
                                   as the SCORM 1.2 says that the value should always be between 0 and 100.
2487
                                */
2488
                                if ($max_score == 0 || is_null($max_score) || $max_score == '') {
2489
                                    // Chamilo style
2490
                                    if ($use_max_score[$lp_id]) {
2491
                                        $max_score = 100;
2492
                                    } else {
2493
                                        // Overwrites max score = 100 to use the one that came in the lp_item_view see BT#1613
2494
                                        $max_score = $max_score_item_view;
2495
                                    }
2496
                                }
2497
                                // Avoid division by zero errors
2498
                                if (!empty($max_score)) {
2499
                                    $lp_partial_total += $score/$max_score;
2500
                                }
2501 View Code Duplication
                                if ($debug) echo '<b>$lp_partial_total, $score, $max_score '.$lp_partial_total.' '.$score.' '.$max_score.'</b><br />';
2502
                            } else {
2503
                                // Case of a TOOL_QUIZ element
2504
                                $item_id = $row_max_score['iid'];
2505
                                $item_path = $row_max_score['path'];
2506
                                $lp_item_view_id = $row_max_score['lp_item_view_id'];
2507
2508
                                // Get last attempt to this exercise through
2509
                                // the current lp for the current user
2510
                                $sql = "SELECT exe_id
2511
                                        FROM $tbl_stats_exercices
2512
                                        WHERE
2513
                                            exe_exo_id           = '$item_path' AND
2514
                                            exe_user_id          = $user_id AND
2515
                                            orig_lp_item_id      = $item_id AND
2516
                                            orig_lp_item_view_id = $lp_item_view_id AND
2517
                                            c_id                 = $course_id AND
2518
                                            session_id           = $session_id AND
2519
                                            status = ''
2520
                                        ORDER BY exe_date DESC
2521
                                        LIMIT 1";
2522
2523
                                if ($debug) echo $sql .'<br />';
2524
                                $result_last_attempt = Database::query($sql);
2525
                                $num = Database :: num_rows($result_last_attempt);
2526
                                if ($num > 0 ) {
2527
                                    $id_last_attempt = Database :: result($result_last_attempt, 0, 0);
2528
                                    if ($debug) echo $id_last_attempt.'<br />';
2529
2530
                                    // Within the last attempt number tracking, get the sum of
2531
                                    // the max_scores of all questions that it was
2532
                                    // made of (we need to make this call dynamic because of random questions selection)
2533
                                    $sql = "SELECT SUM(t.ponderation) as maxscore FROM
2534
                                            (
2535
                                                SELECT DISTINCT
2536
                                                    question_id,
2537
                                                    marks,
2538
                                                    ponderation
2539
                                                FROM $tbl_stats_attempts AS at
2540
                                                INNER JOIN $tbl_quiz_questions AS q
2541
                                                ON (q.id = at.question_id)
2542
                                                WHERE
2543
                                                    exe_id ='$id_last_attempt' AND
2544
                                                    q.c_id = $course_id
2545
                                            )
2546
                                            AS t";
2547
                                    if ($debug) echo '$sql: '.$sql.' <br />';
2548
                                    $res_max_score_bis = Database::query($sql);
2549
                                    $row_max_score_bis = Database::fetch_array($res_max_score_bis);
2550
2551
                                    if (!empty($row_max_score_bis['maxscore'])) {
2552
                                        $max_score = $row_max_score_bis['maxscore'];
2553
                                    }
2554
                                    if (!empty($max_score) && floatval($max_score) > 0) {
2555
                                        $lp_partial_total += $score/$max_score;
2556
                                    }
2557 View Code Duplication
                                    if ($debug) echo '$lp_partial_total, $score, $max_score <b>'.$lp_partial_total.' '.$score.' '.$max_score.'</b><br />';
2558
                                }
2559
                            }
2560
2561
                            if (in_array($row_max_score['item_type'], array('quiz','sco'))) {
2562
                                // Normal way
2563
                                if ($use_max_score[$lp_id]) {
2564
                                    $count_items++;
2565
                                } else {
2566
                                    if ($max_score != '') {
2567
                                        $count_items++;
2568
                                    }
2569
                                }
2570
                                if ($debug) echo '$count_items: '.$count_items;
2571
                            }
2572
                        } //end for
2573
2574
                        $score_of_scorm_calculate += $count_items ? (($lp_partial_total / $count_items) * 100) : 0;
2575
2576
                        if ($debug) echo '<h3>$count_items '.$count_items.'</h3>';
2577
                        if ($debug) echo '<h3>$score_of_scorm_calculate '.$score_of_scorm_calculate.'</h3>';
2578
2579
                        $global_result += $score_of_scorm_calculate;
2580
                        if ($debug) echo '<h3>$global_result '.$global_result.'</h3>';
2581
                    } // end while
2582
                }
2583
2584
                $lp_with_quiz = 0;
2585
                foreach ($lp_list as $lp_id) {
2586
                    // Check if LP have a score we assume that all SCO have an score
2587
                    $sql = "SELECT count(id) as count
2588
                            FROM $lp_item_table
2589
                            WHERE
2590
                                c_id = $course_id AND
2591
                                (item_type = 'quiz' OR item_type = 'sco') AND
2592
                                lp_id = ".$lp_id;
2593
                    if ($debug) echo $sql;
2594
                    $result_have_quiz = Database::query($sql);
2595
2596
                    if (Database::num_rows($result_have_quiz) > 0 ) {
2597
                        $row = Database::fetch_array($result_have_quiz,'ASSOC');
2598
                        if (is_numeric($row['count']) && $row['count'] != 0) {
2599
                            $lp_with_quiz++;
2600
                        }
2601
                    }
2602
                }
2603
2604
                if ($debug) echo '<h3>$lp_with_quiz '.$lp_with_quiz.' </h3>';
2605
                if ($debug) echo '<h3>Final return</h3>';
2606
2607
                if ($lp_with_quiz != 0) {
2608
                    if (!$return_array) {
2609
                        $score_of_scorm_calculate = round(($global_result/$lp_with_quiz),2);
2610
                        if ($debug) var_dump($score_of_scorm_calculate);
2611
                        if (empty($lp_ids)) {
2612
                            if ($debug) echo '<h2>All lps fix: '.$score_of_scorm_calculate.'</h2>';
2613
                        }
2614
                        return $score_of_scorm_calculate;
2615
                    } else {
2616
                        if ($debug) var_dump($global_result, $lp_with_quiz);
2617
                        return array($global_result, $lp_with_quiz);
2618
                    }
2619
                } else {
2620
2621
                    return '-';
2622
                }
2623
            }
2624
        }
2625
2626
        return null;
2627
    }
2628
2629
    /**
2630
     * This function gets:
2631
     * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores.
2632
     * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores.
2633
     * 3. And finally it will return the average between 1. and 2.
2634
     * This function does not take the results of a Test out of a LP
2635
     *
2636
     * @param   int|array   Array of user ids or an user id
2637
     * @param   string      Course code
2638
     * @param   array       List of LP ids
2639
     * @param   int         Session id (optional), if param $session_id is null(default)
2640
     * it'll return results including sessions, 0 = session is not filtered
2641
     * @param   bool        Returns an array of the type [sum_score, num_score] if set to true
2642
     * @param   bool        get only the latest attempts or ALL attempts
2643
     * @return  string      Value (number %) Which represents a round integer explain in got in 3.
2644
     */
2645
    public static function getAverageStudentScore(
2646
        $student_id,
2647
        $course_code = null,
2648
        $lp_ids = array(),
2649
        $session_id = null
2650
    ) {
2651
        if (empty($student_id)) {
2652
            return 0;
2653
        }
2654
2655
        $conditions = array();
2656
2657
        if (!empty($course_code)) {
2658
            $course = api_get_course_info($course_code);
2659
            $courseId = $course['real_id'];
2660
            $conditions[] = " c_id = $courseId";
2661
        }
2662
2663
        // Get course tables names
2664
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
2665
        $lp_item_table = Database :: get_course_table(TABLE_LP_ITEM);
2666
        $lp_view_table = Database :: get_course_table(TABLE_LP_VIEW);
2667
        $lp_item_view_table = Database :: get_course_table(TABLE_LP_ITEM_VIEW);
2668
2669
        // Compose a filter based on optional learning paths list given
2670
2671
        if (!empty($lp_ids) && count($lp_ids) > 0) {
2672
            $conditions[] = " id IN(".implode(',', $lp_ids).") ";
2673
        }
2674
2675
        // Compose a filter based on optional session id
2676
        $session_id = intval($session_id);
2677
        if (!empty($session_id)) {
2678
            $conditions[] = " session_id = $session_id ";
2679
        }
2680
2681 View Code Duplication
        if (is_array($student_id)) {
2682
            array_walk($student_id, 'intval');
2683
            $conditions[] =" lp_view.user_id IN (".implode(',', $student_id).") ";
2684
        } else {
2685
            $conditions[] =" lp_view.user_id = $student_id ";
2686
        }
2687
2688
        $conditionsToString = implode('AND ', $conditions);
2689
        $sql = "SELECT  SUM(lp_iv.score) sum_score,
2690
                        SUM(lp_i.max_score) sum_max_score,
2691
                        count(*) as count
2692
                FROM $lp_table as lp
2693
                INNER JOIN $lp_item_table as lp_i
2694
                ON lp.id = lp_id AND lp.c_id = lp_i.c_id
2695
                INNER JOIN $lp_view_table as lp_view
2696
                ON lp_view.lp_id = lp_i.lp_id AND lp_view.c_id = lp_i.c_id
2697
                INNER JOIN $lp_item_view_table as lp_iv
2698
                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
2699
                WHERE (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."') AND
2700
                $conditionsToString
2701
                ";
2702
        $result = Database::query($sql);
2703
        $row = Database::fetch_array($result, 'ASSOC');
2704
2705
        if (empty($row['sum_max_score'])) {
2706
            return 0;
2707
        }
2708
2709
        return ($row['sum_score'] / $row['sum_max_score'])*100;
2710
2711
    }
2712
2713
    /**
2714
     * This function gets time spent in learning path for a student inside a course
2715
     * @param     int|array    Student id(s)
2716
     * @param     string         Course code
2717
     * @param     array         Limit average to listed lp ids
2718
     * @param     int            Session id (optional), if param $session_id is
2719
     * null(default) it'll return results including sessions, 0 = session is not filtered
2720
     * @return     int         Total time
2721
     */
2722
    public static function get_time_spent_in_lp($student_id, $course_code, $lp_ids = array(), $session_id = null)
2723
    {
2724
        $course = CourseManager :: get_course_information($course_code);
2725
        $student_id = intval($student_id);
2726
        $total_time = 0;
2727
2728
        if (!empty($course)) {
2729
2730
            $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
2731
            $t_lpv = Database :: get_course_table(TABLE_LP_VIEW);
2732
            $t_lpiv = Database :: get_course_table(TABLE_LP_ITEM_VIEW);
2733
2734
            $course_id = $course['real_id'];
2735
2736
            // Compose a filter based on optional learning paths list given
2737
            $condition_lp = "";
2738 View Code Duplication
            if (count($lp_ids) > 0) {
2739
                $condition_lp =" AND id IN(".implode(',',$lp_ids).") ";
2740
            }
2741
2742
            // Compose a filter based on optional session id
2743
            $session_id = intval($session_id);
2744
            $condition_session = "";
2745
            if (isset($session_id)) {
2746
                $condition_session = " AND session_id = $session_id ";
2747
            }
2748
2749
            // Check the real number of LPs corresponding to the filter in the
2750
            // database (and if no list was given, get them all)
2751
2752
            $res_row_lp = Database::query("SELECT DISTINCT(id) FROM $lp_table WHERE c_id = $course_id $condition_lp");
2753
            $count_row_lp = Database::num_rows($res_row_lp);
2754
2755
            // calculates time
2756
            if ($count_row_lp > 0) {
2757 View Code Duplication
                while ($row_lp = Database::fetch_array($res_row_lp)) {
2758
                    $lp_id = intval($row_lp['id']);
2759
                    $sql = 'SELECT SUM(total_time)
2760
                        FROM '.$t_lpiv.' AS item_view
2761
                        INNER JOIN '.$t_lpv.' AS view
2762
                            ON item_view.lp_view_id = view.id
2763
                            WHERE
2764
                            item_view.c_id 		= '.$course_id.' AND
2765
                            view.c_id 			= '.$course_id.' AND
2766
                            view.lp_id 			= '.$lp_id.'
2767
                            AND view.user_id 	= '.$student_id.' AND
2768
                            session_id 			= '.$session_id;
2769
2770
                    $rs = Database::query($sql);
2771
                    if (Database :: num_rows($rs) > 0) {
2772
                        $total_time += Database :: result($rs, 0, 0);
2773
                    }
2774
                }
2775
            }
2776
        }
2777
2778
        return $total_time;
2779
    }
2780
2781
    /**
2782
     * This function gets last connection time to one learning path
2783
     * @param     int|array    Student id(s)
2784
     * @param     string         Course code
2785
     * @param     int         Learning path id
2786
     * @return     int         Total time
2787
     */
2788
    public static function get_last_connection_time_in_lp($student_id, $course_code, $lp_id, $session_id = 0)
2789
    {
2790
        $course = CourseManager :: get_course_information($course_code);
2791
        $student_id = intval($student_id);
2792
        $lp_id = intval($lp_id);
2793
        $last_time = 0;
2794
        $session_id = intval($session_id);
2795
2796
        if (!empty($course)) {
2797
2798
            $course_id	 = $course['real_id'];
2799
2800
            $lp_table    = Database :: get_course_table(TABLE_LP_MAIN);
2801
            $t_lpv       = Database :: get_course_table(TABLE_LP_VIEW);
2802
            $t_lpiv      = Database :: get_course_table(TABLE_LP_ITEM_VIEW);
2803
2804
            // Check the real number of LPs corresponding to the filter in the
2805
            // database (and if no list was given, get them all)
2806
            $res_row_lp = Database::query("SELECT id FROM $lp_table WHERE c_id = $course_id AND id = $lp_id ");
2807
            $count_row_lp = Database::num_rows($res_row_lp);
2808
2809
            // calculates last connection time
2810
            if ($count_row_lp > 0) {
2811
                $sql = 'SELECT MAX(start_time)
2812
                        FROM ' . $t_lpiv . ' AS item_view
2813
                        INNER JOIN ' . $t_lpv . ' AS view
2814
                            ON item_view.lp_view_id = view.id
2815
                        WHERE
2816
                            item_view.c_id 		= '.$course_id.' AND
2817
                            view.c_id 			= '.$course_id.' AND
2818
                            view.lp_id 			= '.$lp_id.'
2819
                            AND view.user_id 	= '.$student_id.'
2820
                            AND view.session_id = '.$session_id;
2821
                $rs = Database::query($sql);
2822
                if (Database :: num_rows($rs) > 0) {
2823
                    $last_time = Database :: result($rs, 0, 0);
2824
                }
2825
            }
2826
        }
2827
2828
        return $last_time;
2829
    }
2830
2831
    /**
2832
     * gets the list of students followed by coach
2833
     * @param     int     Coach id
2834
     * @return     array     List of students
2835
     */
2836
    public static function get_student_followed_by_coach($coach_id)
2837
    {
2838
        $coach_id = intval($coach_id);
2839
2840
        $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2841
        $tbl_session_course = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE);
2842
        $tbl_session_user = Database :: get_main_table(TABLE_MAIN_SESSION_USER);
2843
        $tbl_session = Database :: get_main_table(TABLE_MAIN_SESSION);
2844
2845
        $students = [];
2846
2847
        // At first, courses where $coach_id is coach of the course //
2848
        $sql = 'SELECT session_id, c_id
2849
                FROM ' . $tbl_session_course_user . '
2850
                WHERE user_id=' . $coach_id.' AND status=2';
2851
2852
        if (api_is_multiple_url_enabled()) {
2853
            $tbl_session_rel_access_url= Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
2854
            $access_url_id = api_get_current_access_url_id();
2855
            if ($access_url_id != -1) {
2856
                $sql = 'SELECT scu.session_id, scu.c_id
2857
                    FROM ' . $tbl_session_course_user . ' scu
2858
                    INNER JOIN '.$tbl_session_rel_access_url.'  sru
2859
                    ON (scu.session_id=sru.session_id)
2860
                    WHERE
2861
                        scu.user_id=' . $coach_id.' AND
2862
                        scu.status=2 AND
2863
                        sru.access_url_id = '.$access_url_id;
2864
            }
2865
        }
2866
2867
        $result = Database::query($sql);
2868
2869 View Code Duplication
        while ($a_courses = Database::fetch_array($result)) {
2870
            $courseId = $a_courses["c_id"];
2871
            $id_session = $a_courses["session_id"];
2872
2873
            $sql = "SELECT DISTINCT srcru.user_id
2874
                    FROM $tbl_session_course_user AS srcru, $tbl_session_user sru
2875
                    WHERE
2876
                        srcru.user_id = sru.user_id AND
2877
                        sru.relation_type<>".SESSION_RELATION_TYPE_RRHH." AND
2878
                        srcru.session_id = sru.session_id AND
2879
                        srcru.c_id = '$courseId' AND
2880
                        srcru.session_id='$id_session'";
2881
2882
            $rs = Database::query($sql);
2883
2884
            while ($row = Database::fetch_array($rs)) {
2885
                $students[$row['user_id']] = $row['user_id'];
2886
            }
2887
        }
2888
2889
        // Then, courses where $coach_id is coach of the session    //
2890
        $sql = 'SELECT session_course_user.user_id
2891
                FROM ' . $tbl_session_course_user . ' as session_course_user
2892
                INNER JOIN     '.$tbl_session_user.' sru
2893
                ON session_course_user.user_id = sru.user_id AND session_course_user.session_id = sru.session_id
2894
                INNER JOIN ' . $tbl_session_course . ' as session_course
2895
                ON session_course.c_id = session_course_user.c_id
2896
                AND session_course_user.session_id = session_course.session_id
2897
                INNER JOIN ' . $tbl_session . ' as session
2898
                ON session.id = session_course.session_id
2899
                AND session.id_coach = ' . $coach_id;
2900 View Code Duplication
        if (api_is_multiple_url_enabled()) {
2901
            $tbl_session_rel_access_url= Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
2902
            $access_url_id = api_get_current_access_url_id();
2903
            if ($access_url_id != -1){
2904
                $sql = 'SELECT session_course_user.user_id
2905
                        FROM ' . $tbl_session_course_user . ' as session_course_user
2906
                        INNER JOIN     '.$tbl_session_user.' sru
2907
                            ON session_course_user.user_id = sru.user_id AND
2908
                               session_course_user.session_id = sru.session_id
2909
                        INNER JOIN ' . $tbl_session_course . ' as session_course
2910
                            ON session_course.c_id = session_course_user.c_id AND
2911
                            session_course_user.session_id = session_course.session_id
2912
                        INNER JOIN ' . $tbl_session . ' as session
2913
                            ON session.id = session_course.session_id AND
2914
                            session.id_coach = ' . $coach_id.'
2915
                        INNER JOIN '.$tbl_session_rel_access_url.' session_rel_url
2916
                            ON session.id = session_rel_url.session_id WHERE access_url_id = '.$access_url_id;
2917
            }
2918
        }
2919
2920
        $result = Database::query($sql);
2921
        while ($row = Database::fetch_array($result)) {
2922
            $students[$row['user_id']] = $row['user_id'];
2923
        }
2924
2925
        return $students;
2926
    }
2927
2928
    /**
2929
     * Get student followed by a coach inside a session
2930
     * @param    int        Session id
2931
     * @param    int        Coach id
2932
     * @return   array    students list
2933
     */
2934
    public static function get_student_followed_by_coach_in_a_session($id_session, $coach_id)
2935
    {
2936
        $coach_id = intval($coach_id);
2937
        $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2938
        $tbl_session = Database :: get_main_table(TABLE_MAIN_SESSION);
2939
2940
        $students = [];
2941
        // At first, courses where $coach_id is coach of the course //
2942
        $sql = 'SELECT c_id FROM ' . $tbl_session_course_user . '
2943
                WHERE session_id="' . $id_session . '" AND user_id=' . $coach_id.' AND status=2';
2944
        $result = Database::query($sql);
2945
2946
        while ($a_courses = Database::fetch_array($result)) {
2947
            $courseId = $a_courses["c_id"];
2948
2949
            $sql = "SELECT DISTINCT srcru.user_id
2950
                    FROM $tbl_session_course_user AS srcru
2951
                    WHERE
2952
                        c_id = '$courseId' AND
2953
                        session_id = '" . $id_session . "'";
2954
            $rs = Database::query($sql);
2955
            while ($row = Database::fetch_array($rs)) {
2956
                $students[$row['user_id']] = $row['user_id'];
2957
            }
2958
        }
2959
2960
        // Then, courses where $coach_id is coach of the session
2961
        $sql = 'SELECT id_coach FROM ' . $tbl_session . '
2962
                WHERE id="' . $id_session.'" AND id_coach="' . $coach_id . '"';
2963
        $result = Database::query($sql);
2964
2965
        //He is the session_coach so we select all the users in the session
2966
        if (Database::num_rows($result) > 0) {
2967
            $sql = 'SELECT DISTINCT srcru.user_id
2968
                    FROM ' . $tbl_session_course_user . ' AS srcru
2969
                    WHERE session_id="' . $id_session . '"';
2970
            $result = Database::query($sql);
2971
            while ($row = Database::fetch_array($result)) {
2972
                $students[$row['user_id']] = $row['user_id'];
2973
            }
2974
        }
2975
2976
        return $students;
2977
    }
2978
2979
    /**
2980
     * Check if a coach is allowed to follow a student
2981
     * @param    int        Coach id
2982
     * @param    int        Student id
2983
     * @return    bool
2984
     */
2985
    public static function is_allowed_to_coach_student($coach_id, $student_id)
2986
    {
2987
        $coach_id = intval($coach_id);
2988
        $student_id = intval($student_id);
2989
2990
        $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2991
        $tbl_session_course = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE);
2992
        $tbl_session = Database :: get_main_table(TABLE_MAIN_SESSION);
2993
2994
        // At first, courses where $coach_id is coach of the course //
2995
2996
        $sql = 'SELECT 1 FROM ' . $tbl_session_course_user . '
2997
                WHERE user_id=' . $coach_id .' AND status=2';
2998
        $result = Database::query($sql);
2999
        if (Database::num_rows($result) > 0) {
3000
            return true;
3001
        }
3002
3003
        // Then, courses where $coach_id is coach of the session
3004
        $sql = 'SELECT session_course_user.user_id
3005
                FROM ' . $tbl_session_course_user . ' as session_course_user
3006
                INNER JOIN ' . $tbl_session_course . ' as session_course
3007
                    ON session_course.c_id = session_course_user.c_id
3008
                INNER JOIN ' . $tbl_session . ' as session
3009
                    ON session.id = session_course.session_id
3010
                    AND session.id_coach = ' . $coach_id . '
3011
                WHERE user_id = ' . $student_id;
3012
        $result = Database::query($sql);
3013
        if (Database::num_rows($result) > 0) {
3014
            return true;
3015
        }
3016
3017
        return false;
3018
    }
3019
3020
    /**
3021
     * Get courses followed by coach
3022
     * @param     int        Coach id
3023
     * @param    int        Session id (optional)
3024
     * @return    array    Courses list
3025
     */
3026
    public static function get_courses_followed_by_coach($coach_id, $id_session = null)
3027
    {
3028
        $coach_id = intval($coach_id);
3029
        if (!empty($id_session)) {
3030
            $id_session = intval($id_session);
3031
        }
3032
3033
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3034
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3035
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3036
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3037
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3038
3039
        // At first, courses where $coach_id is coach of the course.
3040
3041
        $sql = 'SELECT DISTINCT c.code
3042
                FROM ' . $tbl_session_course_user . ' sc
3043
                INNER JOIN '.$tbl_course.' c
3044
                ON (c.id = sc.c_id)
3045
                WHERE user_id = ' . $coach_id.' AND status = 2';
3046
3047
        if (api_is_multiple_url_enabled()) {
3048
            $access_url_id = api_get_current_access_url_id();
3049
            if ($access_url_id != -1){
3050
                $sql = 'SELECT DISTINCT c.code
3051
                        FROM ' . $tbl_session_course_user . ' scu
3052
                        INNER JOIN '.$tbl_course.' c
3053
                        ON (c.code = scu.c_id)
3054
                        INNER JOIN '.$tbl_course_rel_access_url.' cru
3055
                        ON (c.id = cru.c_id)
3056
                        WHERE
3057
                            scu.user_id=' . $coach_id.' AND
3058
                            scu.status=2 AND
3059
                            cru.access_url_id = '.$access_url_id;
3060
            }
3061
        }
3062
3063
        if (!empty($id_session)) {
3064
            $sql .= ' AND session_id=' . $id_session;
3065
        }
3066
3067
        $courseList = array();
3068
        $result = Database::query($sql);
3069
        while ($row = Database::fetch_array($result)) {
3070
            $courseList[$row['code']] = $row['code'];
3071
        }
3072
3073
        // Then, courses where $coach_id is coach of the session
3074
3075
        $sql = 'SELECT DISTINCT course.code
3076
                FROM ' . $tbl_session_course . ' as session_course
3077
                INNER JOIN ' . $tbl_session . ' as session
3078
                    ON session.id = session_course.session_id
3079
                    AND session.id_coach = ' . $coach_id . '
3080
                INNER JOIN ' . $tbl_course . ' as course
3081
                    ON course.id = session_course.c_id';
3082
3083 View Code Duplication
        if (api_is_multiple_url_enabled()) {
3084
            $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3085
            $access_url_id = api_get_current_access_url_id();
3086
            if ($access_url_id != -1){
3087
                $sql = 'SELECT DISTINCT c.code
3088
                    FROM ' . $tbl_session_course . ' as session_course
3089
                    INNER JOIN '.$tbl_course.' c
3090
                    ON (c.id = session_course.c_id)
3091
                    INNER JOIN ' . $tbl_session . ' as session
3092
                    ON session.id = session_course.session_id
3093
                        AND session.id_coach = ' . $coach_id . '
3094
                    INNER JOIN ' . $tbl_course . ' as course
3095
                        ON course.id = session_course.c_id
3096
                     INNER JOIN '.$tbl_course_rel_access_url.' course_rel_url
3097
                    ON (course_rel_url.c_id = c.id)';
3098
            }
3099
        }
3100
3101
        if (!empty ($id_session)) {
3102
            $sql .= ' WHERE session_course.session_id=' . $id_session;
3103
            if (api_is_multiple_url_enabled())
3104
            $sql .=  ' AND access_url_id = '.$access_url_id;
3105
        }  else {
3106
            if (api_is_multiple_url_enabled())
3107
            $sql .=  ' WHERE access_url_id = '.$access_url_id;
3108
        }
3109
3110
        $result = Database::query($sql);
3111
        while ($row = Database::fetch_array($result)) {
3112
            $courseList[$row['code']] = $row['code'];
3113
        }
3114
3115
        return $courseList;
3116
    }
3117
3118
    /**
3119
     * Get sessions coached by user
3120
     * @param $coach_id
3121
     * @param int $start
3122
     * @param int $limit
3123
     * @param bool $getCount
3124
     * @param string $keyword
3125
     * @param string $description
3126
     * @return mixed
3127
     */
3128
    public static function get_sessions_coached_by_user(
3129
        $coach_id,
3130
        $start = 0,
3131
        $limit = 0,
3132
        $getCount = false,
3133
        $keyword = '',
3134
        $description = ''
3135
    ) {
3136
        // table definition
3137
        $tbl_session = Database :: get_main_table(TABLE_MAIN_SESSION);
3138
        $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3139
        $coach_id = intval($coach_id);
3140
3141
        $select = " SELECT * FROM ";
3142
        if ($getCount) {
3143
            $select = " SELECT count(DISTINCT id) as count FROM ";
3144
        }
3145
3146
        $limitCondition = null;
3147 View Code Duplication
        if (!empty($start) && !empty($limit)) {
3148
            $limitCondition = " LIMIT ".intval($start).", ".intval($limit);
3149
        }
3150
3151
        $keywordCondition = null;
3152
3153 View Code Duplication
        if (!empty($keyword)) {
3154
            $keyword = Database::escape_string($keyword);
3155
            $keywordCondition = " AND (name LIKE '%$keyword%' ) ";
3156
3157
            if (!empty($description)) {
3158
                $description = Database::escape_string($description);
3159
                $keywordCondition = " AND (name LIKE '%$keyword%' OR description LIKE '%$description%' ) ";
3160
            }
3161
        }
3162
3163
        $tbl_session_rel_access_url= Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3164
        $access_url_id = api_get_current_access_url_id();
3165
3166
        $sql = "
3167
            $select
3168
            (
3169
                SELECT DISTINCT
3170
                    id,
3171
                    name,
3172
                    access_start_date,
3173
                    access_end_date
3174
                FROM $tbl_session session INNER JOIN $tbl_session_rel_access_url session_rel_url
3175
                ON (session.id = session_rel_url.session_id)
3176
                WHERE
3177
                    id_coach = $coach_id AND
3178
                    access_url_id = $access_url_id
3179
                    $keywordCondition
3180
            UNION
3181
                SELECT DISTINCT
3182
                    session.id,
3183
                    session.name,
3184
                    session.access_start_date,
3185
                    session.access_end_date
3186
                FROM $tbl_session as session
3187
                INNER JOIN $tbl_session_course_user as session_course_user
3188
                    ON session.id = session_course_user.session_id AND
3189
                    session_course_user.user_id = $coach_id AND
3190
                    session_course_user.status = 2
3191
                INNER JOIN $tbl_session_rel_access_url session_rel_url
3192
                ON (session.id = session_rel_url.session_id)
3193
                WHERE
3194
                    access_url_id = $access_url_id
3195
                    $keywordCondition
3196
            ) as sessions $limitCondition
3197
            ";
3198
3199
        $rs = Database::query($sql);
3200
        if ($getCount) {
3201
            $row = Database::fetch_array($rs);
3202
            return $row['count'];
3203
        }
3204
3205
        $sessions = [];
3206
        while ($row = Database::fetch_array($rs)) {
3207
            $sessions[$row['id']] = $row;
3208
        }
3209
3210
        if (!empty($sessions)) {
3211
            foreach ($sessions as & $session) {
3212
                if ($session['access_start_date'] == '0000-00-00 00:00:00' || empty($session['access_start_date'])
3213
                ) {
3214
                    $session['status'] = get_lang('SessionActive');
3215
                }
3216
                else {
3217
                    $time_start = api_strtotime($session['access_start_date'], 'UTC');
3218
                    $time_end = api_strtotime($session['access_end_date'], 'UTC');
3219
                    if ($time_start < time() && time() < $time_end) {
3220
                        $session['status'] = get_lang('SessionActive');
3221
                    } else {
3222
                        if (time() < $time_start) {
3223
                            $session['status'] = get_lang('SessionFuture');
3224
                        } else {
3225
                            if (time() > $time_end) {
3226
                                $session['status'] = get_lang('SessionPast');
3227
                            }
3228
                        }
3229
                    }
3230
                }
3231
            }
3232
        }
3233
3234
        return $sessions;
3235
    }
3236
3237
    /**
3238
     * Get courses list from a session
3239
     * @param    int        Session id
3240
     * @return    array    Courses list
3241
     */
3242 View Code Duplication
    public static function get_courses_list_from_session($session_id)
3243
    {
3244
        $session_id = intval($session_id);
3245
3246
        // table definition
3247
        $tbl_session_course = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE);
3248
        $courseTable = Database :: get_main_table(TABLE_MAIN_COURSE);
3249
3250
        $sql = "SELECT DISTINCT code, c_id
3251
                FROM $tbl_session_course sc
3252
                INNER JOIN $courseTable c
3253
                ON sc.c_id = c.id
3254
                WHERE session_id= $session_id";
3255
3256
        $result = Database::query($sql);
3257
3258
        $courses = array();
3259
        while ($row = Database::fetch_array($result)) {
3260
            $courses[$row['code']] = $row;
3261
        }
3262
3263
        return $courses;
3264
    }
3265
3266
    /**
3267
     * Count the number of documents that an user has uploaded to a course
3268
     * @param    int|array   Student id(s)
3269
     * @param    string      Course code
3270
     * @param    int         Session id (optional),
3271
     * if param $session_id is null(default)
3272
     * return count of assignments including sessions, 0 = session is not filtered
3273
     * @return    int        Number of documents
3274
     */
3275
    public static function count_student_uploaded_documents($student_id, $course_code, $session_id = null)
3276
    {
3277
        // get the information of the course
3278
        $a_course = CourseManager::get_course_information($course_code);
3279
        if (!empty($a_course)) {
3280
            // table definition
3281
            $tbl_item_property = Database :: get_course_table(TABLE_ITEM_PROPERTY);
3282
            $tbl_document = Database :: get_course_table(TABLE_DOCUMENT);
3283
            $course_id	 = $a_course['real_id'];
3284
            if (is_array($student_id)) {
3285
                $studentList = array_map('intval', $student_id);
3286
                $condition_user = " AND ip.insert_user_id IN ('".implode(',', $studentList)."') ";
3287
            } else {
3288
                $student_id = intval($student_id);
3289
                $condition_user = " AND ip.insert_user_id = '$student_id' ";
3290
            }
3291
3292
            $condition_session = null;
3293
            if (isset($session_id)) {
3294
                $session_id = intval($session_id);
3295
                $condition_session = " AND pub.session_id = $session_id ";
3296
            }
3297
3298
            $sql = "SELECT count(ip.tool) AS count
3299
                    FROM $tbl_item_property ip INNER JOIN $tbl_document pub
3300
                            ON ip.ref = pub.id
3301
                    WHERE 	ip.c_id  = $course_id AND
3302
                            pub.c_id  = $course_id AND
3303
                            pub.filetype ='file' AND
3304
                            ip.tool = 'document'
3305
                            $condition_user $condition_session ";
3306
            $rs = Database::query($sql);
3307
            $row = Database::fetch_array($rs, 'ASSOC');
3308
            return $row['count'];
3309
        }
3310
        return null;
3311
    }
3312
3313
    /**
3314
     * Count assignments per student
3315
     * @param    int|array   Student id(s)
3316
     * @param    string        Course code
3317
     * @param    int            Session id (optional),
3318
     * if param $session_id is null(default) return count of assignments
3319
     * including sessions, 0 = session is not filtered
3320
     * @return    int            Count of assignments
3321
     */
3322
    public static function count_student_assignments($student_id, $course_code = null, $session_id = null)
3323
    {
3324
        if (empty($student_id)) {
3325
            return 0;
3326
        }
3327
3328
        $conditions = array();
3329
3330
        // Get the information of the course
3331
        $a_course = CourseManager::get_course_information($course_code);
3332
        if (!empty($a_course)) {
3333
            $course_id = $a_course['real_id'];
3334
            $conditions[]= " ip.c_id  = $course_id AND pub.c_id  = $course_id ";
3335
        }
3336
3337
        // table definition
3338
        $tbl_item_property = Database :: get_course_table(TABLE_ITEM_PROPERTY);
3339
        $tbl_student_publication = Database :: get_course_table(TABLE_STUDENT_PUBLICATION);
3340
3341 View Code Duplication
        if (is_array($student_id)) {
3342
            $studentList = array_map('intval', $student_id);
3343
            $conditions[]= " ip.insert_user_id IN ('".implode("','", $studentList)."') ";
3344
        } else {
3345
            $student_id = intval($student_id);
3346
            $conditions[]= " ip.insert_user_id = '$student_id' ";
3347
        }
3348
        if (isset($session_id)) {
3349
            $session_id = intval($session_id);
3350
            $conditions[]= " pub.session_id = $session_id ";
3351
        }
3352
        $conditionToString = implode('AND', $conditions);
3353
3354
        $sql = "SELECT count(ip.tool) as count
3355
                FROM $tbl_item_property ip
3356
                INNER JOIN $tbl_student_publication pub ON ip.ref = pub.id
3357
                WHERE
3358
                    ip.tool='work' AND
3359
                    $conditionToString";
3360
        $rs = Database::query($sql);
3361
        $row = Database::fetch_array($rs, 'ASSOC');
3362
        return $row['count'];
3363
    }
3364
3365
    /**
3366
     * Count messages per student inside forum tool
3367
     * @param    int|array        Student id
3368
     * @param    string    Course code
3369
     * @param    int        Session id (optional), if param $session_id is
3370
     * null(default) return count of messages including sessions, 0 = session is not filtered
3371
     * @return    int        Count of messages
3372
     */
3373
    public static function count_student_messages($student_id, $courseCode = null, $session_id = null)
3374
    {
3375
        if (empty($student_id)) {
3376
            return 0;
3377
        }
3378
3379
        $courseInfo = api_get_course_info($courseCode);
3380
        $courseCondition = null;
3381
        $conditions = array();
3382
        if (!empty($courseInfo)) {
3383
            $course_id	    = $courseInfo['real_id'];
3384
            $conditions[]= " post.c_id  = $course_id AND forum.c_id = $course_id ";
3385
        }
3386
3387
        // Table definition.
3388
        $tbl_forum_post = Database :: get_course_table(TABLE_FORUM_POST);
3389
        $tbl_forum = Database :: get_course_table(TABLE_FORUM);
3390
3391 View Code Duplication
        if (is_array($student_id)) {
3392
            $studentList = array_map('intval', $student_id);
3393
            $conditions[]= " post.poster_id IN ('".implode("','", $studentList)."') ";
3394
        } else {
3395
            $student_id = intval($student_id);
3396
            $conditions[]= " post.poster_id = '$student_id' ";
3397
        }
3398
3399
        if (isset($session_id)) {
3400
            $session_id = intval($session_id);
3401
            $conditions[]= " forum.session_id = $session_id";
3402
        }
3403
3404
        $conditionsToString = implode('AND ', $conditions);
3405
        $sql = "SELECT count(poster_id) as count
3406
                FROM $tbl_forum_post post INNER JOIN $tbl_forum forum
3407
                ON forum.forum_id = post.forum_id
3408
                WHERE $conditionsToString";
3409
3410
        $rs = Database::query($sql);
3411
        $row = Database::fetch_array($rs, 'ASSOC');
3412
        $count = $row['count'];
3413
3414
        return $count;
3415
    }
3416
3417
    /**
3418
     * This function counts the number of post by course
3419
     * @param      string     Course code
3420
     * @param    int        Session id (optional), if param $session_id is
3421
     * null(default) it'll return results including sessions,
3422
     * 0 = session is not filtered
3423
     * @param int $groupId
3424
     * @return    int     The number of post by course
3425
     */
3426 View Code Duplication
    public static function count_number_of_posts_by_course($course_code, $session_id = null, $groupId = 0)
3427
    {
3428
        $courseInfo = api_get_course_info($course_code);
3429
        if (!empty($courseInfo)) {
3430
            $tbl_posts = Database :: get_course_table(TABLE_FORUM_POST);
3431
            $tbl_forums = Database :: get_course_table(TABLE_FORUM);
3432
3433
            $condition_session = '';
3434
            if (isset($session_id)) {
3435
                $session_id = intval($session_id);
3436
                $condition_session = api_get_session_condition($session_id, true,  false, 'f.session_id');
3437
            }
3438
3439
            $course_id = $courseInfo['real_id'];
3440
            $groupId = intval($groupId);
3441
            if (!empty($groupId)) {
3442
                $groupCondition = " i.to_group_id = $groupId  ";
3443
            } else {
3444
                $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) ";
3445
            }
3446
3447
            $item = Database :: get_course_table(TABLE_ITEM_PROPERTY);
3448
            $sql = "SELECT count(*) FROM $tbl_posts p
3449
                    INNER JOIN $tbl_forums f
3450
                    ON f.forum_id = p.forum_id AND p.c_id = f.c_id
3451
                    INNER JOIN $item i
3452
                    ON (tool = '".TOOL_FORUM."' AND f.c_id = i.c_id AND f.iid = i.ref)
3453
                    WHERE
3454
                        p.c_id = $course_id AND
3455
                        f.c_id = $course_id AND
3456
                        $groupCondition
3457
                        $condition_session
3458
                    ";
3459
            $result = Database::query($sql);
3460
            $row = Database::fetch_row($result);
3461
            $count = $row[0];
3462
3463
            return $count;
3464
        } else {
3465
            return null;
3466
        }
3467
    }
3468
3469
    /**
3470
     * This function counts the number of threads by course
3471
     * @param      string     Course code
3472
     * @param    int        Session id (optional),
3473
     * if param $session_id is null(default) it'll return results including
3474
     * sessions, 0 = session is not filtered
3475
     * @param int $groupId
3476
     * @return    int     The number of threads by course
3477
     */
3478 View Code Duplication
    public static function count_number_of_threads_by_course($course_code, $session_id = null, $groupId = 0)
3479
    {
3480
        $course_info = api_get_course_info($course_code);
3481
        if (empty($course_info)) {
3482
            return null;
3483
        }
3484
3485
        $course_id = $course_info['real_id'];
3486
        $tbl_threads = Database :: get_course_table(TABLE_FORUM_THREAD);
3487
        $tbl_forums = Database :: get_course_table(TABLE_FORUM);
3488
3489
        $condition_session = '';
3490
        if (isset($session_id)) {
3491
            $session_id = intval($session_id);
3492
            $condition_session = ' AND f.session_id = '. $session_id;
3493
        }
3494
3495
        $groupId = intval($groupId);
3496
3497
        if (!empty($groupId)) {
3498
            $groupCondition = " i.to_group_id = $groupId ";
3499
        } else {
3500
            $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) ";
3501
        }
3502
3503
        $item = Database :: get_course_table(TABLE_ITEM_PROPERTY);
3504
        $sql = "SELECT count(*)
3505
                FROM $tbl_threads t
3506
                INNER JOIN $tbl_forums f
3507
                ON f.iid = t.forum_id AND f.c_id = t.c_id
3508
                INNER JOIN $item i
3509
                ON (
3510
                    tool = '".TOOL_FORUM_THREAD."' AND
3511
                    f.c_id = i.c_id AND
3512
                    t.iid = i.ref
3513
                )
3514
                WHERE
3515
                    t.c_id = $course_id AND
3516
                    f.c_id = $course_id AND
3517
                    $groupCondition
3518
                    $condition_session
3519
                ";
3520
3521
        $result = Database::query($sql);
3522
        if (Database::num_rows($result)) {
3523
            $row = Database::fetch_row($result);
3524
            $count = $row[0];
3525
3526
            return $count;
3527
        } else {
3528
3529
            return null;
3530
        }
3531
    }
3532
3533
    /**
3534
     * This function counts the number of forums by course
3535
     * @param      string     Course code
3536
     * @param    int        Session id (optional),
3537
     * if param $session_id is null(default) it'll return results
3538
     * including sessions, 0 = session is not filtered
3539
     * @param int $groupId
3540
     * @return    int     The number of forums by course
3541
     */
3542
    public static function count_number_of_forums_by_course($course_code, $session_id = null, $groupId = 0)
3543
    {
3544
        $course_info = api_get_course_info($course_code);
3545
        if (empty($course_info)) {
3546
            return null;
3547
        }
3548
        $course_id = $course_info['real_id'];
3549
3550
        $condition_session = '';
3551
        if (isset($session_id)) {
3552
             $session_id = intval($session_id);
3553
             $condition_session = ' AND f.session_id = '. $session_id;
3554
        }
3555
3556
        $groupId = intval($groupId);
3557
        if (!empty($groupId)) {
3558
            $groupCondition = " i.to_group_id = $groupId ";
3559
        } else {
3560
            $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) ";
3561
        }
3562
3563
        $tbl_forums = Database :: get_course_table(TABLE_FORUM);
3564
        $item = Database :: get_course_table(TABLE_ITEM_PROPERTY);
3565
3566
        $sql = "SELECT count(*)
3567
                FROM $tbl_forums f
3568
                INNER JOIN $item i
3569
                    ON f.c_id = i.c_id AND f.iid = i.ref AND tool = '".TOOL_FORUM."'
3570
                WHERE
3571
                    f.c_id = $course_id AND
3572
                    $groupCondition
3573
                    $condition_session
3574
                ";
3575
        $result = Database::query($sql);
3576
        if (Database::num_rows($result)) {
3577
            $row = Database::fetch_row($result);
3578
            $count = $row[0];
3579
            return $count;
3580
        } else {
3581
            return null;
3582
        }
3583
    }
3584
3585
    /**
3586
     * This function counts the chat last connections by course in x days
3587
     * @param      string     Course code
3588
     * @param      int     Last x days
3589
     * @param    int        Session id (optional)
3590
     * @return     int     Chat last connections by course in x days
3591
     */
3592
    public static function chat_connections_during_last_x_days_by_course($course_code, $last_days, $session_id = 0)
3593
    {
3594
        $course_info = api_get_course_info($course_code);
3595
        if (empty($course_info)) {
3596
            return null;
3597
        }
3598
        $course_id = $course_info['real_id'];
3599
3600
        //protect data
3601
        $last_days   = intval($last_days);
3602
        $session_id  = intval($session_id);
3603
        $tbl_stats_access = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
3604
        $now = api_get_utc_datetime();
3605
        $sql = "SELECT count(*) FROM $tbl_stats_access
3606
                WHERE
3607
                    DATE_SUB('$now',INTERVAL $last_days DAY) <= access_date AND
3608
                    c_id = '$course_id' AND
3609
                    access_tool='".TOOL_CHAT."' AND
3610
                    access_session_id='$session_id' ";
3611
        $result = Database::query($sql);
3612
        if (Database::num_rows($result)) {
3613
            $row = Database::fetch_row($result);
3614
            $count = $row[0];
3615
            return $count;
3616
        } else {
3617
            return null;
3618
        }
3619
    }
3620
3621
    /**
3622
     * This function gets the last student's connection in chat
3623
     * @param      int     Student id
3624
     * @param      string     Course code
3625
     * @param    int        Session id (optional)
3626
     * @return     string    datetime formatted without day (e.g: February 23, 2010 10:20:50 )
3627
     */
3628
    public static function chat_last_connection($student_id, $courseId, $session_id = 0)
3629
    {
3630
        $student_id = intval($student_id);
3631
        $courseId = intval($courseId);
3632
        $session_id    = intval($session_id);
3633
        $date_time  = '';
3634
3635
        // table definition
3636
        $tbl_stats_access = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
3637
        $sql = "SELECT access_date
3638
                FROM $tbl_stats_access
3639
                WHERE
3640
                     access_tool='".TOOL_CHAT."' AND
3641
                     access_user_id='$student_id' AND
3642
                     c_id = $courseId AND
3643
                     access_session_id = '$session_id'
3644
                ORDER BY access_date DESC limit 1";
3645
        $rs = Database::query($sql);
3646 View Code Duplication
        if (Database::num_rows($rs) > 0) {
3647
            $row = Database::fetch_array($rs);
3648
            $date_time = api_convert_and_format_date(
3649
                $row['access_date'],
3650
                null,
3651
                date_default_timezone_get()
3652
            );
3653
        }
3654
        return $date_time;
3655
    }
3656
3657
    /**
3658
     * Get count student's visited links
3659
     * @param    int        Student id
3660
     * @param    int    $courseId
3661
     * @param    int        Session id (optional)
3662
     * @return    int        count of visited links
3663
     */
3664 View Code Duplication
    public static function count_student_visited_links($student_id, $courseId, $session_id = 0)
3665
    {
3666
        $student_id  = intval($student_id);
3667
        $courseId = intval($courseId);
3668
        $session_id  = intval($session_id);
3669
3670
        // table definition
3671
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
3672
3673
        $sql = 'SELECT 1
3674
                FROM '.$table.'
3675
                WHERE
3676
                    links_user_id= '.$student_id.' AND
3677
                    c_id = "'.$courseId.'" AND
3678
                    links_session_id = '.$session_id.' ';
3679
3680
        $rs = Database::query($sql);
3681
        return Database::num_rows($rs);
3682
    }
3683
3684
    /**
3685
     * Get count student downloaded documents
3686
     * @param    int        Student id
3687
     * @param    int    $courseId
3688
     * @param    int        Session id (optional)
3689
     * @return    int        Count downloaded documents
3690
     */
3691 View Code Duplication
    public static function count_student_downloaded_documents($student_id, $courseId, $session_id = 0)
3692
    {
3693
        $student_id  = intval($student_id);
3694
        $courseId = intval($courseId);
3695
        $session_id  = intval($session_id);
3696
3697
        // table definition
3698
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
3699
3700
        $sql = 'SELECT 1
3701
                FROM ' . $table . '
3702
                WHERE down_user_id = '.$student_id.'
3703
                AND c_id  = "'.$courseId.'"
3704
                AND down_session_id = '.$session_id.' ';
3705
        $rs = Database::query($sql);
3706
3707
        return Database::num_rows($rs);
3708
    }
3709
3710
    /**
3711
     * Get course list inside a session from a student
3712
     * @param    int        $user_id Student id
3713
     * @param    int        $id_session Session id (optional)
3714
     * @return    array    Courses list
3715
     */
3716
    public static function get_course_list_in_session_from_student($user_id, $id_session = 0)
3717
    {
3718
        $user_id = intval($user_id);
3719
        $id_session = intval($id_session);
3720
        $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3721
        $courseTable = Database :: get_main_table(TABLE_MAIN_COURSE);
3722
3723
        $sql = "SELECT c.code
3724
                FROM $tbl_session_course_user sc
3725
                INNER JOIN $courseTable c
3726
                WHERE
3727
                    user_id= $user_id  AND
3728
                    session_id = $id_session";
3729
        $result = Database::query($sql);
3730
        $courses = array();
3731
        while ($row = Database::fetch_array($result)) {
3732
            $courses[$row['code']] = $row['code'];
3733
        }
3734
3735
        return $courses;
3736
    }
3737
3738
    /**
3739
     * Get inactive students in course
3740
     * @param    int   $courseId
3741
     * @param    string  $since  Since login course date (optional, default = 'never')
3742
     * @param    int        $session_id    (optional)
3743
     * @return    array    Inactive users
3744
     */
3745
    public static function getInactiveStudentsInCourse($courseId, $since = 'never', $session_id = 0)
3746
    {
3747
        $tbl_track_login = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
3748
        $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3749
        $table_course_rel_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
3750
        $tableCourse = Database :: get_main_table(TABLE_MAIN_COURSE);
3751
        $now = api_get_utc_datetime();
3752
        $courseId = intval($courseId);
3753
3754
        if (empty($courseId)) {
3755
            return false;
3756
        }
3757
3758
        if (empty($session_id)) {
3759
            $inner = '
3760
                INNER JOIN '.$table_course_rel_user.' course_user
3761
                ON course_user.user_id = stats_login.user_id AND course_user.c_id = c.id
3762
            ';
3763
        } else {
3764
            $inner = '
3765
                    INNER JOIN '.$tbl_session_course_user.' session_course_user
3766
                    ON
3767
                        c.id = session_course_user.c_id AND
3768
                        session_course_user.session_id = '.intval($session_id).' AND
3769
                        session_course_user.user_id = stats_login.user_id ';
3770
        }
3771
3772
        $sql = 'SELECT stats_login.user_id, MAX(login_course_date) max_date
3773
                FROM '.$tbl_track_login.' stats_login
3774
                INNER JOIN '.$tableCourse.' c
3775
                ON (c.id = stats_login.c_id)
3776
                '.$inner.'
3777
                WHERE c.id = '.$courseId.'
3778
                GROUP BY stats_login.user_id
3779
                HAVING DATE_SUB( "' . $now . '", INTERVAL '.$since.' DAY) > max_date ';
3780
3781
        if ($since == 'never') {
3782
            if (empty($session_id)) {
3783
                $sql = 'SELECT course_user.user_id
3784
                        FROM ' . $table_course_rel_user . ' course_user
3785
                        LEFT JOIN ' . $tbl_track_login . ' stats_login
3786
                        ON course_user.user_id = stats_login.user_id AND
3787
                        relation_type<>' . COURSE_RELATION_TYPE_RRHH . '
3788
                        INNER JOIN ' . $tableCourse . ' c
3789
                        ON (c.id = course_user.c_id)
3790
                        WHERE
3791
                            course_user.c_id = ' . $courseId . ' AND
3792
                            stats_login.login_course_date IS NULL
3793
                        GROUP BY course_user.user_id';
3794
            } else {
3795
                $sql = 'SELECT session_course_user.user_id
3796
                        FROM '.$tbl_session_course_user.' session_course_user
3797
                        LEFT JOIN ' . $tbl_track_login . ' stats_login
3798
                        ON session_course_user.user_id = stats_login.user_id
3799
                        INNER JOIN ' . $tableCourse . ' c
3800
                        ON (c.id = session_course_user.c_id)
3801
                        WHERE
3802
                            session_course_user.c_id = ' . $courseId . ' AND
3803
                            stats_login.login_course_date IS NULL
3804
                        GROUP BY session_course_user.user_id';
3805
3806
            }
3807
        }
3808
3809
        $rs = Database::query($sql);
3810
        $inactive_users = array();
3811
        while($user = Database::fetch_array($rs)) {
3812
            $inactive_users[] = $user['user_id'];
3813
        }
3814
3815
        return $inactive_users;
3816
    }
3817
3818
    /**
3819
     * Get count login per student
3820
     * @param    int    $student_id    Student id
3821
     * @param    int    $courseId
3822
     * @param    int    $session_id    Session id (optional)
3823
     * @return    int        count login
3824
     */
3825
    public static function count_login_per_student($student_id, $courseId, $session_id = 0)
3826
    {
3827
        $student_id  = intval($student_id);
3828
        $courseId = intval($courseId);
3829
        $session_id  = intval($session_id);
3830
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
3831
3832
        $sql = 'SELECT '.$student_id.'
3833
                FROM ' . $table . '
3834
                WHERE
3835
                    access_user_id=' . $student_id . ' AND
3836
                    c_id="' . $courseId . '" AND
3837
                    access_session_id = "'.$session_id.'" ';
3838
3839
        $rs = Database::query($sql);
3840
        $nb_login = Database::num_rows($rs);
3841
3842
        return $nb_login;
3843
    }
3844
3845
    /**
3846
     * Get students followed by a human resources manager
3847
     * @param    int        Drh id
3848
     * @return    array    Student list
3849
     */
3850
    public static function get_student_followed_by_drh($hr_dept_id)
3851
    {
3852
        $hr_dept_id = intval($hr_dept_id);
3853
        $a_students = array();
3854
        $tbl_user     = Database :: get_main_table(TABLE_MAIN_USER);
3855
3856
        $sql = 'SELECT DISTINCT user_id FROM '.$tbl_user.' as user
3857
                WHERE hr_dept_id='.$hr_dept_id;
3858
        $rs = Database::query($sql);
3859
3860
        while($user = Database :: fetch_array($rs)) {
3861
            $a_students[$user['user_id']] = $user['user_id'];
3862
        }
3863
3864
        return $a_students;
3865
    }
3866
3867
3868
3869
    /**
3870
     * get count clicks about tools most used by course
3871
     * @param    int      $courseId
3872
     * @param    int        Session id (optional),
3873
     * if param $session_id is null(default) it'll return results
3874
     * including sessions, 0 = session is not filtered
3875
     * @return    array     tools data
3876
     */
3877 View Code Duplication
    public static function get_tools_most_used_by_course($courseId, $session_id = null)
3878
    {
3879
        $courseId = intval($courseId);
3880
        $data = array();
3881
        $TABLETRACK_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
3882
        $condition_session     = '';
3883
        if (isset($session_id)) {
3884
            $session_id = intval($session_id);
3885
            $condition_session = ' AND access_session_id = '. $session_id;
3886
        }
3887
        $sql = "SELECT
3888
                    access_tool,
3889
                    COUNT(DISTINCT access_user_id),
3890
                    count(access_tool) as count_access_tool
3891
                FROM $TABLETRACK_ACCESS
3892
                WHERE
3893
                    access_tool IS NOT NULL AND
3894
                    access_tool != '' AND
3895
                    c_id = '$courseId'
3896
                    $condition_session
3897
                GROUP BY access_tool
3898
                ORDER BY count_access_tool DESC
3899
                LIMIT 0, 3";
3900
        $rs = Database::query($sql);
3901
        if (Database::num_rows($rs) > 0) {
3902
            while ($row = Database::fetch_array($rs)) {
3903
                $data[] = $row;
3904
            }
3905
        }
3906
        return $data;
3907
    }
3908
    /**
3909
     * Get total clicks
3910
     * 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,
3911
     * BUT NO ROW MATCH THE CONDITION, IT SHOULD BE FINE TO USE IT WHEN YOU USE USER DEFINED DATES AND NO CHAMILO DATES
3912
     * @param   int     User Id
3913
     * @param   int     Course Id
3914
     * @param   int     Session Id (optional), if param $session_id is null(default) it'll return results including sessions, 0 = session is not filtered
3915
     * @param   string  Date from
3916
     * @param   string  Date to
3917
     * @return  array   Data
3918
     * @author  César Perales [email protected] 2014-01-16
3919
     */
3920
    public static function get_total_clicks($userId, $courseId, $sessionId = 0, $date_from = '', $date_to = '')
3921
    {
3922
        $course = api_get_course_info_by_id($courseId);
3923
        $tables = array(
3924
            TABLE_STATISTIC_TRACK_E_LASTACCESS => array(
3925
                'course'    => 'c_id',
3926
                'session'   => 'access_session_id',
3927
                'user'      => 'access_user_id',
3928
                'start_date'=> 'access_date',
3929
            ),
3930
            TABLE_STATISTIC_TRACK_E_ACCESS => array(
3931
                'course'    => 'c_id',
3932
                'session'   => 'access_session_id',
3933
                'user'      => 'access_user_id',
3934
                'start_date'=> 'access_date',
3935
            ),
3936
            #TABLE_STATISTIC_TRACK_E_LOGIN, array(,, 'login_date', 'logout_date');
3937
            TABLE_STATISTIC_TRACK_E_DOWNLOADS => array(
3938
                'course'    => 'c_id',
3939
                'session'   => 'down_session_id',
3940
                'user'      => 'down_user_id',
3941
                'start_date'=> 'down_date',
3942
                ),
3943
            TABLE_STATISTIC_TRACK_E_LINKS => array(
3944
                'course'    => 'c_id',
3945
                'session'   => 'links_session_id',
3946
                'user'      => 'links_user_id',
3947
                'start_date'=> 'links_date',
3948
            ),
3949
            TABLE_STATISTIC_TRACK_E_ONLINE => array(
3950
                'course'    => 'c_id',
3951
                'session'   => 'session_id',
3952
                'user'      => 'login_user_id',
3953
                'start_date'=> 'login_date',
3954
            ),
3955
            #TABLE_STATISTIC_TRACK_E_HOTPOTATOES,
3956
            /*TABLE_STATISTIC_TRACK_E_COURSE_ACCESS => array(
3957
                'course'    => 'c_id',
3958
                'session'   => 'session_id',
3959
                'user'      => 'user_id',
3960
                'start_date'=> 'login_course_date',
3961
                'end_date'  => 'logout_course_date',
3962
                ),*/
3963
            TABLE_STATISTIC_TRACK_E_EXERCISES => array(
3964
                'course'    => 'c_id',
3965
                'session'   => 'session_id',
3966
                'user'      => 'exe_user_id',
3967
                'start_date'=> 'exe_date',
3968
            ),
3969
            TABLE_STATISTIC_TRACK_E_ATTEMPT => array(
3970
                'course'    => 'c_id',
3971
                'session'   => 'session_id',
3972
                'user'      => 'user_id',
3973
                'start_date'=> 'tms',
3974
            ),
3975
            #TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING,
3976
            #TABLE_STATISTIC_TRACK_E_DEFAULT,
3977
            TABLE_STATISTIC_TRACK_E_UPLOADS => array(
3978
                'course'    => 'c_id',
3979
                'session'   => 'upload_session_id',
3980
                'user'      => 'upload_user_id',
3981
                'start_date'=> 'upload_date',
3982
            ),
3983
        );
3984
3985
        foreach ($tables as $tableName => $fields) {
3986
            //If session is defined, add it to query
3987
            $where = '';
3988
            if (isset($sessionId) && !empty($sessionId)) {
3989
                $sessionField = $fields['session'];
3990
                $where .= " AND $sessionField = $sessionId";
3991
            }
3992
3993
            //filter by date
3994
            if (!empty($date_from) && !empty($date_to)) {
3995
                $fieldStartDate = $fields['start_date'];
3996
                if (!isset($fields['end_date'])) {
3997
                    $where .= sprintf(" AND ($fieldStartDate BETWEEN '%s' AND '%s' )", $date_from, $date_to) ;
3998
                } else {
3999
                    $fieldEndDate = $fields['end_date'];
4000
                    $where .= sprintf(" AND fieldStartDate >= '%s'
4001
                        AND $fieldEndDate <= '%s'", $date_from, $date_to);
4002
                }
4003
            }
4004
4005
            //query
4006
            $sql = "SELECT %s as user, count(*) as total
4007
                FROM %s
4008
                WHERE %s = '%s'
4009
                AND %s = %s
4010
                $where
4011
                GROUP BY %s";
4012
            $sql = sprintf($sql,
4013
                $fields['user'],    //user field
4014
                $tableName,         //FROM
4015
                $fields['course'],  //course condition
4016
                $course['real_id'],    //course condition
4017
                $fields['user'],    //user condition
4018
                $userId,            //user condition
4019
                $fields['user']     //GROUP BY
4020
                );
4021
            $rs = Database::query($sql);
4022
4023
            //iterate query
4024
            if (Database::num_rows($rs) > 0) {
4025
                while ($row = Database::fetch_array($rs)) {
4026
                    $data[$row['user']] = (isset($data[$row['user']])) ?  $data[$row['user']] + $row[total]: $row['total'];
4027
                }
4028
            }
4029
        }
4030
4031
        return $data;
4032
    }
4033
4034
    /**
4035
     * get documents most downloaded by course
4036
     * @param      string     Course code
4037
     * @param    int        Session id (optional),
4038
     * if param $session_id is null(default) it'll return results including
4039
     * sessions, 0 = session is not filtered
4040
     * @param    int        Limit (optional, default = 0, 0 = without limit)
4041
     * @return    array     documents downloaded
4042
     */
4043 View Code Duplication
    public static function get_documents_most_downloaded_by_course($course_code, $session_id = null, $limit = 0)
4044
    {
4045
        //protect data
4046
        $courseId = api_get_course_int_id($course_code);
4047
        $data = array();
4048
4049
        $TABLETRACK_DOWNLOADS   = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
4050
        $condition_session = '';
4051
        if (isset($session_id)) {
4052
            $session_id = intval($session_id);
4053
            $condition_session = ' AND down_session_id = '. $session_id;
4054
        }
4055
        $sql = "SELECT down_doc_path, COUNT(DISTINCT down_user_id), COUNT(down_doc_path) as count_down
4056
                FROM $TABLETRACK_DOWNLOADS
4057
                WHERE c_id = $courseId
4058
                    $condition_session
4059
                GROUP BY down_doc_path
4060
                ORDER BY count_down DESC
4061
                LIMIT 0,  $limit";
4062
        $rs = Database::query($sql);
4063
4064
        if (Database::num_rows($rs) > 0) {
4065
            while ($row = Database::fetch_array($rs)) {
4066
                $data[] = $row;
4067
            }
4068
        }
4069
        return $data;
4070
    }
4071
4072
    /**
4073
     * get links most visited by course
4074
     * @param      string     Course code
4075
     * @param    int        Session id (optional),
4076
     * if param $session_id is null(default) it'll
4077
     * return results including sessions, 0 = session is not filtered
4078
     * @return    array     links most visited
4079
     */
4080
    public static function get_links_most_visited_by_course($course_code, $session_id = null)
4081
    {
4082
        $course_code = Database::escape_string($course_code);
4083
        $course_info = api_get_course_info($course_code);
4084
        $course_id = $course_info['real_id'];
4085
        $data = array();
4086
4087
        $TABLETRACK_LINKS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
4088
        $TABLECOURSE_LINKS = Database::get_course_table(TABLE_LINK);
4089
4090
        $condition_session = '';
4091
        if (isset($session_id)) {
4092
            $session_id = intval($session_id);
4093
            $condition_session = ' AND cl.session_id = '.$session_id;
4094
        }
4095
4096
        $sql = "SELECT cl.title, cl.url,count(DISTINCT sl.links_user_id), count(cl.title) as count_visits
4097
                FROM $TABLETRACK_LINKS AS sl, $TABLECOURSE_LINKS AS cl
4098
                WHERE
4099
                    cl.c_id = $course_id AND
4100
                    sl.links_link_id = cl.id AND
4101
                    sl.c_id = $course_id
4102
                    $condition_session
4103
                GROUP BY cl.title, cl.url
4104
                ORDER BY count_visits DESC
4105
                LIMIT 0, 3";
4106
        $rs = Database::query($sql);
4107
        if (Database::num_rows($rs) > 0) {
4108
            while ($row = Database::fetch_array($rs)) {
4109
                $data[] = $row;
4110
            }
4111
        }
4112
        return $data;
4113
    }
4114
4115
    /**
4116
     * Shows the user progress (when clicking in the Progress tab)
4117
     *
4118
     * @param int $user_id
4119
     * @param int $session_id
4120
     * @param string $extra_params
4121
     * @param bool $show_courses
4122
     * @param bool $showAllSessions
4123
     *
4124
     * @return string
4125
     */
4126
    public static function show_user_progress(
4127
        $user_id,
4128
        $session_id = 0,
4129
        $extra_params = '',
4130
        $show_courses = true,
4131
        $showAllSessions = true
4132
    ) {
4133
        $tbl_course = Database :: get_main_table(TABLE_MAIN_COURSE);
4134
        $tbl_session = Database :: get_main_table(TABLE_MAIN_SESSION);
4135
        $tbl_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
4136
        $tbl_access_rel_course = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4137
        $tbl_session_course_user = Database :: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4138
        $tbl_access_rel_session = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
4139
4140
        $user_id = intval($user_id);
4141
        $session_id = intval($session_id);
4142
4143
        if (api_is_multiple_url_enabled()) {
4144
            $sql = "SELECT c.code, title
4145
                    FROM $tbl_course_user cu
4146
                    INNER JOIN $tbl_course c
4147
                    ON (cu.c_id = c.id)
4148
                    INNER JOIN $tbl_access_rel_course a
4149
                    ON (a.c_id = c.id)
4150
                    WHERE
4151
                        cu.user_id = $user_id AND
4152
                        relation_type<> ".COURSE_RELATION_TYPE_RRHH." AND
4153
                        access_url_id = ".api_get_current_access_url_id()."
4154
                    ORDER BY title";
4155
        } else {
4156
            $sql = "SELECT c.code, title
4157
                    FROM $tbl_course_user u
4158
                    INNER JOIN $tbl_course c ON (c_id = c.id)
4159
                    WHERE
4160
                        u.user_id= $user_id AND
4161
                        relation_type<>".COURSE_RELATION_TYPE_RRHH."
4162
                    ORDER BY title";
4163
        }
4164
4165
        $rs = Database::query($sql);
4166
        $courses = $course_in_session = $temp_course_in_session = array();
4167
        while ($row = Database :: fetch_array($rs, 'ASSOC')) {
4168
            $courses[$row['code']] = $row['title'];
4169
        }
4170
4171
        $orderBy = " ORDER BY name ";
4172
        $extraInnerJoin = null;
4173
4174
        if (SessionManager::orderCourseIsEnabled() && !empty($session_id)) {
4175
            $orderBy = " ORDER BY s.id, position ";
4176
            $tableSessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
4177
            $extraInnerJoin = " INNER JOIN $tableSessionRelCourse src
4178
                                ON (cu.c_id = src.c_id AND src.session_id = $session_id) ";
4179
        }
4180
4181
        $sessionCondition = '';
4182
        if (!empty($session_id)) {
4183
            $sessionCondition = " AND s.id = $session_id";
4184
        }
4185
4186
        // Get the list of sessions where the user is subscribed as student
4187
        if (api_is_multiple_url_enabled()) {
4188
            $sql = "SELECT DISTINCT c.code, s.id as session_id, name
4189
                    FROM $tbl_session_course_user cu
4190
                    INNER JOIN $tbl_access_rel_session a
4191
                    ON (a.session_id = cu.session_id)
4192
                    INNER JOIN $tbl_session s
4193
                    ON (s.id = a.session_id)
4194
                    INNER JOIN $tbl_course c
4195
                    ON (c.id = cu.c_id)
4196
                    $extraInnerJoin
4197
                    WHERE
4198
                        cu.user_id = $user_id AND
4199
                        access_url_id = ".api_get_current_access_url_id()."
4200
                        $sessionCondition
4201
                    $orderBy ";
4202
        } else {
4203
            $sql = "SELECT DISTINCT c.code, s.id as session_id, name
4204
                    FROM $tbl_session_course_user cu
4205
                    INNER JOIN $tbl_session s
4206
                    ON (s.id = cu.session_id)
4207
                    INNER JOIN $tbl_course c
4208
                    ON (c.id = cu.c_id)
4209
                    $extraInnerJoin
4210
                    WHERE
4211
                        cu.user_id = $user_id
4212
                        $sessionCondition
4213
                    $orderBy ";
4214
        }
4215
4216
        $rs = Database::query($sql);
4217
        $simple_session_array = array();
4218
        while ($row = Database :: fetch_array($rs)) {
4219
            $course_info = CourseManager::get_course_information($row['code']);
4220
            $temp_course_in_session[$row['session_id']]['course_list'][$course_info['real_id']] = $course_info;
4221
            $temp_course_in_session[$row['session_id']]['name'] = $row['name'];
4222
            $simple_session_array[$row['session_id']] = $row['name'];
4223
        }
4224
4225
        foreach ($simple_session_array as $my_session_id => $session_name) {
4226
            $course_list = $temp_course_in_session[$my_session_id]['course_list'];
4227
            $my_course_data = array();
4228
            foreach ($course_list as $course_data) {
4229
                $my_course_data[$course_data['id']] = $course_data['title'];
4230
            }
4231
4232
            if (empty($session_id)) {
4233
                $my_course_data = utf8_sort($my_course_data);
4234
            }
4235
4236
            $final_course_data = array();
4237
4238
            foreach($my_course_data as $course_id => $value) {
4239
                $final_course_data[$course_id] = $course_list[$course_id];
4240
            }
4241
            $course_in_session[$my_session_id]['course_list'] = $final_course_data;
4242
            $course_in_session[$my_session_id]['name'] = $session_name;
4243
        }
4244
4245
        $html = '';
4246
4247
        // Course list
4248
4249
        if ($show_courses) {
4250
            if (!empty($courses)) {
4251
                $html .= Display::page_subheader(
4252
                    Display::return_icon('course.png', get_lang('MyCourses'), array(), ICON_SIZE_SMALL).' '.get_lang('MyCourses')
4253
                );
4254
                $html .= '<table class="data_table" width="100%">';
4255
                $html .= '<tr>
4256
                          '.Display::tag('th', get_lang('Course'), array('width'=>'300px')).'
4257
                          '.Display::tag('th', get_lang('TimeSpentInTheCourse'), array('class'=>'head')).'
4258
                          '.Display::tag('th', get_lang('Progress'), array('class'=>'head')).'
4259
                          '.Display::tag('th', get_lang('Score').Display::return_icon('info3.gif', get_lang('ScormAndLPTestTotalAverage'), array('align' => 'absmiddle', 'hspace' => '3px')),array('class'=>'head')).'
4260
                          '.Display::tag('th', get_lang('LastConnexion'), array('class'=>'head')).'
4261
                          '.Display::tag('th', get_lang('Details'), array('class'=>'head')).'
4262
                        </tr>';
4263
4264
                foreach ($courses as $course_code => $course_title) {
4265
                    $courseInfo = api_get_course_info($course_code);
4266
                    $courseId = $courseInfo['real_id'];
4267
4268
                    $total_time_login = Tracking :: get_time_spent_on_the_course(
4269
                        $user_id,
4270
                        $courseId
4271
                    );
4272
                    $time = api_time_to_hms($total_time_login);
4273
                    $progress = Tracking :: get_avg_student_progress(
4274
                        $user_id,
4275
                        $course_code
4276
                    );
4277
                    $percentage_score = Tracking :: get_avg_student_score(
4278
                        $user_id,
4279
                        $course_code,
4280
                        array()
4281
                    );
4282
                    $last_connection = Tracking :: get_last_connection_date_on_the_course(
4283
                        $user_id,
4284
                        $courseInfo
4285
                    );
4286
4287
                    if (is_null($progress)) {
4288
                        $progress = '0%';
4289
                    } else {
4290
                        $progress = $progress.'%';
4291
                    }
4292
4293
                    if (isset($_GET['course']) &&
4294
                        $course_code == $_GET['course'] &&
4295
                        empty($_GET['session_id'])
4296
                    ) {
4297
                        $html .= '<tr class="row_odd" style="background-color:#FBF09D">';
4298
                    } else {
4299
                        $html .= '<tr class="row_even">';
4300
                    }
4301
                    $url = api_get_course_url($course_code, $session_id);
4302
                    $course_url = Display::url($course_title, $url, array('target'=>SESSION_LINK_TARGET));
4303
                    $html .= '<td>'.$course_url.'</td>';
4304
4305
                    $html .= '<td align="center">'.$time.'</td>';
4306
                    $html .= '<td align="center">'.$progress.'</td>';
4307
                    $html .= '<td align="center">';
4308
                    if (is_numeric($percentage_score)) {
4309
                        $html .= $percentage_score.'%';
4310
                    } else {
4311
                        $html .= '0%';
4312
                    }
4313
                    $html .= '</td>';
4314
                    $html .= '<td align="center">'.$last_connection.'</td>';
4315
                    $html .= '<td align="center">';
4316
                    if (isset($_GET['course']) &&
4317
                        $course_code == $_GET['course'] &&
4318
                        empty($_GET['session_id'])
4319
                    ) {
4320
                        $html .= '<a href="#">';
4321
                        $html .= Display::return_icon('2rightarrow_na.png', get_lang('Details'));
4322 View Code Duplication
                    } else {
4323
                        $html .= '<a href="'.api_get_self().'?course='.$course_code.$extra_params.'">';
4324
                        $html .= Display::return_icon('2rightarrow.png', get_lang('Details'));
4325
                    }
4326
                    $html .= '</a>';
4327
                    $html .= '</td></tr>';
4328
                }
4329
                $html .= '</table>';
4330
            }
4331
        }
4332
4333
        // Session list
4334
        if (!empty($course_in_session)) {
4335
            $main_session_graph = '';
4336
            //Load graphics only when calling to an specific session
4337
            $session_graph = array();
4338
4339
            $all_exercise_graph_name_list = array();
4340
            $my_results = array();
4341
            $all_exercise_graph_list = array();
4342
4343
            $all_exercise_start_time = array();
4344
4345
            foreach ($course_in_session as $my_session_id => $session_data) {
4346
                $course_list  = $session_data['course_list'];
4347
                $user_count = count(SessionManager::get_users_by_session($my_session_id));
4348
                $exercise_graph_name_list = array();
4349
                //$user_results = array();
4350
                $exercise_graph_list = array();
4351
4352
                foreach ($course_list as $course_data) {
4353
                    $exercise_list = ExerciseLib::get_all_exercises(
4354
                        $course_data,
4355
                        $my_session_id,
4356
                        false,
4357
                        null,
4358
                        false,
4359
                        1
4360
                    );
4361
4362
                    foreach ($exercise_list as $exercise_data) {
4363
                        $exercise_obj = new Exercise($course_data['id']);
4364
                        $exercise_obj->read($exercise_data['id']);
4365
                        //Exercise is not necessary to be visible to show results check the result_disable configuration instead
4366
                        //$visible_return = $exercise_obj->is_visible();
4367
4368
                        if ($exercise_data['results_disabled'] == 0 || $exercise_data['results_disabled'] == 2) {
4369
4370
                            $best_average = intval(
4371
                                ExerciseLib::get_best_average_score_by_exercise(
4372
                                    $exercise_data['id'],
4373
                                    $course_data['id'],
4374
                                    $my_session_id,
4375
                                    $user_count
4376
                                )
4377
                            );
4378
4379
                            $exercise_graph_list[] = $best_average;
4380
                            $all_exercise_graph_list[] = $best_average;
4381
4382
                            $user_result_data = ExerciseLib::get_best_attempt_by_user(
4383
                                api_get_user_id(),
4384
                                $exercise_data['id'],
4385
                                $course_data['real_id'],
4386
                                $my_session_id
4387
                            );
4388
4389
                            $score = 0;
4390
                            if (!empty($user_result_data['exe_weighting']) && intval($user_result_data['exe_weighting']) != 0) {
4391
                                $score = intval($user_result_data['exe_result']/$user_result_data['exe_weighting'] * 100);
4392
                            }
4393
                            $time = api_strtotime($exercise_data['start_time']) ? api_strtotime($exercise_data['start_time'], 'UTC') : 0;
4394
                            $all_exercise_start_time[] = $time;
4395
                            $my_results[] = $score;
4396
                            if (count($exercise_list)<=10) {
4397
                                $title = cut($course_data['title'], 30)." \n ".cut($exercise_data['title'], 30);
4398
                                $exercise_graph_name_list[]= $title;
4399
                                $all_exercise_graph_name_list[] = $title;
4400
                            } else {
4401
                                // if there are more than 10 results, space becomes difficult to find, so only show the title of the exercise, not the tool
4402
                                $title = cut($exercise_data['title'], 30);
4403
                                $exercise_graph_name_list[]= $title;
4404
                                $all_exercise_graph_name_list[]= $title;
4405
                            }
4406
                        }
4407
                    }
4408
                }
4409
            }
4410
4411
            // Complete graph
4412
            if (!empty($my_results) && !empty($all_exercise_graph_list)) {
4413
                asort($all_exercise_start_time);
4414
4415
                //Fix exams order
4416
                $final_all_exercise_graph_name_list = array();
4417
                $my_results_final = array();
4418
                $final_all_exercise_graph_list = array();
4419
4420
                foreach ($all_exercise_start_time as $key => $time) {
4421
                    $label_time = '';
4422
                    if (!empty($time)) {
4423
                        $label_time = date('d-m-y', $time);
4424
                    }
4425
                    $final_all_exercise_graph_name_list[] = $all_exercise_graph_name_list[$key].' '.$label_time;
4426
                    $my_results_final[] = $my_results[$key];
4427
                    $final_all_exercise_graph_list[] = $all_exercise_graph_list[$key];
4428
                }
4429
                $main_session_graph = self::generate_session_exercise_graph(
4430
                    $final_all_exercise_graph_name_list,
4431
                    $my_results_final,
4432
                    $final_all_exercise_graph_list
4433
                );
4434
            }
4435
4436
            $html .= Display::page_subheader(
4437
                Display::return_icon('session.png', get_lang('Sessions'), array(), ICON_SIZE_SMALL) . ' ' . get_lang('Sessions')
4438
            );
4439
4440
            $html .= '<table class="data_table" width="100%">';
4441
            $html .= '<tr>
4442
                  '.Display::tag('th', get_lang('Session'), array('width'=>'300px')).'
4443
                  '.Display::tag('th', get_lang('PublishedExercises'), array('width'=>'300px')).'
4444
                  '.Display::tag('th', get_lang('NewExercises'), array('class'=>'head')).'
4445
                  '.Display::tag('th', get_lang('AverageExerciseResult'), array('class'=>'head')).'
4446
                  '.Display::tag('th', get_lang('Details'), array('class'=>'head')).'
4447
                  </tr>';
4448
4449
            foreach ($course_in_session as $my_session_id => $session_data) {
4450
                $course_list  = $session_data['course_list'];
4451
                $session_name = $session_data['name'];
4452
4453
                if ($showAllSessions == false) {
4454
                    if (isset($session_id) && !empty($session_id)) {
4455
                        if ($session_id != $my_session_id) {
4456
                            continue;
4457
                        }
4458
                    }
4459
                }
4460
4461
                $all_exercises = 0;
4462
                $all_unanswered_exercises_by_user = 0;
4463
                $all_average = 0;
4464
                $stats_array = array();
4465
4466
                foreach ($course_list as $course_data) {
4467
                    //All exercises in the course @todo change for a real count
4468
                    $exercises = ExerciseLib::get_all_exercises($course_data, $my_session_id);
4469
                    $count_exercises = 0;
4470
                    if (is_array($exercises) && !empty($exercises)) {
4471
                        $count_exercises = count($exercises);
4472
                    }
4473
4474
                    // Count of user results
4475
                    $done_exercises = null;
4476
                    $courseInfo = api_get_course_info($course_data['code']);
4477
4478
                    $answered_exercises = 0;
4479
                    if (!empty($exercises)) {
4480
                        foreach ($exercises as $exercise_item) {
4481
                            $attempts = Event::count_exercise_attempts_by_user(
4482
                                api_get_user_id(),
4483
                                $exercise_item['id'],
4484
                                $courseInfo['real_id'],
4485
                                $my_session_id
4486
                            );
4487
                            if ($attempts > 1)  {
4488
                                $answered_exercises++;
4489
                            }
4490
                        }
4491
                    }
4492
4493
                    // Average
4494
                    $average = ExerciseLib::get_average_score_by_course($courseInfo['real_id'], $my_session_id);
4495
                    $all_exercises += $count_exercises;
4496
                    $all_unanswered_exercises_by_user += $count_exercises - $answered_exercises;
4497
                    $all_average += $average;
4498
                }
4499
4500
                $all_average = $all_average /  count($course_list);
4501
4502
                if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) {
4503
                    $html .= '<tr style="background-color:#FBF09D">';
4504
                } else {
4505
                    $html .= '<tr>';
4506
                }
4507
                $url = api_get_path(WEB_CODE_PATH)."session/index.php?session_id={$my_session_id}";
4508
4509
                $html .= Display::tag('td', Display::url($session_name, $url, array('target'=>SESSION_LINK_TARGET)));
4510
                $html .= Display::tag('td', $all_exercises);
4511
                $html .= Display::tag('td', $all_unanswered_exercises_by_user);
4512
4513
                //$html .= Display::tag('td', $all_done_exercise);
4514
                $html .= Display::tag('td', ExerciseLib::convert_to_percentage($all_average));
4515
4516
                if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) {
4517
                    $icon = Display::url(Display::return_icon('2rightarrow_na.png', get_lang('Details')), '?session_id='.$my_session_id);
4518
                } else {
4519
                    $icon = Display::url(Display::return_icon('2rightarrow.png', get_lang('Details')), '?session_id='.$my_session_id);
4520
                }
4521
                $html .= Display::tag('td', $icon);
4522
                $html .= '</tr>';
4523
            }
4524
            $html .= '</table><br />';
4525
            $html .= Display::div($main_session_graph, array('id'=>'session_graph','class'=>'chart-session', 'style'=>'position:relative; text-align: center;') );
4526
4527
            // Checking selected session.
4528
4529
            if (isset($_GET['session_id'])) {
4530
                $session_id_from_get = intval($_GET['session_id']);
4531
                $session_data 	= $course_in_session[$session_id_from_get];
4532
                $course_list 	= $session_data['course_list'];
4533
4534
                $html .= Display::tag('h3',$session_data['name'].' - '.get_lang('CourseList'));
4535
4536
                $html .= '<table class="data_table" width="100%">';
4537
                //'.Display::tag('th', get_lang('DoneExercises'),         array('class'=>'head')).'
4538
                $html .= '
4539
                    <tr>
4540
                      <th width="300px">'.get_lang('Course').'</th>
4541
                      '.Display::tag('th', get_lang('PublishedExercises'),    	array('class'=>'head')).'
4542
                      '.Display::tag('th', get_lang('NewExercises'),    		array('class'=>'head')).'
4543
                      '.Display::tag('th', get_lang('MyAverage'), 				array('class'=>'head')).'
4544
                      '.Display::tag('th', get_lang('AverageExerciseResult'), 	array('class'=>'head')).'
4545
                      '.Display::tag('th', get_lang('TimeSpentInTheCourse'),    array('class'=>'head')).'
4546
                      '.Display::tag('th', get_lang('LPProgress')     ,      	array('class'=>'head')).'
4547
                      '.Display::tag('th', get_lang('Score').Display::return_icon('info3.gif', get_lang('ScormAndLPTestTotalAverage'), array ('align' => 'absmiddle', 'hspace' => '3px')), array('class'=>'head')).'
4548
                      '.Display::tag('th', get_lang('LastConnexion'),         	array('class'=>'head')).'
4549
                      '.Display::tag('th', get_lang('Details'),               	array('class'=>'head')).'
4550
                    </tr>';
4551
4552
                foreach ($course_list as $course_data) {
4553
                    $course_code  = $course_data['code'];
4554
                    $course_title = $course_data['title'];
4555
                    $courseInfo = api_get_course_info($course_code);
4556
                    $courseId = $courseInfo['real_id'];
4557
4558
                    // All exercises in the course @todo change for a real count
4559
                    $exercises = ExerciseLib::get_all_exercises($course_data, $session_id_from_get);
4560
                    $count_exercises = 0;
4561
                    if (!empty($exercises)) {
4562
                        $count_exercises = count($exercises);
4563
                    }
4564
                    $answered_exercises = 0;
4565
                    foreach($exercises as $exercise_item) {
4566
                        $attempts = Event::count_exercise_attempts_by_user(
4567
                            api_get_user_id(),
4568
                            $exercise_item['id'],
4569
                            $courseId,
4570
                            $session_id_from_get
4571
                        );
4572
                        if ($attempts > 1)  {
4573
                            $answered_exercises++;
4574
                        }
4575
                    }
4576
4577
                    $unanswered_exercises = $count_exercises - $answered_exercises;
4578
4579
                    // Average
4580
                    $average = ExerciseLib::get_average_score_by_course($courseId, $session_id_from_get);
4581
                    $my_average	= ExerciseLib::get_average_score_by_course_by_user(api_get_user_id(), $courseId, $session_id_from_get);
4582
4583
                    $stats_array[$course_code] = array(
4584
                        'exercises' => $count_exercises,
4585
                        'unanswered_exercises_by_user' => $unanswered_exercises,
4586
                        'done_exercises' => $done_exercises,
4587
                        'average' => $average,
4588
                        'my_average' => $my_average
4589
                    );
4590
4591
                    $last_connection = Tracking:: get_last_connection_date_on_the_course(
4592
                        $user_id,
4593
                        $courseInfo,
4594
                        $session_id_from_get
4595
                    );
4596
4597
                    $progress = Tracking::get_avg_student_progress(
4598
                        $user_id,
4599
                        $course_code,
4600
                        array(),
4601
                        $session_id_from_get
4602
                    );
4603
4604
                    $total_time_login = Tracking:: get_time_spent_on_the_course(
4605
                        $user_id,
4606
                        $courseId,
4607
                        $session_id_from_get
4608
                    );
4609
                    $time = api_time_to_hms($total_time_login);
4610
4611
                    $percentage_score = Tracking::get_avg_student_score(
4612
                        $user_id,
4613
                        $course_code,
4614
                        array(),
4615
                        $session_id_from_get
4616
                    );
4617
                    $courseCodeFromGet = isset($_GET['course']) ? $_GET['course'] : null;
4618
4619
                    if ($course_code == $courseCodeFromGet && $_GET['session_id'] == $session_id_from_get) {
4620
                        $html .= '<tr class="row_odd" style="background-color:#FBF09D" >';
4621
                    } else {
4622
                        $html .= '<tr class="row_even">';
4623
                    }
4624
4625
                    $url = api_get_course_url($course_code, $session_id_from_get);
4626
                    $course_url = Display::url($course_title, $url, array('target' => SESSION_LINK_TARGET));
4627
4628
                    $html .= Display::tag('td', $course_url);
4629
                    $html .= Display::tag('td', $stats_array[$course_code]['exercises']);
4630
                    $html .= Display::tag('td', $stats_array[$course_code]['unanswered_exercises_by_user']);
4631
                    //$html .= Display::tag('td', $stats_array[$course_code]['done_exercises']);
4632
                    $html .= Display::tag('td', ExerciseLib::convert_to_percentage($stats_array[$course_code]['my_average']));
4633
4634
                    $html .= Display::tag('td', $stats_array[$course_code]['average'] == 0 ? '-' : '('.ExerciseLib::convert_to_percentage($stats_array[$course_code]['average']).')');
4635
                    $html .= Display::tag('td', $time, array('align'=>'center'));
4636
4637
                    if (is_numeric($progress)) {
4638
                        $progress = $progress.'%';
4639
                    } else {
4640
                        $progress = '0%';
4641
                    }
4642
                    // Progress
4643
                    $html .= Display::tag('td', $progress, array('align'=>'center'));
4644
                    if (is_numeric($percentage_score)) {
4645
                        $percentage_score = $percentage_score.'%';
4646
                    } else {
4647
                        $percentage_score = '0%';
4648
                    }
4649
                    //Score
4650
                    $html .= Display::tag('td', $percentage_score, array('align'=>'center'));
4651
                    $html .= Display::tag('td', $last_connection,  array('align'=>'center'));
0 ignored issues
show
Bug introduced by
It seems like $last_connection defined by \Tracking::get_last_conn..., $session_id_from_get) on line 4591 can also be of type boolean; however, Display::tag() does only seem to accept string, 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...
4652
4653
                    if ($course_code == $courseCodeFromGet && $_GET['session_id'] == $session_id_from_get) {
4654
                        $details = '<a href="#">';
4655
                        $details .=Display::return_icon('2rightarrow_na.png', get_lang('Details'));
4656 View Code Duplication
                    } else {
4657
                        $details = '<a href="'.api_get_self().'?course='.$course_code.'&session_id='.$session_id_from_get.$extra_params.'">';
4658
                        $details .= Display::return_icon('2rightarrow.png', get_lang('Details'));
4659
                    }
4660
                    $details .= '</a>';
4661
                    $html .= Display::tag('td', $details, array('align'=>'center'));
4662
                    $html .= '</tr>';
4663
                }
4664
                $html .= '</table>';
4665
            }
4666
        }
4667
4668
        return $html;
4669
    }
4670
4671
    /**
4672
     * Shows the user detail progress (when clicking in the details link)
4673
     * @param   int     $user_id
4674
     * @param   string  $course_code
4675
     * @param   int     $session_id
4676
     * @return  string  html code
4677
     */
4678
    public static function show_course_detail($user_id, $course_code, $session_id)
4679
    {
4680
        $html = '';
4681
        if (isset($course_code)) {
4682
4683
            $user_id = intval($user_id);
4684
            $session_id = intval($session_id);
4685
            $course = Database::escape_string($course_code);
4686
            $course_info = CourseManager::get_course_information($course);
4687
4688
            $html .= Display::page_subheader($course_info['title']);
4689
            $html .= '<table class="data_table" width="100%">';
4690
4691
            //Course details
4692
            $html .= '
4693
                <tr>
4694
                <th class="head" style="color:#000">'.get_lang('Exercises').'</th>
4695
                <th class="head" style="color:#000">'.get_lang('Attempts').'</th>
4696
                <th class="head" style="color:#000">'.get_lang('BestAttempt').'</th>
4697
                <th class="head" style="color:#000">'.get_lang('Ranking').'</th>
4698
                <th class="head" style="color:#000">'.get_lang('BestResultInCourse').'</th>
4699
                <th class="head" style="color:#000">'.get_lang('Statistics').' '.Display :: return_icon('info3.gif', get_lang('OnlyBestResultsPerStudent'), array('align' => 'absmiddle', 'hspace' => '3px')).'</th>
4700
                </tr>';
4701
4702
            if (empty($session_id)) {
4703
                $user_list = CourseManager::get_user_list_from_course_code(
4704
                    $course,
4705
                    $session_id,
4706
                    null,
4707
                    null,
4708
                    STUDENT
4709
                );
4710
            } else {
4711
                $user_list = CourseManager::get_user_list_from_course_code(
4712
                    $course,
4713
                    $session_id,
4714
                    null,
4715
                    null,
4716
                    0
4717
                );
4718
            }
4719
4720
            // Show exercise results of invisible exercises? see BT#4091
4721
            $exercise_list = ExerciseLib::get_all_exercises(
4722
                $course_info,
4723
                $session_id,
4724
                false,
4725
                null,
4726
                false,
4727
                2
4728
            );
4729
4730
            $to_graph_exercise_result = array();
4731
4732
            if (!empty($exercise_list)) {
4733
                $score = $weighting = $exe_id = 0;
4734
                foreach ($exercise_list as $exercices) {
4735
4736
                    $exercise_obj = new Exercise($course_info['real_id']);
4737
                    $exercise_obj->read($exercices['id']);
4738
                    $visible_return = $exercise_obj->is_visible();
4739
4740
                    $score = $weighting = $attempts = 0;
4741
4742
                    // Getting count of attempts by user
4743
                    $attempts = Event::count_exercise_attempts_by_user(
4744
                        api_get_user_id(),
4745
                        $exercices['id'],
4746
                        $course_info['real_id'],
4747
                        $session_id
4748
                    );
4749
4750
                    $html .= '<tr class="row_even">';
4751
                    $url = api_get_path(WEB_CODE_PATH)."exercice/overview.php?cidReq={$course_info['code']}&id_session=$session_id&exerciseId={$exercices['id']}";
4752
4753
                    if ($visible_return['value'] == true) {
4754
                        $exercices['title'] = Display::url(
4755
                            $exercices['title'],
4756
                            $url,
4757
                            array('target' => SESSION_LINK_TARGET)
4758
                        );
4759
                    }
4760
4761
                    $html .= Display::tag('td', $exercices['title']);
4762
4763
                    // Exercise configuration show results or show only score
4764
                    if ($exercices['results_disabled'] == 0 || $exercices['results_disabled'] == 2) {
4765
                        //For graphics
4766
                        $best_exercise_stats = Event::get_best_exercise_results_by_user(
4767
                            $exercices['id'],
4768
                            $course_info['real_id'],
4769
                            $session_id
4770
                        );
4771
4772
                        $to_graph_exercise_result[$exercices['id']] = array(
4773
                            'title' => $exercices['title'],
4774
                            'data' => $best_exercise_stats
4775
                        );
4776
4777
                        $latest_attempt_url = '';
4778
                        $best_score = $position = $percentage_score_result  = '-';
4779
                        $graph = $normal_graph = null;
4780
4781
                        // Getting best results
4782
                        $best_score_data = ExerciseLib::get_best_attempt_in_course(
4783
                            $exercices['id'],
4784
                            $course_info['real_id'],
4785
                            $session_id
4786
                        );
4787
4788
                        $best_score = '';
4789
                        if (!empty($best_score_data)) {
4790
                            $best_score = ExerciseLib::show_score(
4791
                                $best_score_data['exe_result'],
4792
                                $best_score_data['exe_weighting']
4793
                            );
4794
                        }
4795
4796
                        if ($attempts > 0) {
4797
                            $exercise_stat = ExerciseLib::get_best_attempt_by_user(
4798
                                api_get_user_id(),
4799
                                $exercices['id'],
4800
                                $course_info['real_id'],
4801
                                $session_id
4802
                            );
4803
                            if (!empty($exercise_stat)) {
4804
4805
                                // Always getting the BEST attempt
4806
                                $score          = $exercise_stat['exe_result'];
4807
                                $weighting      = $exercise_stat['exe_weighting'];
4808
                                $exe_id         = $exercise_stat['exe_id'];
4809
4810
                                $latest_attempt_url .= api_get_path(WEB_CODE_PATH).'exercice/result.php?id='.$exe_id.'&cidReq='.$course_info['code'].'&show_headers=1&id_session='.$session_id;
4811
                                $percentage_score_result = Display::url(ExerciseLib::show_score($score, $weighting), $latest_attempt_url);
4812
                                $my_score = 0;
4813
                                if (!empty($weighting) && intval($weighting) != 0) {
4814
                                    $my_score = $score/$weighting;
4815
                                }
4816
                                //@todo this function slows the page
4817
                                $position = ExerciseLib::get_exercise_result_ranking($my_score, $exe_id, $exercices['id'], $course_info['code'], $session_id, $user_list);
0 ignored issues
show
Bug introduced by
It seems like $user_list can also be of type integer; however, ExerciseLib::get_exercise_result_ranking() 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...
4818
4819
                                $graph = self::generate_exercise_result_thumbnail_graph($to_graph_exercise_result[$exercices['id']]);
4820
                                $normal_graph = self::generate_exercise_result_graph($to_graph_exercise_result[$exercices['id']]);
4821
                            }
4822
                        }
4823
                        $html .= Display::div(
4824
                            $normal_graph,
4825
                            array('id'=>'main_graph_'.$exercices['id'],'class'=>'dialog', 'style'=>'display:none')
4826
                        );
4827
4828
                        if (empty($graph)) {
4829
                            $graph = '-';
4830
                        } else {
4831
                            $graph = Display::url(
4832
                                '<img src="' . $graph . '" >',
4833
                                $normal_graph,
4834
                                array(
4835
                                    'id' => $exercices['id'],
4836
                                    'class' => 'expand-image',
4837
                                )
4838
                            );
4839
                        }
4840
4841
                        $html .= Display::tag('td', $attempts, array('align'=>'center'));
4842
                        $html .= Display::tag('td', $percentage_score_result, array('align'=>'center'));
4843
                        $html .= Display::tag('td', $position, array('align'=>'center'));
4844
                        $html .= Display::tag('td', $best_score, array('align'=>'center'));
4845
                        $html .= Display::tag('td', $graph, array('align'=>'center'));
4846
                        //$html .= Display::tag('td', $latest_attempt_url,       array('align'=>'center', 'width'=>'25'));
4847
4848
                    } else {
4849
                        // Exercise configuration NO results
4850
                        $html .= Display::tag('td', $attempts, array('align'=>'center'));
4851
                        $html .= Display::tag('td', '-', array('align'=>'center'));
4852
                        $html .= Display::tag('td', '-', array('align'=>'center'));
4853
                        $html .= Display::tag('td', '-', array('align'=>'center'));
4854
                        $html .= Display::tag('td', '-', array('align'=>'center'));
4855
                    }
4856
                    $html .= '</tr>';
4857
                }
4858
            } else {
4859
                $html .= '<tr><td colspan="5" align="center">'.get_lang('NoEx').'</td></tr>';
4860
            }
4861
            $html .= '</table>';
4862
4863
4864
            // LP table results
4865
            $html .='<table class="data_table">';
4866
            $html .= Display::tag('th', get_lang('Learnpaths'), array('class'=>'head', 'style'=>'color:#000'));
4867
            $html .= Display::tag('th', get_lang('LatencyTimeSpent'), array('class'=>'head', 'style'=>'color:#000'));
4868
            $html .= Display::tag('th', get_lang('Progress'), array('class'=>'head', 'style'=>'color:#000'));
4869
            $html .= Display::tag('th', get_lang('Score'), array('class'=>'head', 'style'=>'color:#000'));
4870
            $html .= Display::tag('th', get_lang('LastConnexion'), array('class'=>'head', 'style'=>'color:#000'));
4871
            $html .= '</tr>';
4872
4873
            $list = new LearnpathList(
4874
                api_get_user_id(),
4875
                $course_info['code'],
4876
                $session_id,
4877
                'publicated_on ASC',
4878
                true,
4879
                null,
4880
                true
4881
            );
4882
4883
            $lp_list = $list->get_flat_list();
4884
4885
            if (!empty($lp_list) > 0) {
4886
                foreach ($lp_list as $lp_id => $learnpath) {
4887
                    $progress = Tracking::get_avg_student_progress($user_id, $course, array($lp_id), $session_id);
4888
                    $last_connection_in_lp = Tracking::get_last_connection_time_in_lp($user_id, $course, $lp_id, $session_id);
4889
                    $time_spent_in_lp = Tracking::get_time_spent_in_lp($user_id, $course, array($lp_id), $session_id);
4890
                    $percentage_score = Tracking::get_avg_student_score($user_id, $course, array($lp_id), $session_id);
4891
                    if (is_numeric($percentage_score)) {
4892
                        $percentage_score = $percentage_score.'%';
4893
                    } else {
4894
                        $percentage_score = '0%';
4895
                    }
4896
4897
                    $time_spent_in_lp = api_time_to_hms($time_spent_in_lp);
4898
4899
                    $html .= '<tr class="row_even">';
4900
                    $url = api_get_path(WEB_CODE_PATH)."newscorm/lp_controller.php?cidReq={$course_code}&id_session=$session_id&lp_id=$lp_id&action=view";
4901
4902
                    if ($learnpath['lp_visibility'] == 0) {
4903
                        $html .= Display::tag('td', $learnpath['lp_name']);
4904
                    } else {
4905
                        $html .= Display::tag('td', Display::url($learnpath['lp_name'], $url, array('target'=>SESSION_LINK_TARGET)));
4906
                    }
4907
4908
                    $html .= Display::tag('td', $time_spent_in_lp, array('align'=>'center'));
4909
                    if (is_numeric($progress)) {
4910
                        $progress = $progress.'%';
4911
                    }
4912
                    $html .= Display::tag('td', $progress, array('align'=>'center'));
4913
                    $html .= Display::tag('td', $percentage_score);
4914
4915
                    $last_connection = '-';
4916
                    if (!empty($last_connection_in_lp)) {
4917
                        $last_connection = api_convert_and_format_date($last_connection_in_lp, DATE_TIME_FORMAT_LONG);
4918
                    }
4919
                    $html .= Display::tag('td', $last_connection, array('align'=>'center','width'=>'180px'));
4920
                    $html .= "</tr>";
4921
                }
4922
            } else {
4923
                $html .= '<tr>
4924
                        <td colspan="4" align="center">
4925
                            '.get_lang('NoLearnpath').'
4926
                        </td>
4927
                      </tr>';
4928
            }
4929
            $html .='</table>';
4930
        }
4931
4932
        return $html;
4933
    }
4934
4935
    /**
4936
     * Generates an histogram
4937
     * @param    array    list of exercise names
4938
     * @param    array    my results 0 to 100
4939
     * @param    array    average scores 0-100
4940
     * @return string
4941
     */
4942
    static function generate_session_exercise_graph($names, $my_results, $average)
4943
    {
4944
        /* Create and populate the pData object */
4945
        $myData = new pData();
4946
        $myData->addPoints($names, 'Labels');
4947
        $myData->addPoints($my_results, 'Serie1');
4948
        $myData->addPoints($average, 'Serie2');
4949
        $myData->setSerieWeight('Serie1', 1);
4950
        $myData->setSerieTicks('Serie2', 4);
4951
        $myData->setSerieDescription('Labels', 'Months');
4952
        $myData->setAbscissa('Labels');
4953
        $myData->setSerieDescription('Serie1', get_lang('MyResults'));
4954
        $myData->setSerieDescription('Serie2', get_lang('AverageScore'));
4955
        $myData->setAxisUnit(0, '%');
4956
        $myData->loadPalette(api_get_path(SYS_CODE_PATH) . 'palettes/pchart/default.color', true);
4957
        // Cache definition
4958
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
4959
        $myCache = new pCache(array('CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)));
4960
        $chartHash = $myCache->getHash($myData);
4961
4962
        if ($myCache->isInCache($chartHash)) {
4963
            //if we already created the img
4964
            $imgPath = api_get_path(SYS_ARCHIVE_PATH) . $chartHash;
4965
            $myCache->saveFromCache($chartHash, $imgPath);
4966
            $imgPath = api_get_path(WEB_ARCHIVE_PATH) . $chartHash;
4967
        } else {
4968
            /* Define width, height and angle */
4969
            $mainWidth = 860;
4970
            $mainHeight = 500;
4971
            $angle = 50;
4972
4973
            /* Create the pChart object */
4974
            $myPicture = new pImage($mainWidth, $mainHeight, $myData);
4975
4976
            /* Turn of Antialiasing */
4977
            $myPicture->Antialias = false;
4978
4979
            /* Draw the background */
4980
            $settings = array('R' => 255, 'G' => 255, 'B' => 255);
4981
            $myPicture->drawFilledRectangle(0, 0, $mainWidth, $mainHeight, $settings);
4982
4983
            /* Add a border to the picture */
4984
            $myPicture->drawRectangle(
4985
                0,
4986
                0,
4987
                $mainWidth - 1,
4988
                $mainHeight - 1,
4989
                array('R' => 0, 'G' => 0, 'B' => 0)
4990
            );
4991
4992
            /* Set the default font */
4993
            $myPicture->setFontProperties(
4994
                array(
4995
                    'FontName' => api_get_path(SYS_FONTS_PATH) . 'opensans/OpenSans-Regular.ttf',
4996
                    'FontSize' => 10)
4997
            );
4998
            /* Write the chart title */
4999
            $myPicture->drawText(
5000
                $mainWidth / 2,
5001
                30,
5002
                get_lang('ExercisesInTimeProgressChart'),
5003
                array(
5004
                    'FontSize' => 12,
5005
                    'Align' => TEXT_ALIGN_BOTTOMMIDDLE
5006
                )
5007
            );
5008
5009
            /* Set the default font */
5010
            $myPicture->setFontProperties(
5011
                array(
5012
                    'FontName' => api_get_path(SYS_FONTS_PATH) . 'opensans/OpenSans-Regular.ttf',
5013
                    'FontSize' => 6
5014
                )
5015
            );
5016
5017
            /* Define the chart area */
5018
            $myPicture->setGraphArea(60, 60, $mainWidth - 60, $mainHeight - 150);
5019
5020
            /* Draw the scale */
5021
            $scaleSettings = array(
5022
                'XMargin' => 10,
5023
                'YMargin' => 10,
5024
                'Floating' => true,
5025
                'GridR' => 200,
5026
                'GridG' => 200,
5027
                'GridB' => 200,
5028
                'DrawSubTicks' => true,
5029
                'CycleBackground' => true,
5030
                'LabelRotation' => $angle,
5031
                'Mode' => SCALE_MODE_ADDALL_START0,
5032
            );
5033
            $myPicture->drawScale($scaleSettings);
5034
5035
            /* Turn on Antialiasing */
5036
            $myPicture->Antialias = true;
5037
5038
            /* Enable shadow computing */
5039
            $myPicture->setShadow(
5040
                true,
5041
                array(
5042
                    'X' => 1,
5043
                    'Y' => 1,
5044
                    'R' => 0,
5045
                    'G' => 0,
5046
                    'B' => 0,
5047
                    'Alpha' => 10
5048
                )
5049
            );
5050
5051
            /* Draw the line chart */
5052
            $myPicture->setFontProperties(
5053
                array(
5054
                    'FontName' => api_get_path(SYS_FONTS_PATH) . 'opensans/OpenSans-Regular.ttf',
5055
                    'FontSize' => 10
5056
                )
5057
            );
5058
            $myPicture->drawSplineChart();
5059
            $myPicture->drawPlotChart(
5060
                array(
5061
                    'DisplayValues' => true,
5062
                    'PlotBorder' => true,
5063
                    'BorderSize' => 1,
5064
                    'Surrounding' => -60,
5065
                    'BorderAlpha' => 80
5066
                )
5067
            );
5068
5069
            /* Write the chart legend */
5070
            $myPicture->drawLegend(
5071
                $mainWidth / 2 + 50,
5072
                50,
5073
                array(
5074
                    'Style' => LEGEND_BOX,
5075
                    'Mode' => LEGEND_HORIZONTAL,
5076
                    'FontR' => 0,
5077
                    'FontG' => 0,
5078
                    'FontB' => 0,
5079
                    'R' => 220,
5080
                    'G' => 220,
5081
                    'B' => 220,
5082
                    'Alpha' => 100
5083
                )
5084
            );
5085
5086
            $myCache->writeToCache($chartHash, $myPicture);
5087
            $imgPath = api_get_path(SYS_ARCHIVE_PATH) . $chartHash;
5088
            $myCache->saveFromCache($chartHash, $imgPath);
5089
            $imgPath = api_get_path(WEB_ARCHIVE_PATH) . $chartHash;
5090
        }
5091
5092
        $html = '<img src="' . $imgPath . '">';
5093
5094
        return $html;
5095
    }
5096
5097
    /**
5098
     *
5099
     * Returns a thumbnail of the function generate_exercise_result_graph
5100
     * @param  array $attempts
5101
     */
5102
    static function generate_exercise_result_thumbnail_graph($attempts)
5103
    {
5104
        //$exercise_title = $attempts['title'];
5105
        $attempts = $attempts['data'];
5106
        $my_exercise_result_array = $exercise_result = array();
5107
        if (empty($attempts)) {
5108
            return null;
5109
        }
5110
5111 View Code Duplication
        foreach ($attempts as $attempt) {
5112
            if (api_get_user_id() == $attempt['exe_user_id']) {
5113
                if ($attempt['exe_weighting'] != 0 ) {
5114
                    $my_exercise_result_array[]= $attempt['exe_result']/$attempt['exe_weighting'];
5115
                }
5116
            } else {
5117
                if ($attempt['exe_weighting'] != 0 ) {
5118
                    $exercise_result[]=  $attempt['exe_result']/$attempt['exe_weighting'];
5119
                }
5120
            }
5121
        }
5122
5123
        //Getting best result
5124
        rsort($my_exercise_result_array);
5125
        $my_exercise_result = 0;
5126
        if (isset($my_exercise_result_array[0])) {
5127
            $my_exercise_result = $my_exercise_result_array[0] *100;
5128
        }
5129
5130
        $max     = 100;
5131
        $pieces  = 5 ;
5132
        $part    = round($max / $pieces);
5133
        $x_axis = array();
5134
        $final_array = array();
5135
        $my_final_array = array();
5136
5137 View Code Duplication
        for ($i=1; $i <=$pieces; $i++) {
5138
            $sum = 1;
5139
            if ($i == 1) {
5140
                $sum = 0;
5141
            }
5142
            $min = ($i-1)*$part + $sum;
5143
            $max = ($i)*$part;
5144
            $x_axis[]= $min." - ".$max;
5145
            $count = 0;
5146
            foreach($exercise_result as $result) {
5147
                $percentage = $result*100;
5148
                //echo $percentage.' - '.$min.' - '.$max."<br />";
5149
                if ($percentage >= $min && $percentage <= $max) {
5150
                    //echo ' is > ';
5151
                    $count++;
5152
                }
5153
            }
5154
            //echo '<br />';
5155
            $final_array[]= $count;
5156
5157
            if ($my_exercise_result >= $min && $my_exercise_result <= $max) {
5158
                $my_final_array[] = 1;
5159
            } else {
5160
                $my_final_array[] = 0;
5161
            }
5162
        }
5163
5164
        //Fix to remove the data of the user with my data
5165 View Code Duplication
        for($i = 0; $i<=count($my_final_array); $i++) {
5166
            if (!empty($my_final_array[$i])) {
5167
                $my_final_array[$i] =  $final_array[$i] + 1; //Add my result
5168
                $final_array[$i] = 0;
5169
            }
5170
        }
5171
5172
        // Dataset definition
5173
        $dataSet = new pData();
5174
        $dataSet->addPoints($final_array, 'Serie1');
5175
        $dataSet->addPoints($my_final_array, 'Serie2');
5176
        $dataSet->normalize(100, "%");
5177
        $dataSet->loadPalette(api_get_path(SYS_CODE_PATH) . 'palettes/pchart/default.color', true);
5178
5179
        // Cache definition
5180
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
5181
        $myCache = new pCache(array('CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)));
5182
        $chartHash = $myCache->getHash($dataSet);
5183
        if ($myCache->isInCache($chartHash)) {
5184
            $imgPath = api_get_path(SYS_ARCHIVE_PATH) . $chartHash;
5185
            $myCache->saveFromCache($chartHash, $imgPath);
5186
            $imgPath = api_get_path(WEB_ARCHIVE_PATH) . $chartHash;
5187
        } else {
5188
            /* Create the pChart object */
5189
            $widthSize = 80;
5190
            $heightSize = 35;
5191
            $fontSize = 2;
5192
5193
            $myPicture = new pImage($widthSize, $heightSize, $dataSet);
5194
5195
            /* Turn of Antialiasing */
5196
            $myPicture->Antialias = false;
5197
5198
            /* Add a border to the picture */
5199
            $myPicture->drawRectangle(0, 0, $widthSize - 1, $heightSize - 1, array('R' => 0, 'G' => 0, 'B' => 0));
5200
5201
            /* Set the default font */
5202
            $myPicture->setFontProperties(array('FontName' => api_get_path(SYS_FONTS_PATH) . 'opensans/OpenSans-Regular.ttf', 'FontSize' => $fontSize));
5203
5204
            /* Do not write the chart title */
5205
5206
            /* Define the chart area */
5207
            $myPicture->setGraphArea(5, 5, $widthSize - 5, $heightSize - 5);
5208
5209
            /* Draw the scale */
5210
            $scaleSettings = array(
5211
                'GridR' => 200,
5212
                'GridG' => 200,
5213
                'GridB' => 200,
5214
                'DrawSubTicks' => true,
5215
                'CycleBackground' => true,
5216
                'Mode' => SCALE_MODE_MANUAL,
5217
                'ManualScale' => array(
5218
                    '0' => array(
5219
                        'Min' => 0,
5220
                        'Max' => 100
5221
                    )
5222
                )
5223
            );
5224
            $myPicture->drawScale($scaleSettings);
5225
5226
            /* Turn on shadow computing */
5227
            $myPicture->setShadow(
5228
                true,
5229
                array(
5230
                    'X' => 1,
5231
                    'Y' => 1,
5232
                    'R' => 0,
5233
                    'G' => 0,
5234
                    'B' => 0,
5235
                    'Alpha' => 10
5236
                )
5237
            );
5238
5239
            /* Draw the chart */
5240
            $myPicture->setShadow(
5241
                true,
5242
                array(
5243
                    'X' => 1,
5244
                    'Y' => 1,
5245
                    'R' => 0,
5246
                    'G' => 0,
5247
                    'B' => 0,
5248
                    'Alpha' => 10
5249
                )
5250
            );
5251
            $settings = array(
5252
                'DisplayValues' => true,
5253
                'DisplaySize' => $fontSize,
5254
                'DisplayR' => 0,
5255
                'DisplayG' => 0,
5256
                'DisplayB' => 0,
5257
                'DisplayOrientation' => ORIENTATION_HORIZONTAL,
5258
                'Gradient' => false,
5259
                'Surrounding' => 5,
5260
                'InnerSurrounding' => 5
5261
            );
5262
            $myPicture->drawStackedBarChart($settings);
5263
5264
            /* Save and write in cache */
5265
            $myCache->writeToCache($chartHash, $myPicture);
5266
            $imgPath = api_get_path(SYS_ARCHIVE_PATH) . $chartHash;
5267
            $myCache->saveFromCache($chartHash, $imgPath);
5268
            $imgPath = api_get_path(WEB_ARCHIVE_PATH) . $chartHash;
5269
        }
5270
5271
        return $imgPath;
5272
    }
5273
5274
    /**
5275
     * Generates a big graph with the number of best results
5276
     * @param	array
5277
     */
5278
    static function generate_exercise_result_graph($attempts)
5279
    {
5280
        $exercise_title = strip_tags($attempts['title']);
5281
        $attempts       = $attempts['data'];
5282
        $my_exercise_result_array = $exercise_result = array();
5283
        if (empty($attempts)) {
5284
            return null;
5285
        }
5286 View Code Duplication
        foreach ($attempts as $attempt) {
5287
            if (api_get_user_id() == $attempt['exe_user_id']) {
5288
                if ($attempt['exe_weighting'] != 0 ) {
5289
                    $my_exercise_result_array[]= $attempt['exe_result']/$attempt['exe_weighting'];
5290
                }
5291
            } else {
5292
                if ($attempt['exe_weighting'] != 0 ) {
5293
                    $exercise_result[]=  $attempt['exe_result']/$attempt['exe_weighting'];
5294
                }
5295
            }
5296
        }
5297
5298
        //Getting best result
5299
        rsort($my_exercise_result_array);
5300
        $my_exercise_result = 0;
5301
        if (isset($my_exercise_result_array[0])) {
5302
            $my_exercise_result = $my_exercise_result_array[0] *100;
5303
        }
5304
5305
        $max = 100;
5306
        $pieces = 5 ;
5307
        $part = round($max / $pieces);
5308
        $x_axis = array();
5309
        $final_array = array();
5310
        $my_final_array = array();
5311
5312 View Code Duplication
        for ($i=1; $i <=$pieces; $i++) {
5313
            $sum = 1;
5314
            if ($i == 1) {
5315
                $sum = 0;
5316
            }
5317
            $min = ($i-1)*$part + $sum;
5318
            $max = ($i)*$part;
5319
            $x_axis[]= $min." - ".$max;
5320
            $count = 0;
5321
            foreach($exercise_result as $result) {
5322
                $percentage = $result*100;
5323
                if ($percentage >= $min && $percentage <= $max) {
5324
                    $count++;
5325
                }
5326
            }
5327
            $final_array[]= $count;
5328
5329
            if ($my_exercise_result >= $min && $my_exercise_result <= $max) {
5330
                $my_final_array[] = 1;
5331
            } else {
5332
                $my_final_array[] = 0;
5333
            }
5334
        }
5335
5336
        //Fix to remove the data of the user with my data
5337
5338 View Code Duplication
        for($i = 0; $i<=count($my_final_array); $i++) {
5339
            if (!empty($my_final_array[$i])) {
5340
                $my_final_array[$i] =  $final_array[$i] + 1; //Add my result
5341
                $final_array[$i] = 0;
5342
            }
5343
        }
5344
5345
        // Dataset definition
5346
        $dataSet = new pData();
5347
        $dataSet->addPoints($final_array, 'Serie1');
5348
        $dataSet->addPoints($my_final_array, 'Serie2');
5349
        $dataSet->addPoints($x_axis, 'Serie3');
5350
5351
        $dataSet->setSerieDescription('Serie1', get_lang('Score'));
5352
        $dataSet->setSerieDescription('Serie2', get_lang('MyResults'));
5353
        $dataSet->setAbscissa('Serie3');
5354
5355
        $dataSet->setXAxisName(get_lang('Score'));
5356
        $dataSet->normalize(100, "%");
5357
5358
        $dataSet->loadPalette(api_get_path(SYS_CODE_PATH) . 'palettes/pchart/default.color', true);
5359
5360
        // Cache definition
5361
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
5362
        $myCache = new pCache(array('CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)));
5363
        $chartHash = $myCache->getHash($dataSet);
5364
5365
        if ($myCache->isInCache($chartHash)) {
5366
            $imgPath = api_get_path(SYS_ARCHIVE_PATH) . $chartHash;
5367
            $myCache->saveFromCache($chartHash, $imgPath);
5368
            $imgPath = api_get_path(WEB_ARCHIVE_PATH) . $chartHash;
5369
        } else {
5370
            /* Create the pChart object */
5371
            $widthSize = 480;
5372
            $heightSize = 250;
5373
            $fontSize = 8;
5374
5375
            $myPicture = new pImage($widthSize, $heightSize, $dataSet);
5376
5377
            /* Turn of Antialiasing */
5378
            $myPicture->Antialias = false;
5379
5380
            /* Add a border to the picture */
5381
            $myPicture->drawRectangle(0, 0, $widthSize - 1, $heightSize - 1, array('R' => 0, 'G' => 0, 'B' => 0));
5382
5383
            /* Set the default font */
5384
            $myPicture->setFontProperties(array('FontName' => api_get_path(SYS_FONTS_PATH) . 'opensans/OpenSans-Regular.ttf', 'FontSize' => 10));
5385
5386
            /* Write the chart title */
5387
            $myPicture->drawText(
5388
                250,
5389
                20,
5390
                $exercise_title,
5391
                array(
5392
                    'FontSize' => 12,
5393
                    'Align' => TEXT_ALIGN_BOTTOMMIDDLE
5394
                )
5395
            );
5396
5397
            /* Define the chart area */
5398
            $myPicture->setGraphArea(50, 50, $widthSize - 20, $heightSize - 30);
5399
5400
            /* Draw the scale */
5401
            $scaleSettings = array(
5402
                'GridR' => 200,
5403
                'GridG' => 200,
5404
                'GridB' => 200,
5405
                'DrawSubTicks' => true,
5406
                'CycleBackground' => true,
5407
                'Mode' => SCALE_MODE_MANUAL,
5408
                'ManualScale' => array(
5409
                    '0' => array(
5410
                        'Min' => 0,
5411
                        'Max' => 100
5412
                    )
5413
                )
5414
            );
5415
            $myPicture->drawScale($scaleSettings);
5416
5417
            /* Turn on shadow computing */
5418
            $myPicture->setShadow(true, array('X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10));
5419
5420
            /* Draw the chart */
5421
            $myPicture->setShadow(true, array('X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10));
5422
            $settings = array(
5423
                'DisplayValues' => true,
5424
                'DisplaySize' => $fontSize,
5425
                'DisplayR' => 0,
5426
                'DisplayG' => 0,
5427
                'DisplayB' => 0,
5428
                'DisplayOrientation' => ORIENTATION_HORIZONTAL,
5429
                'Gradient' => false,
5430
                'Surrounding' => 30,
5431
                'InnerSurrounding' => 25
5432
            );
5433
            $myPicture->drawStackedBarChart($settings);
5434
5435
            $legendSettings = array(
5436
                'Mode' => LEGEND_HORIZONTAL,
5437
                'Style' => LEGEND_NOBORDER,
5438
            );
5439
            $myPicture->drawLegend($widthSize / 2, 30, $legendSettings);
5440
5441
            /* Write and save into cache */
5442
            $myCache->writeToCache($chartHash, $myPicture);
5443
            $imgPath = api_get_path(SYS_ARCHIVE_PATH) . $chartHash;
5444
            $myCache->saveFromCache($chartHash, $imgPath);
5445
            $imgPath = api_get_path(WEB_ARCHIVE_PATH) . $chartHash;
5446
        }
5447
5448
        return $imgPath;
5449
    }
5450
5451
    /**
5452
    * @param FormValidator $form
5453
    * @return mixed
5454
    */
5455
    public static function setUserSearchForm($form)
5456
    {
5457
        global $_configuration;
5458
        $form->addElement('text', 'keyword', get_lang('Keyword'));
5459
        $form->addElement(
5460
            'select',
5461
            'active',
5462
            get_lang('Status'),
5463
            array(1 => get_lang('Active'), 0 => get_lang('Inactive'))
5464
        );
5465
5466
        $form->addElement(
5467
            'select',
5468
            'sleeping_days',
5469
            get_lang('InactiveDays'),
5470
            array(
5471
                '',
5472
                1 => 1,
5473
                5 => 5,
5474
                15 => 15,
5475
                30 => 30,
5476
                60 => 60,
5477
                90 => 90,
5478
                120 => 120,
5479
            )
5480
        );
5481
5482
        $form->addButtonSearch(get_lang('Search'));
5483
5484
        return $form;
5485
    }
5486
5487
    /**
5488
     * Get the progress of a exercise
5489
     * @param   int $sessionId  The session ID (session.id)
5490
     * @param   int $courseId   The course ID (course.id)
5491
     * @param   int $exerciseId The quiz ID (c_quiz.id)
5492
     * @param   int $answer     The answer status (0 = incorrect, 1 = correct, 2 = both)
0 ignored issues
show
Bug introduced by
There is no parameter named $answer. 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...
5493
     * @param   array   $options    An array of options you can pass to the query (limit, where and order)
5494
     * @return array An array with the data of exercise(s) progress
5495
     */
5496
    public static function get_exercise_progress(
5497
        $sessionId = 0,
5498
        $courseId = 0,
5499
        $exerciseId = 0,
5500
        $date_from = null,
5501
        $date_to = null,
5502
        $options = array()
5503
    ) {
5504
        $sessionId  = intval($sessionId);
5505
        $courseId   = intval($courseId);
5506
        $exerciseId = intval($exerciseId);
5507
        $date_from  = Database::escape_string($date_from);
5508
        $date_to    = Database::escape_string($date_to);
5509
        /*
5510
         * This method gets the data by blocks, as previous attempts at one single
5511
         * query made it take ages. The logic of query division is described below
5512
         */
5513
        // Get tables names
5514
        $tuser = Database::get_main_table(TABLE_MAIN_USER);
5515
        $tquiz = Database::get_course_table(TABLE_QUIZ_TEST);
5516
        $tquiz_answer = Database::get_course_table(TABLE_QUIZ_ANSWER);
5517
        $tquiz_question = Database::get_course_table(TABLE_QUIZ_QUESTION);
5518
        $tquiz_rel_question = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
5519
        $ttrack_exercises  = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
5520
        $ttrack_attempt    = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
5521
5522
        $sessions = array();
5523
        $courses = array();
5524
        // if session ID is defined but course ID is empty, get all the courses
5525
        // from that session
5526
        if (!empty($sessionId) && empty($courseId)) {
5527
            // $courses is an array of course int id as index and course details hash as value
5528
            $courses = SessionManager::get_course_list_by_session_id($sessionId);
5529
            $sessions[$sessionId] = api_get_session_info($sessionId);
5530
        } elseif (empty($sessionId) && !empty($courseId)) {
5531
            // if, to the contrary, course is defined but not sessions, get the sessions that include this course
5532
            // $sessions is an array like: [0] => ('id' => 3, 'name' => 'Session 35'), [1] => () etc;
5533
            $course = api_get_course_info_by_id($courseId);
5534
            $sessionsTemp = SessionManager::get_session_by_course($courseId);
5535
            $courses[$courseId] = $course;
5536
            foreach ($sessionsTemp as $sessionItem) {
5537
                $sessions[$sessionItem['id']] = $sessionItem;
5538
            }
5539
        } elseif (!empty($courseId) && !empty($sessionId)) {
5540
            //none is empty
5541
            $course = api_get_course_info_by_id($courseId);
5542
            $courses[$courseId] = array($course['code']);
5543
            $courses[$courseId]['code'] = $course['code'];
5544
            $sessions[$sessionId] = api_get_session_info($sessionId);
5545
        } else {
5546
            //both are empty, not enough data, return an empty array
5547
            return array();
5548
        }
5549
        // Now we have two arrays of courses and sessions with enough data to proceed
5550
        // If no course could be found, we shouldn't return anything.
5551
        // Sessions can be empty (then we only return the pure-course-context results)
5552
        if (count($courses) < 1) {
5553
            return array();
5554
        }
5555
5556
        $data = array();
5557
        // The following loop is less expensive than what it seems:
5558
        // - if a course was defined, then we only loop through sessions
5559
        // - if a session was defined, then we only loop through courses
5560
        // - if a session and a course were defined, then we only loop once
5561
        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...
5562
            $where = '';
5563
            $whereParams = array();
5564
            $whereSessionParams = '';
5565
            if (count($sessions > 0)) {
5566
                foreach ($sessions as $sessionIdx => $sessionData) {
5567
                    if (!empty($sessionIdx)) {
5568
                        $whereSessionParams .= $sessionIdx.',';
5569
                    }
5570
                }
5571
                $whereSessionParams = substr($whereSessionParams,0,-1);
5572
            }
5573
5574
            if (!empty($exerciseId)) {
5575
                $exerciseId = intval($exerciseId);
5576
                $where .= ' AND q.id = %d ';
5577
                $whereParams[] = $exerciseId;
5578
            }
5579
5580
            /*
5581
             * This feature has been disabled for now, to avoid having to
5582
             * join two very large tables
5583
            //2 = show all questions (wrong and correct answered)
5584
            if ($answer != 2) {
5585
                $answer = intval($answer);
5586
                //$where .= ' AND qa.correct = %d';
5587
                //$whereParams[] = $answer;
5588
            }
5589
            */
5590
5591
            $limit = '';
5592
            if (!empty($options['limit'])) {
5593
                $limit = " LIMIT ".$options['limit'];
5594
            }
5595
5596
            if (!empty($options['where'])) {
5597
                $where .= ' AND '.Database::escape_string($options['where']);
5598
            }
5599
5600
            $order = '';
5601
            if (!empty($options['order'])) {
5602
                $order = " ORDER BY ".$options['order'];
5603
            }
5604
5605
            if (!empty($date_to) && !empty($date_from)) {
5606
                $where .= sprintf(" AND (te.start_date BETWEEN '%s 00:00:00' AND '%s 23:59:59')", $date_from, $date_to);
5607
            }
5608
5609
            $sql = "SELECT
5610
                te.session_id,
5611
                ta.id as attempt_id,
5612
                te.exe_user_id as user_id,
5613
                te.exe_id as exercise_attempt_id,
5614
                ta.question_id,
5615
                ta.answer as answer_id,
5616
                ta.tms as time,
5617
                te.exe_exo_id as quiz_id,
5618
                CONCAT ('c', q.c_id, '_e', q.id) as exercise_id,
5619
                q.title as quiz_title,
5620
                qq.description as description
5621
                FROM $ttrack_exercises te
5622
                INNER JOIN $ttrack_attempt ta ON ta.exe_id = te.exe_id
5623
                INNER JOIN $tquiz q ON q.id = te.exe_exo_id
5624
                INNER JOIN $tquiz_rel_question rq ON rq.exercice_id = q.id AND rq.c_id = q.c_id
5625
                INNER JOIN $tquiz_question qq
5626
                ON
5627
                    qq.id = rq.question_id AND
5628
                    qq.c_id = rq.c_id AND
5629
                    qq.position = rq.question_order AND
5630
                    ta.question_id = rq.question_id
5631
                WHERE
5632
                    te.c_id = $courseIdx ".(empty($whereSessionParams)?'':"AND te.session_id IN ($whereSessionParams)")."
5633
                    AND q.c_id = $courseIdx
5634
                    $where $order $limit";
5635
            $sql_query = vsprintf($sql, $whereParams);
5636
5637
            // Now browse through the results and get the data
5638
            $rs = Database::query($sql_query);
5639
            $userIds = array();
5640
            $questionIds = array();
5641
            $answerIds = array();
5642
            while ($row = Database::fetch_array($rs)) {
5643
                //only show if exercise is visible
5644
                if (api_get_item_visibility($courseData, 'quiz', $row['exercise_id'])) {
5645
                    $userIds[$row['user_id']] = $row['user_id'];
5646
                    $questionIds[$row['question_id']] = $row['question_id'];
5647
                    $answerIds[$row['question_id']][$row['answer_id']] = $row['answer_id'];
5648
                    $row['session'] = $sessions[$row['session_id']];
5649
                    $data[] = $row;
5650
                }
5651
            }
5652
            // Now fill questions data. Query all questions and answers for this test to avoid
5653
            $sqlQuestions = "SELECT tq.c_id, tq.id as question_id, tq.question, tqa.id_auto,
5654
                            tqa.answer, tqa.correct, tq.position, tqa.id_auto as answer_id
5655
                            FROM $tquiz_question tq, $tquiz_answer tqa
5656
                            WHERE
5657
                                tqa.question_id = tq.id AND
5658
                                tqa.c_id = tq.c_id AND
5659
                                tq.c_id = $courseIdx AND
5660
                                tq.id IN (".implode(',', $questionIds).")";
5661
5662
            $resQuestions = Database::query($sqlQuestions);
5663
            $answer = array();
5664
            $question = array();
5665
            while ($rowQuestion = Database::fetch_assoc($resQuestions)) {
5666
                $questionId = $rowQuestion['question_id'];
5667
                $answerId = $rowQuestion['answer_id'];
5668
                $answer[$questionId][$answerId] = array(
5669
                    'position' => $rowQuestion['position'],
5670
                    'question' => $rowQuestion['question'],
5671
                    'answer' => $rowQuestion['answer'],
5672
                    'correct' => $rowQuestion['correct']
5673
                );
5674
                $question[$questionId]['question'] = $rowQuestion['question'];
5675
            }
5676
5677
            // Now fill users data
5678
            $sqlUsers = "SELECT user_id, username, lastname, firstname
5679
                         FROM $tuser
5680
                         WHERE user_id IN (".implode(',',$userIds).")";
5681
            $resUsers = Database::query($sqlUsers);
5682
            while ($rowUser = Database::fetch_assoc($resUsers)) {
5683
                $users[$rowUser['user_id']] = $rowUser;
5684
            }
5685
5686
            foreach ($data as $id => $row) {
5687
                $rowQuestId = $row['question_id'];
5688
                $rowAnsId = $row['answer_id'];
5689
5690
                $data[$id]['session'] = $sessions[$row['session_id']]['name'];
5691
                $data[$id]['firstname'] = $users[$row['user_id']]['firstname'];
5692
                $data[$id]['lastname'] = $users[$row['user_id']]['lastname'];
5693
                $data[$id]['username'] = $users[$row['user_id']]['username'];
5694
                $data[$id]['answer'] = $answer[$rowQuestId][$rowAnsId]['answer'];
5695
                $data[$id]['correct'] = ($answer[$rowQuestId][$rowAnsId]['correct'] == 0 ? get_lang('No') : get_lang('Yes'));
5696
                $data[$id]['question'] = $question[$rowQuestId]['question'];
5697
                $data[$id]['question_id'] = $rowQuestId;
5698
                $data[$id]['description'] = $row['description'];
5699
            }
5700
            /*
5701
            The minimum expected array structure at the end is:
5702
            attempt_id,
5703
            session name,
5704
            exercise_id,
5705
            quiz_title,
5706
            username,
5707
            lastname,
5708
            firstname,
5709
            time,
5710
            question_id,
5711
            question,
5712
            answer,
5713
            */
5714
        }
5715
        return $data;
5716
    }
5717
}
5718
5719
/**
5720
 * @todo move into a proper file
5721
 * @package chamilo.tracking
5722
 */
5723
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...
5724
{
5725
    /**
5726
     * @return mixed
5727
     */
5728
    public static function count_item_resources()
5729
    {
5730
        $session_id = api_get_session_id();
5731
        $course_id = api_get_course_int_id();
5732
5733
    	$table_item_property = Database :: get_course_table(TABLE_ITEM_PROPERTY);
5734
    	$table_user = Database :: get_main_table(TABLE_MAIN_USER);
5735
5736
    	$sql = "SELECT count(tool) AS total_number_of_items
5737
    	        FROM $table_item_property track_resource, $table_user user
5738
    	        WHERE
5739
                    track_resource.c_id = $course_id AND
5740
                    track_resource.insert_user_id = user.user_id AND
5741
                    session_id " .(empty($session_id) ? ' IS NULL ' : " = $session_id ");
5742
5743
    	if (isset($_GET['keyword'])) {
5744
    		$keyword = Database::escape_string(trim($_GET['keyword']));
5745
    		$sql .= " AND (
5746
    		            user.username LIKE '%".$keyword."%' OR
5747
    		            lastedit_type LIKE '%".$keyword."%' OR
5748
    		            tool LIKE '%".$keyword."%'
5749
                    )";
5750
    	}
5751
5752
    	$sql .= " AND tool IN (
5753
    	            'document',
5754
    	            'learnpath',
5755
    	            'quiz',
5756
    	            'glossary',
5757
    	            'link',
5758
    	            'course_description',
5759
    	            'announcement',
5760
    	            'thematic',
5761
    	            'thematic_advance',
5762
    	            'thematic_plan'
5763
                )";
5764
    	$res = Database::query($sql);
5765
    	$obj = Database::fetch_object($res);
5766
5767
    	return $obj->total_number_of_items;
5768
    }
5769
5770
    /**
5771
     * @param $from
5772
     * @param $number_of_items
5773
     * @param $column
5774
     * @param $direction
5775
     * @return array
5776
     */
5777
    public static function get_item_resources_data($from, $number_of_items, $column, $direction)
5778
    {
5779
        $session_id = api_get_session_id();
5780
        $course_id = api_get_course_int_id();
5781
5782
    	$table_item_property = Database :: get_course_table(TABLE_ITEM_PROPERTY);
5783
    	$table_user = Database :: get_main_table(TABLE_MAIN_USER);
5784
    	$table_session = Database :: get_main_table(TABLE_MAIN_SESSION);
5785
    	$session_id = intval($session_id);
5786
5787
    	$sql = "SELECT
5788
                    tool as col0,
5789
                    lastedit_type as col1,
5790
                    ref as ref,
5791
                    user.username as col3,
5792
                    insert_date as col5,
5793
                    visibility as col6,
5794
                    user.user_id as user_id
5795
                FROM $table_item_property track_resource, $table_user user
5796
                WHERE
5797
                  track_resource.c_id = $course_id AND
5798
                  track_resource.insert_user_id = user.user_id AND
5799
                  session_id " .(empty($session_id) ? ' IS NULL ' : " = $session_id ");
5800
5801
    	if (isset($_GET['keyword'])) {
5802
    		$keyword = Database::escape_string(trim($_GET['keyword']));
5803
    		$sql .= " AND (
5804
    		            user.username LIKE '%".$keyword."%' OR
5805
    		            lastedit_type LIKE '%".$keyword."%' OR
5806
    		            tool LIKE '%".$keyword."%'
5807
                     ) ";
5808
    	}
5809
5810
    	$sql .= " AND tool IN (
5811
    	            'document',
5812
    	            'learnpath',
5813
    	            'quiz',
5814
    	            'glossary',
5815
    	            'link',
5816
    	            'course_description',
5817
    	            'announcement',
5818
    	            'thematic',
5819
    	            'thematic_advance',
5820
    	            'thematic_plan'
5821
                )";
5822
5823
    	if ($column == 0) {
5824
    		$column = '0';
5825
    	}
5826
    	if ($column != '' && $direction != '') {
5827
    		if ($column != 2 && $column != 4) {
5828
    			$sql .= " ORDER BY col$column $direction";
5829
    		}
5830
    	} else {
5831
    		$sql .= " ORDER BY col5 DESC ";
5832
    	}
5833
5834
        $from = intval($from);
5835
        $number_of_items = intval($number_of_items);
5836
5837
    	$sql .= " LIMIT $from, $number_of_items ";
5838
5839
    	$res = Database::query($sql);
5840
    	$resources = array();
5841
    	$thematic_tools = array('thematic', 'thematic_advance', 'thematic_plan');
5842
    	while ($row = Database::fetch_array($res)) {
5843
    		$ref = $row['ref'];
5844
    		$table_name = TrackingCourseLog::get_tool_name_table($row['col0']);
5845
    		$table_tool = Database :: get_course_table($table_name['table_name']);
5846
5847
    		$id = $table_name['id_tool'];
5848
    		$recorset = false;
5849
5850
    		if (in_array($row['col0'], array('thematic_plan', 'thematic_advance'))) {
5851
    			$tbl_thematic = Database :: get_course_table(TABLE_THEMATIC);
5852
    			$sql = "SELECT thematic_id FROM $table_tool
5853
    			        WHERE c_id = $course_id AND id = $ref";
5854
    			$rs_thematic  = Database::query($sql);
5855 View Code Duplication
    			if (Database::num_rows($rs_thematic)) {
5856
    				$row_thematic = Database::fetch_array($rs_thematic);
5857
    				$thematic_id = $row_thematic['thematic_id'];
5858
5859
                    $sql = "SELECT session.id, session.name, user.username
5860
                            FROM $tbl_thematic t, $table_session session, $table_user user
5861
                            WHERE
5862
                              t.c_id = $course_id AND
5863
                              t.session_id = session.id AND
5864
                              session.id_coach = user.user_id AND
5865
                              t.id = $thematic_id";
5866
    				$recorset = Database::query($sql);
5867
    			}
5868
    		} else {
5869
                $sql = "SELECT session.id, session.name, user.username
5870
                          FROM $table_tool tool, $table_session session, $table_user user
5871
    			          WHERE
5872
    			              tool.c_id = $course_id AND
5873
    			              tool.session_id = session.id AND
5874
    			              session.id_coach = user.user_id AND
5875
    			              tool.$id = $ref";
5876
    			$recorset = Database::query($sql);
5877
    		}
5878
5879
    		if (!empty($recorset)) {
5880
    			$obj = Database::fetch_object($recorset);
5881
5882
    			$name_session = '';
5883
    			$coach_name = '';
5884
    			if (!empty($obj)) {
5885
    				$name_session = $obj->name;
5886
    				$coach_name   = $obj->username;
5887
    			}
5888
5889
    			$url_tool = api_get_path(WEB_CODE_PATH).$table_name['link_tool'];
5890
    			$row[0] = '';
5891
    			if ($row['col6'] != 2) {
5892
    				if (in_array($row['col0'], $thematic_tools)) {
5893
5894
    					$exp_thematic_tool = explode('_', $row['col0']);
5895
    					$thematic_tool_title = '';
5896
    					if (is_array($exp_thematic_tool)) {
5897
    						foreach ($exp_thematic_tool as $exp) {
5898
    							$thematic_tool_title .= api_ucfirst($exp);
5899
    						}
5900
    					} else {
5901
    						$thematic_tool_title = api_ucfirst($row['col0']);
5902
    					}
5903
5904
    					$row[0] = '<a href="'.$url_tool.'?'.api_get_cidreq().'&action=thematic_details">'.get_lang($thematic_tool_title).'</a>';
5905
    				} else {
5906
    					$row[0] = '<a href="'.$url_tool.'?'.api_get_cidreq().'">'.get_lang('Tool'.api_ucfirst($row['col0'])).'</a>';
5907
    				}
5908
    			} else {
5909
    				$row[0] = api_ucfirst($row['col0']);
5910
    			}
5911
    			$row[1] = get_lang($row[1]);
5912
    			$row[6] = api_convert_and_format_date($row['col5'], null, date_default_timezone_get());
5913
    			$row[5] = '';
5914
    			//@todo Improve this code please
5915
    			switch ($table_name['table_name']) {
5916
    				case 'document' :
5917
    					$sql = "SELECT tool.title as title FROM $table_tool tool
5918
                                WHERE c_id = $course_id AND id = $ref";
5919
    					$rs_document = Database::query($sql);
5920
    					$obj_document = Database::fetch_object($rs_document);
5921
    					$row[5] = $obj_document->title;
5922
5923
    					break;
5924 View Code Duplication
    				case 'announcement':
5925
                        $sql = "SELECT title FROM $table_tool
5926
                                WHERE c_id = $course_id AND id = $ref";
5927
    					$rs_document = Database::query($sql);
5928
    					$obj_document = Database::fetch_object($rs_document);
5929
                        if ($obj_document) {
5930
                            $row[5] = $obj_document->title;
5931
                        }
5932
    					break;
5933
    				case 'glossary':
5934
                        $sql = "SELECT name FROM $table_tool
5935
    					        WHERE c_id = $course_id AND glossary_id = $ref";
5936
    					$rs_document = Database::query($sql);
5937
    					$obj_document = Database::fetch_object($rs_document);
5938
                        if ($obj_document) {
5939
                            $row[5] = $obj_document->name;
5940
                        }
5941
    					break;
5942
    				case 'lp':
5943
                        $sql = "SELECT name
5944
                                FROM $table_tool WHERE c_id = $course_id AND id = $ref";
5945
    					$rs_document = Database::query($sql);
5946
    					$obj_document = Database::fetch_object($rs_document);
5947
    					$row[5] = $obj_document->name;
5948
    					break;
5949
    				case 'quiz':
5950
                        $sql = "SELECT title FROM $table_tool
5951
                                WHERE c_id = $course_id AND id = $ref";
5952
    					$rs_document = Database::query($sql);
5953
    					$obj_document = Database::fetch_object($rs_document);
5954
                        if ($obj_document) {
5955
                            $row[5] = $obj_document->title;
5956
                        }
5957
    					break;
5958 View Code Duplication
    				case 'course_description':
5959
                        $sql = "SELECT title FROM $table_tool
5960
                                WHERE c_id = $course_id AND id = $ref";
5961
    					$rs_document = Database::query($sql);
5962
    					$obj_document = Database::fetch_object($rs_document);
5963
                        if ($obj_document) {
5964
                            $row[5] = $obj_document->title;
5965
                        }
5966
    					break;
5967 View Code Duplication
    				case 'thematic':
5968
    					$rs = Database::query("SELECT title FROM $table_tool WHERE c_id = $course_id AND id = $ref");
5969
    					if (Database::num_rows($rs) > 0) {
5970
    						$obj = Database::fetch_object($rs);
5971
    						$row[5] = $obj->title;
5972
    					}
5973
    					break;
5974 View Code Duplication
    				case 'thematic_advance':
5975
    					$rs = Database::query("SELECT content FROM $table_tool WHERE c_id = $course_id AND id = $ref");
5976
    					if (Database::num_rows($rs) > 0) {
5977
    						$obj = Database::fetch_object($rs);
5978
    						$row[5] = $obj->content;
5979
    					}
5980
    					break;
5981 View Code Duplication
    				case 'thematic_plan':
5982
    					$rs = Database::query("SELECT title FROM $table_tool WHERE c_id = $course_id AND id = $ref");
5983
    					if (Database::num_rows($rs) > 0) {
5984
    						$obj = Database::fetch_object($rs);
5985
    						$row[5] = $obj->title;
5986
    					}
5987
    					break;
5988
    				default:
5989
    					break;
5990
    			}
5991
5992
    			$row2 = $name_session;
5993
    			if (!empty($coach_name)) {
5994
    				$row2 .= '<br />'.get_lang('Coach').': '.$coach_name;
5995
    			}
5996
    			$row[2] = $row2;
5997
                if (!empty($row['col3'])) {
5998
                    $userInfo = api_get_user_info($row['user_id']);
5999
6000
                    $row['col3'] = Display::url(
6001
                        $row['col3'],
6002
                        $userInfo['profile_url']
6003
                    );
6004
                    $row[3] = $row['col3'];
6005
6006
                    $ip = TrackingUserLog::get_ip_from_user_event($row['user_id'], $row['col5'], true);
6007
                    if (empty($ip)) {
6008
                        $ip = get_lang('Unknown');
6009
                    }
6010
                    $row[4] = $ip;
6011
                }
6012
6013
    			$resources[] = $row;
6014
    		}
6015
    	}
6016
6017
    	return $resources;
6018
    }
6019
6020
    /**
6021
     * @param string $tool
6022
     *
6023
     * @return array
6024
     */
6025
    public static function get_tool_name_table($tool)
6026
    {
6027
    	switch ($tool) {
6028
    		case 'document':
6029
    			$table_name = TABLE_DOCUMENT;
6030
    			$link_tool = 'document/document.php';
6031
    			$id_tool = 'id';
6032
    			break;
6033
    		case 'learnpath':
6034
    			$table_name = TABLE_LP_MAIN;
6035
    			$link_tool = 'newscorm/lp_controller.php';
6036
    			$id_tool = 'id';
6037
    			break;
6038
    		case 'quiz':
6039
    			$table_name = TABLE_QUIZ_TEST;
6040
    			$link_tool = 'exercice/exercice.php';
6041
    			$id_tool = 'id';
6042
    			break;
6043
    		case 'glossary':
6044
    			$table_name = TABLE_GLOSSARY;
6045
    			$link_tool = 'glossary/index.php';
6046
    			$id_tool = 'glossary_id';
6047
    			break;
6048
    		case 'link':
6049
    			$table_name = TABLE_LINK;
6050
    			$link_tool = 'link/link.php';
6051
    			$id_tool = 'id';
6052
    			break;
6053
    		case 'course_description':
6054
    			$table_name = TABLE_COURSE_DESCRIPTION;
6055
    			$link_tool = 'course_description/';
6056
    			$id_tool = 'id';
6057
    			break;
6058
    		case 'announcement':
6059
    			$table_name = TABLE_ANNOUNCEMENT;
6060
    			$link_tool = 'announcements/announcements.php';
6061
    			$id_tool = 'id';
6062
    			break;
6063
    		case 'thematic':
6064
    			$table_name = TABLE_THEMATIC;
6065
    			$link_tool = 'course_progress/index.php';
6066
    			$id_tool = 'id';
6067
    			break;
6068
    		case 'thematic_advance':
6069
    			$table_name = TABLE_THEMATIC_ADVANCE;
6070
    			$link_tool = 'course_progress/index.php';
6071
    			$id_tool = 'id';
6072
    			break;
6073
    		case 'thematic_plan':
6074
    			$table_name = TABLE_THEMATIC_PLAN;
6075
    			$link_tool = 'course_progress/index.php';
6076
    			$id_tool = 'id';
6077
    			break;
6078
    		default:
6079
    			$table_name = $tool;
6080
    		break;
6081
    	}
6082
6083
    	return array(
6084
            'table_name' => $table_name,
6085
            'link_tool' => $link_tool,
6086
            'id_tool' => $id_tool
6087
        );
6088
    }
6089
6090
    public static function display_additional_profile_fields()
6091
    {
6092
    	// getting all the extra profile fields that are defined by the platform administrator
6093
    	$extra_fields = UserManager :: get_extra_fields(0,50,5,'ASC');
6094
6095
    	// creating the form
6096
    	$return = '<form action="courseLog.php" method="get" name="additional_profile_field_form" id="additional_profile_field_form">';
6097
6098
    	// the select field with the additional user profile fields (= this is where we select the field of which we want to see
6099
    	// the information the users have entered or selected.
6100
    	$return .= '<select name="additional_profile_field">';
6101
    	$return .= '<option value="-">'.get_lang('SelectFieldToAdd').'</option>';
6102
    	$extra_fields_to_show = 0;
6103
    	foreach ($extra_fields as $key=>$field) {
6104
    		// show only extra fields that are visible + and can be filtered, added by J.Montoya
6105
    		if ($field[6]==1 && $field[8] == 1) {
6106
    			if (isset($_GET['additional_profile_field']) && $field[0] == $_GET['additional_profile_field'] ) {
6107
    				$selected = 'selected="selected"';
6108
    			} else {
6109
    				$selected = '';
6110
    			}
6111
    			$extra_fields_to_show++;
6112
    			$return .= '<option value="'.$field[0].'" '.$selected.'>'.$field[3].'</option>';
6113
    		}
6114
    	}
6115
    	$return .= '</select>';
6116
6117
    	// the form elements for the $_GET parameters (because the form is passed through GET
6118
    	foreach ($_GET as $key=>$value){
6119
    		if ($key <> 'additional_profile_field')    {
6120
    			$return .= '<input type="hidden" name="'.Security::remove_XSS($key).'" value="'.Security::remove_XSS($value).'" />';
6121
    		}
6122
    	}
6123
    	// the submit button
6124
    	$return .= '<button class="save" type="submit">'.get_lang('AddAdditionalProfileField').'</button>';
6125
    	$return .= '</form>';
6126
    	if ($extra_fields_to_show > 0) {
6127
    		return $return;
6128
    	} else {
6129
    		return '';
6130
    	}
6131
    }
6132
6133
    /**
6134
     * This function gets all the information of a certrain ($field_id)
6135
     * additional profile field for a specific list of users is more efficent
6136
     * than get_addtional_profile_information_of_field() function
6137
     * It gets the information of all the users so that it can be displayed
6138
     * in the sortable table or in the csv or xls export
6139
     *
6140
     * @author    Julio Montoya <[email protected]>
6141
     * @param    int field id
6142
     * @param    array list of user ids
6143
     * @return    array
6144
     * @since    Nov 2009
6145
     * @version    1.8.6.2
6146
     */
6147
    public static function get_addtional_profile_information_of_field_by_user($field_id, $users)
6148
    {
6149
    	// Database table definition
6150
    	$table_user = Database::get_main_table(TABLE_MAIN_USER);
6151
    	$table_user_field_values = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
6152
        $extraField = Database::get_main_table(TABLE_EXTRA_FIELD);
6153
    	$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...
6154
6155
    	if (!empty($users)) {
6156
    		if ($result_extra_field['field_type'] == UserManager::USER_FIELD_TYPE_TAG ) {
6157
    			foreach($users as $user_id) {
6158
    				$user_result = UserManager::get_user_tags($user_id, $field_id);
6159
    				$tag_list = array();
6160
    				foreach($user_result as $item) {
6161
    					$tag_list[] = $item['tag'];
6162
    				}
6163
    				$return[$user_id][] = implode(', ',$tag_list);
6164
    			}
6165
    		} else {
6166
    			$new_user_array = array();
6167
    			foreach ($users as $user_id) {
6168
    				$new_user_array[]= "'".$user_id."'";
6169
    			}
6170
    			$users = implode(',',$new_user_array);
6171
                $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
6172
    			// Selecting only the necessary information NOT ALL the user list
6173
    			$sql = "SELECT user.user_id, v.value
6174
    			        FROM $table_user user
6175
    			        INNER JOIN $table_user_field_values v
6176
                        ON (user.user_id = v.item_id)
6177
                        INNER JOIN $extraField f
6178
                        ON (f.id = v.field_id)
6179
                        WHERE
6180
                            f.extra_field_type = $extraFieldType AND
6181
                            v.field_id=".intval($field_id)." AND
6182
                            user.user_id IN ($users)";
6183
6184
    			$result = Database::query($sql);
6185
    			while($row = Database::fetch_array($result)) {
6186
    				// get option value for field type double select by id
6187
    				if (!empty($row['value'])) {
6188
    					if ($result_extra_field['field_type'] ==
6189
                            ExtraField::FIELD_TYPE_DOUBLE_SELECT
6190
                        ) {
6191
    						$id_double_select = explode(';', $row['value']);
6192
    						if (is_array($id_double_select)) {
6193
    							$value1 = $result_extra_field['options'][$id_double_select[0]]['option_value'];
6194
    							$value2 = $result_extra_field['options'][$id_double_select[1]]['option_value'];
6195
    							$row['value'] = ($value1.';'.$value2);
6196
    						}
6197
    					}
6198
    				}
6199
    				// get other value from extra field
6200
    				$return[$row['user_id']][] = $row['value'];
6201
    			}
6202
    		}
6203
    	}
6204
    	return $return;
6205
    }
6206
6207
    /**
6208
     * count the number of students in this course (used for SortableTable)
6209
     * Deprecated
6210
     */
6211
    public function count_student_in_course()
6212
    {
6213
    	global $nbStudents;
6214
    	return $nbStudents;
6215
    }
6216
6217
    public function sort_users($a, $b)
6218
    {
6219
    	return strcmp(trim(api_strtolower($a[$_SESSION['tracking_column']])), trim(api_strtolower($b[$_SESSION['tracking_column']])));
6220
    }
6221
6222
    public function sort_users_desc($a, $b)
6223
    {
6224
    	return strcmp( trim(api_strtolower($b[$_SESSION['tracking_column']])), trim(api_strtolower($a[$_SESSION['tracking_column']])));
6225
    }
6226
6227
    /**
6228
     * Get number of users for sortable with pagination
6229
     * @return int
6230
     */
6231
    public static function get_number_of_users()
6232
    {
6233
    	global $user_ids;
6234
    	return count($user_ids);
6235
    }
6236
6237
    /**
6238
     * Get data for users list in sortable with pagination
6239
     * @param $from
6240
     * @param $number_of_items
6241
     * @param $column
6242
     * @param $direction
6243
     * @param $includeInvitedUsers boolean Whether include the invited users
6244
     * @return array
6245
     */
6246
    public static function get_user_data($from, $number_of_items, $column, $direction, $includeInvitedUsers = false)
6247
    {
6248
        global $user_ids, $course_code, $additional_user_profile_info, $export_csv, $is_western_name_order, $csv_content, $session_id;
6249
6250
    	$course_code = Database::escape_string($course_code);
6251
    	$tbl_user = Database::get_main_table(TABLE_MAIN_USER);
6252
    	$tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
6253
6254
    	$access_url_id = api_get_current_access_url_id();
6255
6256
    	// get all users data from a course for sortable with limit
6257
    	if (is_array($user_ids)) {
6258
    		$user_ids = array_map('intval', $user_ids);
6259
    		$condition_user = " WHERE user.user_id IN (".implode(',',$user_ids).") ";
6260
    	} else {
6261
    		$user_ids = intval($user_ids);
6262
    		$condition_user = " WHERE user.user_id = $user_ids ";
6263
    	}
6264
6265 View Code Duplication
    	if (!empty($_GET['user_keyword'])) {
6266
    		$keyword = trim(Database::escape_string($_GET['user_keyword']));
6267
    		$condition_user .=  " AND (
6268
                user.firstname LIKE '%".$keyword."%' OR
6269
                user.lastname LIKE '%".$keyword."%'  OR
6270
                user.username LIKE '%".$keyword."%'  OR
6271
                user.email LIKE '%".$keyword."%'
6272
             ) ";
6273
    	}
6274
6275
        $url_table = null;
6276
        $url_condition = null;
6277
    	if (api_is_multiple_url_enabled()) {
6278
    		$url_table = ", ".$tbl_url_rel_user." as url_users";
6279
    		$url_condition = " AND user.user_id = url_users.user_id AND access_url_id='$access_url_id'";
6280
    	}
6281
6282
        $invitedUsersCondition = '';
6283
6284
        if (!$includeInvitedUsers) {
6285
            $invitedUsersCondition = " AND user.status != " . INVITEE;
6286
        }
6287
6288
    	$sql = "SELECT  user.user_id as user_id,
6289
                    user.official_code  as col0,
6290
                    user.lastname       as col1,
6291
                    user.firstname      as col2,
6292
                    user.username       as col3
6293
                FROM $tbl_user as user $url_table
6294
    	        $condition_user $url_condition $invitedUsersCondition";
6295
6296
    	if (!in_array($direction, array('ASC','DESC'))) {
6297
    		$direction = 'ASC';
6298
    	}
6299
6300
    	$column = intval($column);
6301
6302
    	$from = intval($from);
6303
    	$number_of_items = intval($number_of_items);
6304
6305
    	$sql .= " ORDER BY col$column $direction ";
6306
    	$sql .= " LIMIT $from,$number_of_items";
6307
6308
        $res = Database::query($sql);
6309
        $users = array();
6310
6311
        $course_info = api_get_course_info($course_code);
6312
        $total_surveys = 0;
6313
        $total_exercises = ExerciseLib::get_all_exercises(
6314
            $course_info,
6315
            $session_id,
6316
            false,
6317
            null,
6318
            false,
6319
            3
6320
        );
6321
6322
        if (empty($session_id)) {
6323
            $survey_user_list = array();
6324
            $survey_list = SurveyManager::get_surveys($course_code, $session_id);
6325
6326
            $total_surveys = count($survey_list);
6327 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...
6328
                $user_list = SurveyManager::get_people_who_filled_survey(
6329
                    $survey['survey_id'],
6330
                    false,
6331
                    $course_info['real_id']
6332
                );
6333
6334
                foreach ($user_list as $user_id) {
6335
                    isset($survey_user_list[$user_id]) ? $survey_user_list[$user_id]++ : $survey_user_list[$user_id] = 1;
6336
                }
6337
            }
6338
        }
6339
6340
    	while ($user = Database::fetch_array($res, 'ASSOC')) {
6341
            $courseInfo = api_get_course_info($course_code);
6342
            $courseId = $courseInfo['real_id'];
6343
6344
            $user['official_code'] = $user['col0'];
6345
            $user['lastname'] = $user['col1'];
6346
            $user['firstname'] = $user['col2'];
6347
            $user['username'] = $user['col3'];
6348
6349
            $user['time'] = api_time_to_hms(
6350
                Tracking::get_time_spent_on_the_course(
6351
                    $user['user_id'],
6352
                    $courseId,
6353
                    $session_id
6354
                )
6355
            );
6356
6357
            $avg_student_score = Tracking::get_avg_student_score(
6358
                $user['user_id'],
6359
                $course_code,
6360
                array(),
6361
                $session_id
6362
            );
6363
6364
            $avg_student_progress = Tracking::get_avg_student_progress(
6365
                $user['user_id'],
6366
                $course_code,
6367
                array(),
6368
                $session_id
6369
            );
6370
6371
    		if (empty($avg_student_progress)) {
6372
                $avg_student_progress = 0;
6373
    		}
6374
    		$user['average_progress'] = $avg_student_progress.'%';
6375
6376
            $total_user_exercise = Tracking::get_exercise_student_progress(
6377
                $total_exercises,
6378
                $user['user_id'],
6379
                $courseId,
6380
                $session_id
6381
            );
6382
6383
            $user['exercise_progress'] = $total_user_exercise;
6384
6385
            $total_user_exercise = Tracking::get_exercise_student_average_best_attempt(
6386
                $total_exercises,
6387
                $user['user_id'],
6388
                $courseId,
6389
                $session_id
6390
            );
6391
6392
            $user['exercise_average_best_attempt'] = $total_user_exercise;
6393
6394
    		if (is_numeric($avg_student_score)) {
6395
    			$user['student_score']  = $avg_student_score.'%';
6396
    		} else {
6397
    			$user['student_score']  = $avg_student_score;
6398
    		}
6399
6400
            $user['count_assignments'] = Tracking::count_student_assignments(
6401
                $user['user_id'],
6402
                $course_code,
6403
                $session_id
6404
            );
6405
            $user['count_messages'] = Tracking::count_student_messages(
6406
                $user['user_id'],
6407
                $course_code,
6408
                $session_id
6409
            );
6410
            $user['first_connection'] = Tracking::get_first_connection_date_on_the_course(
6411
                $user['user_id'],
6412
                $courseId,
6413
                $session_id
6414
            );
6415
            $user['last_connection'] = Tracking::get_last_connection_date_on_the_course(
6416
                $user['user_id'],
6417
                $courseInfo,
6418
                $session_id
6419
            );
6420
6421
    		// we need to display an additional profile field
6422
    		$user['additional'] = '';
6423
6424
    		if (isset($_GET['additional_profile_field']) && is_numeric($_GET['additional_profile_field'])) {
6425 View Code Duplication
    			if (isset($additional_user_profile_info[$user['user_id']]) &&
6426
                    is_array($additional_user_profile_info[$user['user_id']])
6427
                ) {
6428
    				$user['additional'] = implode(', ', $additional_user_profile_info[$user['user_id']]);
6429
    			}
6430
    		}
6431
6432
            if (empty($session_id)) {
6433
                $user['survey'] = (isset($survey_user_list[$user['user_id']]) ? $survey_user_list[$user['user_id']] : 0) .' / '.$total_surveys;
6434
            }
6435
6436
    		$user['link'] = '<center>
6437
                             <a href="../mySpace/myStudents.php?student='.$user['user_id'].'&details=true&course='.$course_code.'&origin=tracking_course&id_session='.$session_id.'">
6438
    		                 '.Display::return_icon('2rightarrow.png').'
6439
    		                 </a>
6440
                         </center>';
6441
6442
    		// store columns in array $users
6443
    		$is_western_name_order = api_is_western_name_order();
6444
            $user_row = array();
6445
            $user_row[]= $user['official_code']; //0
6446
            if ($is_western_name_order) {
6447
                $user_row[]= $user['firstname'];
6448
                $user_row[]= $user['lastname'];
6449
            } else {
6450
                $user_row[]= $user['lastname'];
6451
                $user_row[]= $user['firstname'];
6452
            }
6453
            $user_row[]= $user['username'];
6454
            $user_row[]= $user['time'];
6455
            $user_row[]= $user['average_progress'];
6456
            $user_row[]= $user['exercise_progress'];
6457
            $user_row[]= $user['exercise_average_best_attempt'];
6458
            $user_row[]= $user['student_score'];
6459
            $user_row[]= $user['count_assignments'];
6460
            $user_row[]= $user['count_messages'];
6461
6462
            if (empty($session_id)) {
6463
                $user_row[]= $user['survey'];
6464
            }
6465
6466
            $user_row[]= $user['first_connection'];
6467
            $user_row[]= $user['last_connection'];
6468
            if (isset($_GET['additional_profile_field']) && is_numeric($_GET['additional_profile_field'])) {
6469
                $user_row[]= $user['additional'];
6470
            }
6471
6472
            $user_row[]= $user['link'];
6473
6474
            $users[] = $user_row;
6475
6476
    		if ($export_csv) {
6477
    		    if (empty($session_id)) {
6478
                    $user_row = array_map('strip_tags', $user_row);
6479
    			    unset($user_row[14]);
6480
    			    unset($user_row[15]);
6481
                } else {
6482
                    $user_row = array_map('strip_tags', $user_row);
6483
                    unset($user_row[13]);
6484
                    unset($user_row[14]);
6485
                }
6486
6487
    			$csv_content[] = $user_row;
6488
    		}
6489
    	}
6490
    	return $users;
6491
    }
6492
}
6493
6494
/**
6495
 * @package chamilo.tracking
6496
 */
6497
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...
6498
{
6499
    /**
6500
     * Displays the number of logins every month for a specific user in a specific course.
6501
     * @param $view
6502
     * @param int $user_id
6503
     * @param int $course_id
6504
     * @param int $session_id
6505
     */
6506
    public function display_login_tracking_info($view, $user_id, $course_id, $session_id = 0)
6507
    {
6508
    	$MonthsLong = $GLOBALS['MonthsLong'];
6509
6510
    	// protected data
6511
    	$user_id = intval($user_id);
6512
    	$session_id = intval($session_id);
6513
    	$course_id = Database::escape_string($course_id);
6514
6515
    	$track_access_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
6516
    	$tempView = $view;
6517
    	if(substr($view,0,1) == '1') {
6518
    		$new_view = substr_replace($view,'0',0,1);
6519
    		echo "
6520
                <tr>
6521
                    <td valign='top'>
6522
                    <font color='#0000FF'>-&nbsp;&nbsp;&nbsp;</font>" .
6523
                    "<b>".get_lang('LoginsAndAccessTools')."</b>&nbsp;&nbsp;&nbsp;[<a href='".api_get_self()."?uInfo=".$user_id."&view=".Security::remove_XSS($new_view)."'>".get_lang('Close')."</a>]&nbsp;&nbsp;&nbsp;[<a href='userLogCSV.php?".api_get_cidreq()."&uInfo=".Security::remove_XSS($_GET['uInfo'])."&view=10000'>".get_lang('ExportAsCSV')."</a>]
6524
                    </td>
6525
                </tr>
6526
                ";
6527
    		echo "<tr><td style='padding-left : 40px;' valign='top'>".get_lang('LoginsDetails')."<br>";
6528
6529
    		$sql = "SELECT UNIX_TIMESTAMP(access_date), count(access_date)
6530
                        FROM $track_access_table
6531
                        WHERE access_user_id = $user_id
6532
                        AND c_id = $course_id
6533
                        AND access_session_id = $session_id
6534
                        GROUP BY YEAR(access_date),MONTH(access_date)
6535
                        ORDER BY YEAR(access_date),MONTH(access_date) ASC";
6536
6537
    		echo "<tr><td style='padding-left : 40px;padding-right : 40px;'>";
6538
    		$results = getManyResults3Col($sql);
6539
6540
    		echo "<table cellpadding='2' cellspacing='1' border='0' align=center>";
6541
    		echo "<tr>
6542
                    <td class='secLine'>
6543
                    ".get_lang('LoginsTitleMonthColumn')."
6544
                    </td>
6545
                    <td class='secLine'>
6546
                    ".get_lang('LoginsTitleCountColumn')."
6547
                    </td>
6548
                </tr>";
6549
    		$total = 0;
6550
    		if (is_array($results)) {
6551
    			for($j = 0 ; $j < count($results) ; $j++) {
6552
    				echo "<tr>";
6553
    				echo "<td class='content'><a href='logins_details.php?uInfo=".$user_id."&reqdate=".$results[$j][0]."&view=".Security::remove_XSS($view)."'>".$MonthsLong[date('n', $results[$j][0])-1].' '.date('Y', $results[$j][0])."</a></td>";
6554
    				echo "<td valign='top' align='right' class='content'>".$results[$j][1]."</td>";
6555
    				echo"</tr>";
6556
    				$total = $total + $results[$j][1];
6557
    			}
6558
    			echo "<tr>";
6559
    			echo "<td>".get_lang('Total')."</td>";
6560
    			echo "<td align='right' class='content'>".$total."</td>";
6561
    			echo"</tr>";
6562
    		} else {
6563
    			echo "<tr>";
6564
    			echo "<td colspan='2'><center>".get_lang('NoResult')."</center></td>";
6565
    			echo"</tr>";
6566
    		}
6567
    		echo "</table>";
6568
    		echo "</td></tr>";
6569 View Code Duplication
    	} else {
6570
    		$new_view = substr_replace($view,'1',0,1);
6571
    		echo "
6572
                <tr>
6573
                    <td valign='top'>
6574
                    +<font color='#0000FF'>&nbsp;&nbsp;</font><a href='".api_get_self()."?uInfo=".$user_id."&view=".Security::remove_XSS($new_view)."' class='specialLink'>".get_lang('LoginsAndAccessTools')."</a>
6575
                    </td>
6576
                </tr>
6577
            ";
6578
    	}
6579
    }
6580
6581
    /**
6582
     * Displays the exercise results for a specific user in a specific course.
6583
     * @param   string $view
6584
     * @param   int $user_id    User ID
6585
     * @param   string  $courseCode Course code
6586
     * @return array
6587
     * @todo remove globals
6588
     */
6589
    public function display_exercise_tracking_info($view, $user_id, $courseCode)
6590
    {
6591
    	global $TBL_TRACK_HOTPOTATOES, $TABLECOURSE_EXERCICES, $TABLETRACK_EXERCICES, $dateTimeFormatLong;
6592
        $courseId = api_get_course_int_id($courseCode);
6593
    	if(substr($view,1,1) == '1') {
6594
    		$new_view = substr_replace($view,'0',1,1);
6595
    		echo "<tr>
6596
                    <td valign='top'>
6597
                        <font color='#0000FF'>-&nbsp;&nbsp;&nbsp;</font><b>".get_lang('ExercicesResults')."</b>&nbsp;&nbsp;&nbsp;[<a href='".api_get_self()."?uInfo=".Security::remove_XSS($user_id)."&view=".Security::remove_XSS($new_view)."'>".get_lang('Close')."</a>]&nbsp;&nbsp;&nbsp;[<a href='userLogCSV.php?".api_get_cidreq()."&uInfo=".Security::remove_XSS($_GET['uInfo'])."&view=01000'>".get_lang('ExportAsCSV')."</a>]
6598
                    </td>
6599
                </tr>";
6600
    		echo "<tr><td style='padding-left : 40px;' valign='top'>".get_lang('ExercicesDetails')."<br />";
6601
6602
    		$sql = "SELECT ce.title, te.exe_result , te.exe_weighting, UNIX_TIMESTAMP(te.exe_date)
6603
                    FROM $TABLECOURSE_EXERCICES AS ce , $TABLETRACK_EXERCICES AS te
6604
                    WHERE te.c_id = $courseId
6605
                        AND te.exe_user_id = ".intval($user_id)."
6606
                        AND te.exe_exo_id = ce.id
6607
                    ORDER BY ce.title ASC, te.exe_date ASC";
6608
6609
    		$hpsql = "SELECT te.exe_name, te.exe_result , te.exe_weighting, UNIX_TIMESTAMP(te.exe_date)
6610
                        FROM $TBL_TRACK_HOTPOTATOES AS te
6611
                        WHERE te.exe_user_id = '".intval($user_id)."' AND te.c_id = $courseId
6612
                        ORDER BY te.c_id ASC, te.exe_date ASC";
6613
6614
    		$hpresults = StatsUtils::getManyResultsXCol($hpsql, 4);
6615
6616
    		$NoTestRes = 0;
6617
    		$NoHPTestRes = 0;
6618
6619
    		echo "<tr>\n<td style='padding-left : 40px;padding-right : 40px;'>\n";
6620
    		$results = StatsUtils::getManyResultsXCol($sql, 4);
6621
    		echo "<table cellpadding='2' cellspacing='1' border='0' align='center'>\n";
6622
    		echo "
6623
                <tr bgcolor='#E6E6E6'>
6624
                    <td>
6625
                    ".get_lang('ExercicesTitleExerciceColumn')."
6626
                    </td>
6627
                    <td>
6628
                    ".get_lang('Date')."
6629
                    </td>
6630
                    <td>
6631
                    ".get_lang('ExercicesTitleScoreColumn')."
6632
                    </td>
6633
                </tr>";
6634
6635
    		if (is_array($results)) {
6636
    			for($i = 0; $i < sizeof($results); $i++) {
6637
    				$display_date = api_convert_and_format_date($results[$i][3], null, date_default_timezone_get());
6638
    				echo "<tr>\n";
6639
    				echo "<td class='content'>".$results[$i][0]."</td>\n";
6640
    				echo "<td class='content'>".$display_date."</td>\n";
6641
    				echo "<td valign='top' align='right' class='content'>".$results[$i][1]." / ".$results[$i][2]."</td>\n";
6642
    				echo "</tr>\n";
6643
    			}
6644
    		} else {
6645
    			// istvan begin
6646
    			$NoTestRes = 1;
6647
    		}
6648
6649
    		// The Result of Tests
6650
    		if (is_array($hpresults)) {
6651
    			for($i = 0; $i < sizeof($hpresults); $i++) {
6652
    				$title = GetQuizName($hpresults[$i][0],'');
6653
    				if ($title == '')
6654
    				$title = basename($hpresults[$i][0]);
6655
    				$display_date = api_convert_and_format_date($hpresults[$i][3], null, date_default_timezone_get());
6656
    				?>
6657
                    <tr>
6658
                        <td class="content"><?php echo $title; ?></td>
6659
                        <td class="content" align="center"><?php echo $display_date; ?></td>
6660
                        <td class="content" align="center"><?php echo $hpresults[$i][1]; ?> / <?php echo $hpresults[$i][2]; ?>
6661
                        </td>
6662
                    </tr>
6663
6664
                    <?php
6665
                }
6666
    		} else {
6667
    			$NoHPTestRes = 1;
6668
    		}
6669
6670
    		if ($NoTestRes == 1 && $NoHPTestRes == 1) {
6671
    			echo "<tr>\n";
6672
    			echo "<td colspan='3'><center>".get_lang('NoResult')."</center></td>\n";
6673
    			echo "</tr>\n";
6674
    		}
6675
    		echo "</table>";
6676
    		echo "</td>\n</tr>\n";
6677
    	} else {
6678
    		$new_view = substr_replace($view,'1',1,1);
6679
    		echo "
6680
                <tr>
6681
                    <td valign='top'>
6682
                        +<font color='#0000FF'>&nbsp;&nbsp;</font><a href='".api_get_self()."?uInfo=$user_id&view=".$new_view."' class='specialLink'>".get_lang('ExercicesResults')."</a>
6683
                    </td>
6684
                </tr>";
6685
    	}
6686
    }
6687
6688
    /**
6689
     * Displays the student publications for a specific user in a specific course.
6690
     * @todo remove globals
6691
     */
6692
    public function display_student_publications_tracking_info($view, $user_id, $course_id)
6693
    {
6694
    	global $TABLETRACK_UPLOADS, $TABLECOURSE_WORK;
6695
        $_course = api_get_course_info_by_id($course_id);
6696
6697
    	if (substr($view,2,1) == '1') {
6698
    		$new_view = substr_replace($view,'0',2,1);
6699
    		echo "<tr>
6700
                    <td valign='top'>
6701
                    <font color='#0000FF'>-&nbsp;&nbsp;&nbsp;</font><b>".get_lang('WorkUploads')."</b>&nbsp;&nbsp;&nbsp;[<a href='".api_get_self()."?uInfo=".Security::remove_XSS($user_id)."&view=".Security::remove_XSS($new_view)."'>".get_lang('Close')."</a>]&nbsp;&nbsp;&nbsp;[<a href='userLogCSV.php?".api_get_cidreq()."&uInfo=".Security::remove_XSS($_GET['uInfo'])."&view=00100'>".get_lang('ExportAsCSV')."</a>]
6702
                    </td>
6703
                </tr>";
6704
    		echo "<tr><td style='padding-left : 40px;' valign='top'>".get_lang('WorksDetails')."<br>";
6705
    		$sql = "SELECT u.upload_date, w.title, w.author,w.url
6706
                    FROM $TABLETRACK_UPLOADS u , $TABLECOURSE_WORK w
6707
                    WHERE u.upload_work_id = w.id
6708
                        AND u.upload_user_id = '".intval($user_id)."'
6709
                        AND u.c_id = '".intval($course_id)."'
6710
                    ORDER BY u.upload_date DESC";
6711
    		echo "<tr><td style='padding-left : 40px;padding-right : 40px;'>";
6712
    		$results = StatsUtils::getManyResultsXCol($sql,4);
6713
    		echo "<table cellpadding='2' cellspacing='1' border='0' align=center>";
6714
    		echo "<tr>
6715
                    <td class='secLine' width='40%'>
6716
                    ".get_lang('WorkTitle')."
6717
                    </td>
6718
                    <td class='secLine' width='30%'>
6719
                    ".get_lang('WorkAuthors')."
6720
                    </td>
6721
                    <td class='secLine' width='30%'>
6722
                    ".get_lang('Date')."
6723
                    </td>
6724
                </tr>";
6725
    		if (is_array($results)) {
6726
    			for($j = 0 ; $j < count($results) ; $j++) {
6727
    				$pathToFile = api_get_path(WEB_COURSE_PATH).$_course['path']."/".$results[$j][3];
6728
    				$beautifulDate = api_convert_and_format_date($results[$j][0], null, date_default_timezone_get());
6729
    				echo "<tr>";
6730
    				echo "<td class='content'>"
6731
    				."<a href ='".$pathToFile."'>".$results[$j][1]."</a>"
6732
    				."</td>";
6733
    				echo "<td class='content'>".$results[$j][2]."</td>";
6734
    				echo "<td class='content'>".$beautifulDate."</td>";
6735
    				echo"</tr>";
6736
    			}
6737
    		} else {
6738
    			echo "<tr>";
6739
    			echo "<td colspan='3'><center>".get_lang('NoResult')."</center></td>";
6740
    			echo"</tr>";
6741
    		}
6742
    		echo "</table>";
6743
    		echo "</td></tr>";
6744 View Code Duplication
    	} else {
6745
    		$new_view = substr_replace($view,'1',2,1);
6746
    		echo "
6747
                <tr>
6748
                    <td valign='top'>
6749
                    +<font color='#0000FF'>&nbsp;&nbsp;</font><a href='".api_get_self()."?uInfo=".Security::remove_XSS($user_id)."&view=".Security::remove_XSS($new_view)."' class='specialLink'>".get_lang('WorkUploads')."</a>
6750
                    </td>
6751
                </tr>
6752
            ";
6753
    	}
6754
    }
6755
6756
    /**
6757
     * Displays the links followed for a specific user in a specific course.
6758
     * @todo remove globals
6759
     */
6760
    public function display_links_tracking_info($view, $user_id, $courseCode)
6761
    {
6762
    	global $TABLETRACK_LINKS, $TABLECOURSE_LINKS;
6763
        $courseId = api_get_course_int_id($courseCode);
6764
    	if (substr($view,3,1) == '1') {
6765
    		$new_view = substr_replace($view,'0',3,1);
6766
    		echo "
6767
                <tr>
6768
                        <td valign='top'>
6769
                        <font color='#0000FF'>-&nbsp;&nbsp;&nbsp;</font><b>".get_lang('LinksAccess')."</b>&nbsp;&nbsp;&nbsp;[<a href='".api_get_self()."?uInfo=".Security::remove_XSS($user_id)."&view=".Security::remove_XSS($new_view)."'>".get_lang('Close')."</a>]&nbsp;&nbsp;&nbsp;[<a href='userLogCSV.php?".api_get_cidreq()."&uInfo=".Security::remove_XSS($_GET['uInfo'])."&view=00010'>".get_lang('ExportAsCSV')."</a>]
6770
                        </td>
6771
                </tr>
6772
            ";
6773
    		echo "<tr><td style='padding-left : 40px;' valign='top'>".get_lang('LinksDetails')."<br>";
6774
    		$sql = "SELECT cl.title, cl.url
6775
                    FROM $TABLETRACK_LINKS AS sl, $TABLECOURSE_LINKS AS cl
6776
                    WHERE sl.links_link_id = cl.id
6777
                        AND sl.c_id = $courseId
6778
                        AND sl.links_user_id = ".intval($user_id)."
6779
                    GROUP BY cl.title, cl.url";
6780
    		echo "<tr><td style='padding-left : 40px;padding-right : 40px;'>";
6781
    		$results = StatsUtils::getManyResults2Col($sql);
6782
    		echo "<table cellpadding='2' cellspacing='1' border='0' align=center>";
6783
    		echo "<tr>
6784
                    <td class='secLine'>
6785
                    ".get_lang('LinksTitleLinkColumn')."
6786
                    </td>
6787
                </tr>";
6788
    		if (is_array($results)) {
6789
    			for($j = 0 ; $j < count($results) ; $j++) {
6790
    				echo "<tr>";
6791
    				echo "<td class='content'><a href='".$results[$j][1]."'>".$results[$j][0]."</a></td>";
6792
    				echo"</tr>";
6793
    			}
6794
    		} else {
6795
    			echo "<tr>";
6796
    			echo "<td ><center>".get_lang('NoResult')."</center></td>";
6797
    			echo"</tr>";
6798
    		}
6799
    		echo "</table>";
6800
    		echo "</td></tr>";
6801 View Code Duplication
    	} else {
6802
    		$new_view = substr_replace($view,'1',3,1);
6803
    		echo "
6804
                <tr>
6805
                    <td valign='top'>
6806
                    +<font color='#0000FF'>&nbsp;&nbsp;</font><a href='".api_get_self()."?uInfo=".Security::remove_XSS($user_id)."&view=".Security::remove_XSS($new_view)."' class='specialLink'>".get_lang('LinksAccess')."</a>
6807
                    </td>
6808
                </tr>
6809
            ";
6810
    	}
6811
    }
6812
6813
    /**
6814
     * Displays the documents downloaded for a specific user in a specific course.
6815
     * @param     string    kind of view inside tracking info
6816
     * @param    int        User id
6817
     * @param    string    Course code
6818
     * @param    int        Session id (optional, default = 0)
6819
     * @return     void
6820
     */
6821
    public static function display_document_tracking_info($view, $user_id, $course_code, $session_id = 0)
6822
    {
6823
    	// protect data
6824
        $user_id = intval($user_id);
6825
        $courseId = api_get_course_int_id($course_code);
6826
    	$session_id = intval($session_id);
6827
6828
    	$downloads_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
6829
    	if(substr($view,4,1) == '1') {
6830
    		$new_view = substr_replace($view,'0',4,1);
6831
    		echo "
6832
                <tr>
6833
                    <td valign='top'>
6834
                    <font color='#0000FF'>-&nbsp;&nbsp;&nbsp;</font><b>".get_lang('DocumentsAccess')."</b>&nbsp;&nbsp;&nbsp;[<a href='".api_get_self()."?uInfo=".Security::remove_XSS($user_id)."&view=".Security::remove_XSS($new_view)."'>".get_lang('Close')."</a>]&nbsp;&nbsp;&nbsp;[<a href='userLogCSV.php?".api_get_cidreq()."&uInfo=".Security::remove_XSS($_GET['uInfo'])."&view=00001'>".get_lang('ExportAsCSV')."</a>]
6835
                    </td>
6836
                </tr>
6837
            ";
6838
    		echo "<tr><td style='padding-left : 40px;' valign='top'>".get_lang('DocumentsDetails')."<br>";
6839
6840
    		$sql = "SELECT down_doc_path
6841
                    FROM $downloads_table
6842
                    WHERE c_id = $courseId
6843
                        AND down_user_id = $user_id
6844
                        AND down_session_id = $session_id
6845
                    GROUP BY down_doc_path";
6846
6847
    		echo "<tr><td style='padding-left : 40px;padding-right : 40px;'>";
6848
    		$results = StatsUtils::getManyResults1Col($sql);
6849
    		echo "<table cellpadding='2' cellspacing='1' border='0' align='center'>";
6850
    		echo "<tr>
6851
                    <td class='secLine'>
6852
                    ".get_lang('DocumentsTitleDocumentColumn')."
6853
                    </td>
6854
                </tr>";
6855
    		if (is_array($results)) {
6856
    			for($j = 0 ; $j < count($results) ; $j++) {
6857
    				echo "<tr>";
6858
    				echo "<td class='content'>".$results[$j]."</td>";
6859
    				echo"</tr>";
6860
    			}
6861
    		} else {
6862
    			echo "<tr>";
6863
    			echo "<td><center>".get_lang('NoResult')."</center></td>";
6864
    			echo"</tr>";
6865
    		}
6866
    		echo "</table>";
6867
    		echo "</td></tr>";
6868 View Code Duplication
    	} else {
6869
    		$new_view = substr_replace($view,'1',4,1);
6870
    		echo "
6871
                <tr>
6872
                    <td valign='top'>
6873
                    +<font color='#0000FF'>&nbsp;&nbsp;</font><a href='".api_get_self()."?uInfo=".Security::remove_XSS($user_id)."&view=".Security::remove_XSS($new_view)."' class='specialLink'>".get_lang('DocumentsAccess')."</a>
6874
                    </td>
6875
                </tr>
6876
            ";
6877
    	}
6878
    }
6879
6880
    /**
6881
     * Gets the IP of a given user, using the last login before the given date
6882
     * @param int User ID
6883
     * @param string Datetime
6884
     * @param bool Whether to return the IP as a link or just as an IP
6885
     * @param string If defined and return_as_link if true, will be used as the text to be shown as the link
6886
     * @return string IP address (or false on error)
6887
     * @assert (0,0) === false
6888
     */
6889
    public static function get_ip_from_user_event($user_id, $event_date, $return_as_link = false, $body_replace = null)
6890
    {
6891
        if (empty($user_id) or empty($event_date)) {
6892
            return false;
6893
        }
6894
        $user_id = intval($user_id);
6895
        $event_date = Database::escape_string($event_date);
6896
6897
        $table_login = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
6898
        $sql_ip = "SELECT login_date, user_ip FROM $table_login
6899
                   WHERE login_user_id = $user_id AND login_date < '$event_date'
6900
                   ORDER BY login_date DESC LIMIT 1";
6901
        $ip = '';
6902
        $res_ip = Database::query($sql_ip);
6903
        if ($res_ip !== false && Database::num_rows($res_ip)>0) {
6904
            $row_ip = Database::fetch_row($res_ip);
6905
            if ($return_as_link) {
6906
                $ip = Display::url(
6907
                    (empty($body_replace)?$row_ip[1]:$body_replace), 'http://www.whatsmyip.org/ip-geo-location/?ip='.$row_ip[1],
6908
                    array('title'=>get_lang('TraceIP'), 'target'=>'_blank')
6909
                );
6910
            } else {
6911
                $ip = $row_ip[1];
6912
            }
6913
        }
6914
6915
        return $ip;
6916
    }
6917
}
6918
6919
/**
6920
 * @package chamilo.tracking
6921
 */
6922
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...
6923
{
6924
    /**
6925
     * Displays the number of logins every month for a specific user in a specific course.
6926
     * @param $view
6927
     * @param int $user_id
6928
     * @param int $course_id
6929
     * @param int $session_id
6930
     * @return array
6931
     */
6932
    public function display_login_tracking_info($view, $user_id, $course_id, $session_id = 0)
6933
    {
6934
    	$MonthsLong = $GLOBALS['MonthsLong'];
6935
    	$track_access_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
6936
6937
    	// protected data
6938
    	$user_id    = intval($user_id);
6939
    	$session_id = intval($session_id);
6940
    	$course_id  = intval($course_id);
6941
6942
    	$tempView = $view;
6943
    	if (substr($view,0,1) == '1') {
6944
    		$new_view = substr_replace($view,'0',0,1);
6945
    		$title[1]= get_lang('LoginsAndAccessTools').get_lang('LoginsDetails');
6946
    		$sql = "SELECT UNIX_TIMESTAMP(access_date), count(access_date)
6947
                    FROM $track_access_table
6948
                    WHERE access_user_id = $user_id
6949
                    AND c_id = $course_id
6950
                    AND access_session_id = $session_id
6951
                    GROUP BY YEAR(access_date),MONTH(access_date)
6952
                    ORDER BY YEAR(access_date),MONTH(access_date) ASC";
6953
    		//$results = getManyResults2Col($sql);
6954
    		$results = getManyResults3Col($sql);
6955
    		$title_line= get_lang('LoginsTitleMonthColumn').';'.get_lang('LoginsTitleCountColumn')."\n";
6956
    		$line='';
6957
    		$total = 0;
6958 View Code Duplication
    		if (is_array($results)) {
6959
    			for($j = 0 ; $j < count($results) ; $j++) {
6960
    				$line .= $results[$j][0].';'.$results[$j][1]."\n";
6961
    				$total = $total + $results[$j][1];
6962
    			}
6963
    			$line .= get_lang('Total').";".$total."\n";
6964
    		} else {
6965
    			$line= get_lang('NoResult')."</center></td>";
6966
    		}
6967
    	} else {
6968
    		$new_view = substr_replace($view,'1',0,1);
6969
    	}
6970
    	return array($title_line, $line);
6971
    }
6972
6973
    /**
6974
     * Displays the exercise results for a specific user in a specific course.
6975
     * @param   string $view
6976
     * @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...
6977
     * @param   string  $courseCode Course code
6978
     * @return array
6979
     * @todo remove globals
6980
     */
6981
    public function display_exercise_tracking_info($view, $userId, $courseCode)
6982
    {
6983
    	global $TABLECOURSE_EXERCICES, $TABLETRACK_EXERCICES, $TABLETRACK_HOTPOTATOES, $dateTimeFormatLong;
6984
        $courseId = api_get_course_int_id($courseCode);
6985
        $userId = intval($userId);
6986
    	if (substr($view,1,1) == '1') {
6987
    		$new_view = substr_replace($view,'0',1,1);
6988
    		$title[1] = get_lang('ExercicesDetails');
6989
    		$line = '';
6990
    		$sql = "SELECT ce.title, te.exe_result , te.exe_weighting, UNIX_TIMESTAMP(te.exe_date)
6991
                    FROM $TABLECOURSE_EXERCICES AS ce , $TABLETRACK_EXERCICES AS te
6992
                    WHERE te.c_id = $courseId
6993
                        AND te.exe_user_id = $userId
6994
                        AND te.exe_exo_id = ce.id
6995
                    ORDER BY ce.title ASC, te.exe_date ASC";
6996
6997
    		$hpsql = "SELECT te.exe_name, te.exe_result , te.exe_weighting, UNIX_TIMESTAMP(te.exe_date)
6998
                        FROM $TABLETRACK_HOTPOTATOES AS te
6999
                        WHERE te.exe_user_id = '$userId' AND te.c_id = $courseId
7000
                        ORDER BY te.c_id ASC, te.exe_date ASC";
7001
7002
    		$hpresults = StatsUtils::getManyResultsXCol($hpsql, 4);
7003
7004
    		$NoTestRes = 0;
7005
    		$NoHPTestRes = 0;
7006
7007
    		$results = StatsUtils::getManyResultsXCol($sql, 4);
7008
    		$title_line = get_lang('ExercicesTitleExerciceColumn').";".get_lang('Date').';'.get_lang('ExercicesTitleScoreColumn')."\n";
7009
7010 View Code Duplication
    		if (is_array($results)) {
7011
    			for($i = 0; $i < sizeof($results); $i++)
7012
    			{
7013
    				$display_date = api_convert_and_format_date($results[$i][3], null, date_default_timezone_get());
7014
    				$line .= $results[$i][0].";".$display_date.";".$results[$i][1]." / ".$results[$i][2]."\n";
7015
    			}
7016
    		} else {
7017
                // istvan begin
7018
    			$NoTestRes = 1;
7019
    		}
7020
7021
    		// The Result of Tests
7022
    		if (is_array($hpresults)) {
7023
    			for($i = 0; $i < sizeof($hpresults); $i++) {
7024
    				$title = GetQuizName($hpresults[$i][0],'');
7025
7026
    				if ($title == '')
7027
    				$title = basename($hpresults[$i][0]);
7028
7029
    				$display_date = api_convert_and_format_date($hpresults[$i][3], null, date_default_timezone_get());
7030
7031
    				$line .= $title.';'.$display_date.';'.$hpresults[$i][1].'/'.$hpresults[$i][2]."\n";
7032
    			}
7033
    		} else {
7034
    			$NoHPTestRes = 1;
7035
    		}
7036
7037
    		if ($NoTestRes == 1 && $NoHPTestRes == 1) {
7038
    			$line=get_lang('NoResult');
7039
    		}
7040
    	} else {
7041
    		$new_view = substr_replace($view,'1',1,1);
7042
    	}
7043
    	return array($title_line, $line);
7044
    }
7045
7046
    /**
7047
     * Displays the student publications for a specific user in a specific course.
7048
     * @todo remove globals
7049
     */
7050
    public function display_student_publications_tracking_info($view, $user_id, $course_id)
7051
    {
7052
    	global $TABLETRACK_UPLOADS, $TABLECOURSE_WORK;
7053
        $_course = api_get_course_info();
7054
        $user_id = intval($user_id);
7055
        $course_id = intval($course_id);
7056
7057
    	if (substr($view,2,1) == '1') {
7058
    		$sql = "SELECT u.upload_date, w.title, w.author, w.url
7059
                    FROM $TABLETRACK_UPLOADS u , $TABLECOURSE_WORK w
7060
                    WHERE
7061
                        u.upload_work_id = w.id AND
7062
                        u.upload_user_id = '$user_id' AND
7063
                        u.c_id = '$course_id'
7064
                    ORDER BY u.upload_date DESC";
7065
    		$results = StatsUtils::getManyResultsXCol($sql,4);
7066
7067
    		$title[1]=get_lang('WorksDetails');
7068
    		$line='';
7069
    		$title_line=get_lang('WorkTitle').";".get_lang('WorkAuthors').";".get_lang('Date')."\n";
7070
7071
    		if (is_array($results)) {
7072
    			for($j = 0 ; $j < count($results) ; $j++) {
7073
    				$pathToFile = api_get_path(WEB_COURSE_PATH).$_course['path']."/".$results[$j][3];
7074
    				$beautifulDate = api_convert_and_format_date($results[$j][0], null, date_default_timezone_get());
7075
    				$line .= $results[$j][1].";".$results[$j][2].";".$beautifulDate."\n";
7076
    			}
7077
7078
    		} else {
7079
    			$line= get_lang('NoResult');
7080
    		}
7081
    	}
7082
    	return array($title_line, $line);
7083
    }
7084
7085
    /**
7086
     * Displays the links followed for a specific user in a specific course.
7087
     * @todo remove globals
7088
     */
7089
    public function display_links_tracking_info($view, $userId, $courseCode)
7090
    {
7091
    	global $TABLETRACK_LINKS, $TABLECOURSE_LINKS;
7092
        $courseId = api_get_course_int_id($courseCode);
7093
        $userId = intval($userId);
7094
        $line = null;
7095 View Code Duplication
    	if (substr($view,3,1) == '1') {
7096
    		$new_view = substr_replace($view,'0',3,1);
7097
    		$title[1]=get_lang('LinksDetails');
7098
    		$sql = "SELECT cl.title, cl.url
7099
                        FROM $TABLETRACK_LINKS AS sl, $TABLECOURSE_LINKS AS cl
7100
                        WHERE sl.links_link_id = cl.id
7101
                            AND sl.c_id = $courseId
7102
                            AND sl.links_user_id = $userId
7103
                        GROUP BY cl.title, cl.url";
7104
    		$results = StatsUtils::getManyResults2Col($sql);
7105
    		$title_line= get_lang('LinksTitleLinkColumn')."\n";
7106
    		if (is_array($results)) {
7107
    			for ($j = 0 ; $j < count($results) ; $j++) {
7108
    				$line .= $results[$j][0]."\n";
7109
    			}
7110
    		} else {
7111
    			$line=get_lang('NoResult');
7112
    		}
7113
    	} else {
7114
    		$new_view = substr_replace($view,'1',3,1);
7115
    	}
7116
    	return array($title_line, $line);
7117
    }
7118
7119
    /**
7120
     * Displays the documents downloaded for a specific user in a specific course.
7121
     * @param     string    kind of view inside tracking info
7122
     * @param    int        User id
7123
     * @param    string    Course code
7124
     * @param    int        Session id (optional, default = 0)
7125
     * @return     void
7126
     */
7127
    public function display_document_tracking_info($view, $user_id, $courseCode, $session_id = 0)
7128
    {
7129
    	// protect data
7130
    	$user_id     = intval($user_id);
7131
        $courseId = api_get_course_int_id($courseCode);
7132
    	$session_id = intval($session_id);
7133
7134
    	$downloads_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
7135
7136 View Code Duplication
    	if (substr($view,4,1) == '1') {
7137
    		$new_view = substr_replace($view,'0',4,1);
7138
    		$title[1]= get_lang('DocumentsDetails');
7139
7140
    		$sql = "SELECT down_doc_path
7141
                        FROM $downloads_table
7142
                        WHERE c_id = $courseId
7143
                            AND down_user_id = $user_id
7144
                            AND down_session_id = $session_id
7145
                        GROUP BY down_doc_path";
7146
7147
    		$results = StatsUtils::getManyResults1Col($sql);
7148
    		$title_line = get_lang('DocumentsTitleDocumentColumn')."\n";
7149
            $line = null;
7150
    		if (is_array($results)) {
7151
    			for ($j = 0 ; $j < count($results) ; $j++) {
7152
    				$line .= $results[$j]."\n";
7153
    			}
7154
    		} else {
7155
    			$line = get_lang('NoResult');
7156
    		}
7157
    	} else {
7158
    		$new_view = substr_replace($view,'1',4,1);
7159
    	}
7160
    	return array($title_line, $line);
7161
    }
7162
7163
    /**
7164
     * @param $userId
7165
     * @param $courseInfo
7166
     * @param int $sessionId
7167
     * @return array
7168
     */
7169
    public static function getToolInformation(
7170
        $userId,
7171
        $courseInfo,
7172
        $sessionId = 0
7173
    ) {
7174
        $csvContent = array();
7175
        $courseToolInformation = null;
7176
        $headerTool = array(
7177
            array(get_lang('Title')),
7178
            array(get_lang('CreatedAt')),
7179
            array(get_lang('UpdatedAt')),
7180
        );
7181
7182
        $headerListForCSV = array();
7183
        foreach ($headerTool as $item) {
7184
            $headerListForCSV[] = $item[0];
7185
        }
7186
7187
        $courseForumInformationArray = getForumCreatedByUser(
7188
            $userId,
7189
            $courseInfo['real_id'],
7190
            $sessionId
7191
        );
7192
7193
        if (!empty($courseForumInformationArray)) {
7194
            $csvContent[] = array();
7195
            $csvContent[] = get_lang('Forums');
7196
            $csvContent[] = $headerListForCSV;
7197
            foreach ($courseForumInformationArray as $row) {
7198
                $csvContent[] = $row;
7199
            }
7200
7201
            $courseToolInformation .= Display::page_subheader2(
7202
                get_lang('Forums')
7203
            );
7204
            $courseToolInformation .= Display::return_sortable_table(
7205
                $headerTool,
7206
                $courseForumInformationArray
7207
            );
7208
        }
7209
7210
        $courseWorkInformationArray = getWorkCreatedByUser(
7211
            $userId,
7212
            $courseInfo['real_id'],
7213
            $sessionId
7214
        );
7215
7216
        if (!empty($courseWorkInformationArray)) {
7217
            $csvContent[] = null;
7218
            $csvContent[] = get_lang('Works');
7219
            $csvContent[] = $headerListForCSV;
7220
7221
            foreach ($courseWorkInformationArray as $row) {
7222
                $csvContent[] = $row;
7223
            }
7224
            $csvContent[] = null;
7225
7226
            $courseToolInformation .= Display::page_subheader2(
7227
                get_lang('Works')
7228
            );
7229
            $courseToolInformation .= Display::return_sortable_table(
7230
                $headerTool,
7231
                $courseWorkInformationArray
7232
            );
7233
        }
7234
        $courseToolInformationTotal = null;
7235
7236
        if (!empty($courseToolInformation)) {
7237
            $sessionTitle = null;
7238
            if (!empty($sessionId)) {
7239
                $sessionTitle = ' ('.api_get_session_name($sessionId).')';
7240
            }
7241
7242
            $courseToolInformationTotal .= Display::page_subheader(
7243
                $courseInfo['title'].$sessionTitle
7244
            );
7245
            $courseToolInformationTotal .= $courseToolInformation;
7246
        }
7247
7248
        return array(
7249
            'array' => $csvContent,
7250
            'html' => $courseToolInformationTotal
7251
        );
7252
    }
7253
}
7254