Completed
Push — 1.10.x ( 0db498...531f7d )
by Julito
55:48 queued 23:11
created

Tracking::get_group_reporting()   C

Complexity

Conditions 10
Paths 13

Size

Total Lines 77
Code Lines 57

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 57
nc 13
nop 9
dl 0
loc 77
rs 5.6756
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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
use Chamilo\UserBundle\Entity\User;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, User.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
9
use Chamilo\CoreBundle\Entity\Course;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Course.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

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