Passed
Push — 1.10.x ( c1f149...c762b4 )
by
unknown
83:20 queued 31:10
created

Tracking::get_last_connection_date_on_the_course()   B

Complexity

Conditions 9
Paths 8

Size

Total Lines 54
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 54
rs 7.255
cc 9
eloc 37
nc 8
nop 4

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

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