Passed
Push — 1.10.x ( 98cf05...ef77fd )
by Yannick
414:03 queued 364:38
created

Tracking::count_number_of_posts_by_course()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 42
Code Lines 30

Duplication

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