Completed
Push — master ( 9b8b24...6e1754 )
by Julito
58:58
created

Tracking::getLpStats()   F

Complexity

Conditions 162
Paths > 20000

Size

Total Lines 1077
Code Lines 696

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 162
eloc 696
nc 55297
nop 13
dl 0
loc 1077
rs 2
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 ChamiloSession as Session;
5
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
6
use CpChart\Cache as pCache;
7
use CpChart\Data as pData;
8
use CpChart\Image as pImage;
9
use Chamilo\UserBundle\Entity\User;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, User. Consider defining an alias.

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\Course;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Course. Consider defining an alias.

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...
11
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
12
13
/**
14
 *  Class Tracking
15
 *
16
 *  @author  Julio Montoya <[email protected]>
17
 *  @package chamilo.library
18
 */
19
class Tracking
20
{
21
    /**
22
     * Get group reporting
23
     * @param int $course_id
24
     * @param int $sessionId
25
     * @param int $group_id
26
     * @param string $type
27
     * @param int $start
28
     * @param int $limit
29
     * @param int $sidx
30
     * @param string $sord
31
     * @param array $where_condition
32
     * @return array|null
33
     */
34
    public static function get_group_reporting(
35
        $course_id,
36
        $sessionId = 0,
37
        $group_id = 0,
0 ignored issues
show
Unused Code introduced by
The parameter $group_id is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

37
        /** @scrutinizer ignore-unused */ $group_id = 0,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
38
        $type = 'all',
39
        $start = 0,
0 ignored issues
show
Unused Code introduced by
The parameter $start is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

39
        /** @scrutinizer ignore-unused */ $start = 0,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
40
        $limit = 1000,
0 ignored issues
show
Unused Code introduced by
The parameter $limit is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

40
        /** @scrutinizer ignore-unused */ $limit = 1000,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
41
        $sidx = 1,
0 ignored issues
show
Unused Code introduced by
The parameter $sidx is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

41
        /** @scrutinizer ignore-unused */ $sidx = 1,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
42
        $sord = 'desc',
0 ignored issues
show
Unused Code introduced by
The parameter $sord is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

42
        /** @scrutinizer ignore-unused */ $sord = 'desc',

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
43
        $where_condition = array()
0 ignored issues
show
Unused Code introduced by
The parameter $where_condition is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

43
        /** @scrutinizer ignore-unused */ $where_condition = array()

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
44
    ) {
45
        $course_id = (int) $course_id;
46
        $sessionId = (int) $sessionId;
47
48
        if (empty($course_id)) {
49
            return null;
50
        }
51
        $courseInfo = api_get_course_info_by_id($course_id);
52
        if ($type == 'count') {
53
            return GroupManager::get_group_list(null, $courseInfo, null, $sessionId, true);
54
        }
55
56
        $groupList = GroupManager::get_group_list(null, $courseInfo, null, $sessionId);
57
        $parsedResult = array();
58
        if (!empty($groupList)) {
59
            foreach ($groupList as $group) {
60
                $users = GroupManager::get_users($group['id'], true, null, null, false, $courseInfo['real_id']);
61
                $time = 0;
62
                $avg_student_score = 0;
63
                $avg_student_progress = 0;
64
                $work = 0;
65
                $messages = 0;
66
67
                foreach ($users as $user_data) {
68
                    $time += self::get_time_spent_on_the_course(
69
                        $user_data['user_id'],
70
                        $courseInfo['real_id'],
71
                        $sessionId
72
                    );
73
                    $avg_student_score += self::get_avg_student_score(
74
                        $user_data['user_id'],
75
                        $courseInfo['code'],
76
                        array(),
77
                        $sessionId
78
                    );
79
                    $avg_student_progress += self::get_avg_student_progress(
80
                        $user_data['user_id'],
81
                        $courseInfo['code'],
82
                        array(),
83
                        $sessionId
84
                    );
85
                    $work += self::count_student_assignments(
86
                        $user_data['user_id'],
87
                        $courseInfo['code'],
88
                        $sessionId
89
                    );
90
                    $messages += self::count_student_messages(
91
                        $user_data['user_id'],
92
                        $courseInfo['code'],
93
                        $sessionId
94
                    );
95
                }
96
97
                $countUsers = count($users);
98
                $averageProgress = empty($countUsers) ? 0 : round($avg_student_progress / $countUsers, 2);
99
                $averageScore = empty($countUsers) ? 0 : round($avg_student_score / $countUsers, 2);
100
101
                $groupItem = array(
102
                    'id' => $group['id'],
103
                    'name' => $group['name'],
104
                    'time' => api_time_to_hms($time),
105
                    'progress' => $averageProgress,
106
                    'score' => $averageScore,
107
                    'works' => $work,
108
                    'messages' => $messages,
109
                );
110
                $parsedResult[] = $groupItem;
111
            }
112
        }
113
114
        return $parsedResult;
115
    }
116
117
    /**
118
     * @param int $user_id
119
     * @param array $courseInfo
120
     * @param int $session_id
121
     * @param string $origin
122
     * @param bool $export_csv
123
     * @param int $lp_id
124
     * @param int $lp_item_id
125
     * @param int $extendId
126
     * @param int $extendAttemptId
127
     * @param string $extendedAttempt
128
     * @param string $extendedAll
129
     * @param string $type classic or simple
130
     * @param boolean $allowExtend Optional. Allow or not extend te results
131
     * @return null|string
132
     */
133
    public static function getLpStats(
134
        $user_id,
135
        $courseInfo,
136
        $session_id,
137
        $origin,
138
        $export_csv,
139
        $lp_id,
140
        $lp_item_id = null,
141
        $extendId = null,
142
        $extendAttemptId = null,
143
        $extendedAttempt = null,
144
        $extendedAll = null,
145
        $type = 'classic',
146
        $allowExtend = true
147
    ) {
148
        if (empty($courseInfo) || empty($lp_id)) {
149
            return null;
150
        }
151
152
        $hideTime = api_get_configuration_value('hide_lp_time');
153
154
        $lp_id = intval($lp_id);
155
        $lp_item_id = intval($lp_item_id);
156
        $user_id = intval($user_id);
157
        $session_id = intval($session_id);
158
        $origin = Security::remove_XSS($origin);
159
        $list = learnpath::get_flat_ordered_items_list($lp_id, 0, $courseInfo['real_id']);
160
        $is_allowed_to_edit = api_is_allowed_to_edit(null, true);
161
        $course_id = $courseInfo['real_id'];
162
        $courseCode = $courseInfo['code'];
163
        $session_condition = api_get_session_condition($session_id);
164
165
        // Extend all button
166
        $output = null;
167
        $extend_all = 0;
168
169
        if ($origin == 'tracking') {
170
            $url_suffix = '&session_id='.$session_id.'&course='.$courseCode.'&student_id='.$user_id.'&lp_id='.$lp_id.'&origin='.$origin;
171
        } else {
172
            $url_suffix = '&lp_id='.$lp_id;
173
        }
174
175
        if (!empty($extendedAll)) {
176
            $extend_all_link = Display::url(
177
                Display::return_icon('view_less_stats.gif', get_lang('HideAllAttempts')),
178
                api_get_self().'?action=stats'.$url_suffix
179
            );
180
            $extend_all = 1;
181
        } else {
182
            $extend_all_link = Display::url(
183
                Display::return_icon('view_more_stats.gif', get_lang('ShowAllAttempts')),
184
                api_get_self().'?action=stats&extend_all=1'.$url_suffix
185
            );
186
        }
187
188
        if ($origin != 'tracking') {
189
            $output .= '<div class="section-status">';
190
            $output .= Display::page_header(get_lang('ScormMystatus'));
191
            $output .= '</div>';
192
        }
193
194
        $actionColumn = null;
195
        if ($type == 'classic') {
196
            $actionColumn = ' <th>'.get_lang('Actions').'</th>';
197
        }
198
199
        $timeHeader = '<th class="lp_time" colspan="2">'.get_lang('ScormTime').'</th>';
200
        if ($hideTime) {
201
            $timeHeader = '';
202
        }
203
        $output .= '<div class="table-responsive">';
204
        $output .= '<table id="lp_tracking" class="table tracking">
205
            <thead>
206
            <tr class="table-header">
207
                <th width="16">' . ($allowExtend == true ? $extend_all_link : '&nbsp;').'</th>
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
208
                <th colspan="4">
209
                    ' . get_lang('ScormLessonTitle').'
210
                </th>
211
                <th colspan="2">
212
                    ' . get_lang('ScormStatus').'
213
                </th>
214
                <th colspan="2">
215
                    ' . get_lang('ScormScore').'
216
                </th>
217
                '.$timeHeader.'
218
                '.$actionColumn.'
219
                </tr>
220
            </thead>
221
            <tbody>
222
        ';
223
224
        // Going through the items using the $items[] array instead of the database order ensures
225
        // we get them in the same order as in the imsmanifest file, which is rather random when using
226
        // the database table.
227
        $TBL_LP_ITEM = Database::get_course_table(TABLE_LP_ITEM);
228
        $TBL_LP_ITEM_VIEW = Database::get_course_table(TABLE_LP_ITEM_VIEW);
229
        $TBL_LP_VIEW = Database::get_course_table(TABLE_LP_VIEW);
230
        $tbl_quiz_questions = Database::get_course_table(TABLE_QUIZ_QUESTION);
231
        $TBL_QUIZ = Database::get_course_table(TABLE_QUIZ_TEST);
232
        $tbl_stats_exercices = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
233
        $tbl_stats_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
234
235
        $sql = "SELECT max(view_count)
236
                FROM $TBL_LP_VIEW
237
                WHERE
238
                    c_id = $course_id AND
239
                    lp_id = $lp_id AND
240
                    user_id = $user_id
241
                    $session_condition";
242
        $res = Database::query($sql);
243
        $view = '';
244
        if (Database::num_rows($res) > 0) {
245
            $myrow = Database::fetch_array($res);
246
            $view = $myrow[0];
247
        }
248
249
        $counter = 0;
250
        $total_time = 0;
251
        $h = get_lang('h');
252
253
        if (!empty($export_csv)) {
254
            $csvHeaders = array(
255
                get_lang('ScormLessonTitle'),
256
                get_lang('ScormStatus'),
257
                get_lang('ScormScore')
258
            );
259
260
            if ($hideTime === false) {
261
                $csvHeaders[] = get_lang('ScormTime');
262
            }
263
264
            $csv_content[] = $csvHeaders;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$csv_content was never initialized. Although not strictly required by PHP, it is generally a good practice to add $csv_content = array(); before regardless.
Loading history...
265
        }
266
267
        $result_disabled_ext_all = true;
268
        $chapterTypes = learnpath::getChapterTypes();
269
270
        // Show lp items
271
        if (is_array($list) && count($list) > 0) {
272
            foreach ($list as $my_item_id) {
273
                $extend_this = 0;
274
                $order = 'DESC';
275
                if ((!empty($extendId) && $extendId == $my_item_id) || $extend_all) {
276
                    $extend_this = 1;
277
                    $order = 'ASC';
278
                }
279
280
                // Prepare statement to go through each attempt.
281
                $viewCondition = null;
282
                if (!empty($view)) {
283
                    $viewCondition = " AND v.view_count = $view  ";
284
                }
285
286
                $sql = "SELECT
287
                    iv.status as mystatus,
288
                    v.view_count as mycount,
289
                    iv.score as myscore,
290
                    iv.total_time as mytime,
291
                    i.id as myid,
292
                    i.lp_id as mylpid,
293
                    iv.lp_view_id as mylpviewid,
294
                    i.title as mytitle,
295
                    i.max_score as mymaxscore,
296
                    iv.max_score as myviewmaxscore,
297
                    i.item_type as item_type,
298
                    iv.view_count as iv_view_count,
299
                    iv.id as iv_id,
300
                    path
301
                FROM $TBL_LP_ITEM as i
302
                INNER JOIN $TBL_LP_ITEM_VIEW as iv
303
                ON (i.id = iv.lp_item_id AND i.c_id = iv.c_id)
304
                INNER JOIN $TBL_LP_VIEW as v
305
                ON (iv.lp_view_id = v.id AND v.c_id = iv.c_id)
306
                WHERE
307
                    v.c_id = $course_id AND
308
                    i.id = $my_item_id AND
309
                    i.lp_id = $lp_id  AND
310
                    v.user_id = $user_id AND
311
                    v.session_id = $session_id
312
                    $viewCondition
313
                ORDER BY iv.view_count $order ";
314
315
                $result = Database::query($sql);
316
                $num = Database::num_rows($result);
317
                $time_for_total = 0;
318
319
                // Extend all
320
                if (($extend_this || $extend_all) && $num > 0) {
321
                    $row = Database::fetch_array($result);
322
                    $result_disabled_ext_all = false;
323
                    if ($row['item_type'] == 'quiz') {
324
                        // Check results_disabled in quiz table.
325
                        $my_path = Database::escape_string($row['path']);
326
327
                        $sql = "SELECT results_disabled
328
                                FROM $TBL_QUIZ
329
                                WHERE
330
                                    c_id = $course_id AND
331
                                    id ='".$my_path."'";
332
                        $res_result_disabled = Database::query($sql);
333
                        $row_result_disabled = Database::fetch_row($res_result_disabled);
334
335
                        if (Database::num_rows($res_result_disabled) > 0 &&
336
                            (int) $row_result_disabled[0] === 1
337
                        ) {
338
                            $result_disabled_ext_all = true;
339
                        }
340
                    }
341
342
                    // If there are several attempts, and the link to extend has been clicked, show each attempt...
343
                    if (($counter % 2) == 0) {
344
                        $oddclass = 'row_odd';
345
                    } else {
346
                        $oddclass = 'row_even';
347
                    }
348
349
                    $extend_link = '';
350
                    if (!empty($inter_num)) {
351
                        $extend_link = Display::url(
352
                            Display::return_icon(
353
                                'visible.gif',
354
                                get_lang('HideAttemptView')
355
                            ),
356
                            api_get_self().'?action=stats&fold_id='.$my_item_id.$url_suffix
357
                        );
358
                    }
359
                    $title = $row['mytitle'];
360
361
                    if (empty($title)) {
362
                        $title = learnpath::rl_get_resource_name($courseInfo['code'], $lp_id, $row['myid']);
363
                    }
364
365
                    if (in_array($row['item_type'], $chapterTypes)) {
366
                        $title = "<h4> $title </h4>";
367
                    }
368
                    $lesson_status = $row['mystatus'];
369
                    $title = Security::remove_XSS($title);
370
                    $counter++;
371
372
                    $action = null;
373
                    if ($type == 'classic') {
374
                        $action = '<td></td>';
375
                    }
376
377
                    if (in_array($row['item_type'], $chapterTypes)) {
378
                        $output .= '<tr class="'.$oddclass.'">
379
                                <td>'.$extend_link.'</td>
380
                                <td colspan="4">
381
                                   '.$title.'
382
                                </td>
383
                                <td colspan="2">'.learnpathItem::humanize_status($lesson_status, true, $type).'</td>
384
                                <td colspan="2"></td>
385
                                <td colspan="2"></td>
386
                                '.$action.'
387
                            </tr>';
388
                        continue;
389
                    } else {
390
                        $output .= '<tr class="'.$oddclass.'">
391
                                <td>'.$extend_link.'</td>
392
                                <td colspan="4">
393
                                   '.$title.'
394
                                </td>
395
                                <td colspan="2"></td>
396
                                <td colspan="2"></td>
397
                                <td colspan="2"></td>
398
                                '.$action.'
399
                            </tr>';
400
                    }
401
402
                    $attemptCount = 1;
403
                    do {
404
                        // Check if there are interactions below.
405
                        $extend_attempt_link = '';
406
                        $extend_this_attempt = 0;
407
408
                        if ((learnpath::get_interactions_count_from_db($row['iv_id'], $course_id) > 0 ||
409
                            learnpath::get_objectives_count_from_db($row['iv_id'], $course_id) > 0) &&
410
                            !$extend_all
411
                        ) {
412
                            if ($extendAttemptId == $row['iv_id']) {
413
                                // The extend button for this attempt has been clicked.
414
                                $extend_this_attempt = 1;
415
                                $extend_attempt_link = Display::url(
416
                                    Display::return_icon('visible.gif', get_lang('HideAttemptView')),
417
                                    api_get_self().'?action=stats&extend_id='.$my_item_id.'&fold_attempt_id='.$row['iv_id'].$url_suffix
418
                                );
419
                            } else { // Same case if fold_attempt_id is set, so not implemented explicitly.
420
                                // The extend button for this attempt has not been clicked.
421
                                $extend_attempt_link = Display::url(
422
                                    Display::return_icon('invisible.gif', get_lang('ExtendAttemptView')),
423
                                    api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix
424
                                );
425
                            }
426
                        }
427
428
                        if (($counter % 2) == 0) {
429
                            $oddclass = 'row_odd';
430
                        } else {
431
                            $oddclass = 'row_even';
432
                        }
433
434
                        $lesson_status = $row['mystatus'];
435
                        $score = $row['myscore'];
436
                        $time_for_total = $row['mytime'];
437
                        $time = learnpathItem::getScormTimeFromParameter('js', $row['mytime']);
438
439
                        if ($score == 0) {
440
                            $maxscore = $row['mymaxscore'];
441
                        } else {
442
                            if ($row['item_type'] == 'sco') {
443
                                if (!empty($row['myviewmaxscore']) && $row['myviewmaxscore'] > 0) {
444
                                    $maxscore = $row['myviewmaxscore'];
445
                                } elseif ($row['myviewmaxscore'] === '') {
446
                                    $maxscore = 0;
447
                                } else {
448
                                    $maxscore = $row['mymaxscore'];
449
                                }
450
                            } else {
451
                                $maxscore = $row['mymaxscore'];
452
                            }
453
                        }
454
455
                        // Remove "NaN" if any (@todo: locate the source of these NaN)
456
                        $time = str_replace('NaN', '00'.$h.'00\'00"', $time);
457
458
                        if ($row['item_type'] != 'dir') {
459
                            if (!$is_allowed_to_edit && $result_disabled_ext_all) {
460
                                $view_score = Display::return_icon(
461
                                    'invisible.gif',
462
                                    get_lang('ResultsHiddenByExerciseSetting')
463
                                );
464
                            } else {
465
                                switch ($row['item_type']) {
466
                                    case 'sco':
467
                                        if ($maxscore == 0) {
468
                                            $view_score = $score;
469
                                        } else {
470
                                            $view_score = ExerciseLib::show_score(
471
                                                $score,
472
                                                $maxscore,
473
                                                false
474
                                            );
475
                                        }
476
                                        break;
477
                                    case 'document':
478
                                        $view_score = ($score == 0 ? '/' : ExerciseLib::show_score($score, $maxscore, false));
479
                                        break;
480
                                    default:
481
                                        $view_score = ExerciseLib::show_score(
482
                                            $score,
483
                                            $maxscore,
484
                                            false
485
                                        );
486
                                        break;
487
                                }
488
                            }
489
490
                            $action = null;
491
                            if ($type == 'classic') {
492
                                $action = '<td></td>';
493
                            }
494
                            $timeRow = '<td class="lp_time" colspan="2">'.$time.'</td>';
495
                            if ($hideTime) {
496
                                $timeRow = '';
497
                            }
498
                            $output .= '<tr class="'.$oddclass.'">
499
                                    <td></td>
500
                                    <td>' . $extend_attempt_link.'</td>
501
                                    <td colspan="3">' . get_lang('Attempt').' '.$attemptCount.'</td>
502
                                    <td colspan="2">' . learnpathItem::humanize_status($lesson_status, true, $type).'</td>
503
                                    <td colspan="2">' . $view_score.'</td>
504
                                    '.$timeRow.'
505
                                    '.$action.'
506
                                </tr>';
507
                            $attemptCount++;
508
                            if (!empty($export_csv)) {
509
                                $temp = array();
510
                                $temp[] = $title = Security::remove_XSS($title);
511
                                $temp[] = Security::remove_XSS(
512
                                    learnpathItem::humanize_status($lesson_status, false, $type)
513
                                );
514
515
                                if ($row['item_type'] == 'quiz') {
516
                                    if (!$is_allowed_to_edit && $result_disabled_ext_all) {
517
                                        $temp[] = '/';
518
                                    } else {
519
                                        $temp[] = ($score == 0 ? '0/'.$maxscore : ($maxscore == 0 ? $score : $score.'/'.float_format($maxscore, 1)));
520
                                    }
521
                                } else {
522
                                    $temp[] = ($score == 0 ? '/' : ($maxscore == 0 ? $score : $score.'/'.float_format($maxscore, 1)));
523
                                }
524
525
                                if ($hideTime === false) {
526
                                    $temp[] = $time;
527
                                }
528
                                $csv_content[] = $temp;
529
                            }
530
                        }
531
532
                        $counter++;
533
                        $action = null;
534
                        if ($type == 'classic') {
535
                            $action = '<td></td>';
536
                        }
537
538
                        if ($extend_this_attempt || $extend_all) {
539
                            $list1 = learnpath::get_iv_interactions_array($row['iv_id']);
540
                            foreach ($list1 as $id => $interaction) {
541
                                if (($counter % 2) == 0) {
542
                                    $oddclass = 'row_odd';
543
                                } else {
544
                                    $oddclass = 'row_even';
545
                                }
546
                                $student_response = urldecode($interaction['student_response']);
547
                                $content_student_response = explode('__|', $student_response);
548
549
                                if (count($content_student_response) > 0) {
550
                                    if (count($content_student_response) >= 3) {
551
                                        // Pop the element off the end of array.
552
                                        array_pop($content_student_response);
553
                                    }
554
                                    $student_response = implode(',', $content_student_response);
555
                                }
556
557
                                $timeRow = '<td class="lp_time">'.$interaction['time'].'</td>';
558
                                if ($hideTime) {
559
                                    $timeRow = '';
560
                                }
561
562
                                $output .= '<tr class="'.$oddclass.'">
563
                                        <td></td>
564
                                        <td></td>
565
                                        <td></td>
566
                                        <td>'.$interaction['order_id'].'</td>
567
                                        <td>'.$interaction['id'].'</td>
568
                                        <td colspan="2">' . $interaction['type'].'</td>
569
                                        <td>'.$student_response.'</td>
570
                                        <td>'.$interaction['result'].'</td>
571
                                        <td>'.$interaction['latency'].'</td>
572
                                        '.$timeRow.'
573
                                        '.$action.'
574
                                    </tr>';
575
                                $counter++;
576
                            }
577
                            $list2 = learnpath::get_iv_objectives_array($row['iv_id']);
578
                            foreach ($list2 as $id => $interaction) {
579
                                if (($counter % 2) == 0) {
580
                                    $oddclass = 'row_odd';
581
                                } else {
582
                                    $oddclass = 'row_even';
583
                                }
584
                                $output .= '<tr class="'.$oddclass.'">
585
                                        <td></td>
586
                                        <td></td>
587
                                        <td></td>
588
                                        <td>' . $interaction['order_id'].'</td>
589
                                        <td colspan="2">' . $interaction['objective_id'].'</td>
590
                                        <td colspan="2">' . $interaction['status'].'</td>
591
                                        <td>' . $interaction['score_raw'].'</td>
592
                                        <td>' . $interaction['score_max'].'</td>
593
                                        <td>' . $interaction['score_min'].'</td>
594
                                        '.$action.'
595
                                     </tr>';
596
                                $counter++;
597
                            }
598
                        }
599
                    } while ($row = Database::fetch_array($result));
600
                } elseif ($num > 0) {
601
                    // Not extended.
602
                    $row = Database::fetch_array($result, 'ASSOC');
603
                    $my_id = $row['myid'];
604
                    $my_lp_id = $row['mylpid'];
605
                    $my_lp_view_id = $row['mylpviewid'];
606
                    $my_path = $row['path'];
607
                    $result_disabled_ext_all = false;
608
609
                    if ($row['item_type'] == 'quiz') {
610
                        // Check results_disabled in quiz table.
611
                        $my_path = Database::escape_string($my_path);
612
                        $sql = "SELECT results_disabled
613
                                FROM $TBL_QUIZ
614
                                WHERE c_id = $course_id AND id ='".$my_path."'";
615
                        $res_result_disabled = Database::query($sql);
616
                        $row_result_disabled = Database::fetch_row($res_result_disabled);
617
618
                        if (Database::num_rows($res_result_disabled) > 0 &&
619
                            (int) $row_result_disabled[0] === 1
620
                        ) {
621
                            $result_disabled_ext_all = true;
622
                        }
623
                    }
624
625
                    // Check if there are interactions below
626
                    $extend_this_attempt = 0;
627
                    $inter_num = learnpath::get_interactions_count_from_db($row['iv_id'], $course_id);
628
                    $objec_num = learnpath::get_objectives_count_from_db($row['iv_id'], $course_id);
629
                    $extend_attempt_link = '';
630
                    if ($inter_num > 0 || $objec_num > 0) {
631
                        if (!empty($extendAttemptId) && $extendAttemptId == $row['iv_id']) {
632
                            // The extend button for this attempt has been clicked.
633
                            $extend_this_attempt = 1;
634
                            $extend_attempt_link = Display::url(
635
                                Display::return_icon('visible.gif', get_lang('HideAttemptView')),
636
                                api_get_self().'?action=stats&extend_id='.$my_item_id.'&fold_attempt_id='.$row['iv_id'].$url_suffix
637
                            );
638
                        } else {
639
                            // Same case if fold_attempt_id is set, so not implemented explicitly.
640
                            // The extend button for this attempt has not been clicked.
641
                            $extend_attempt_link = Display::url(
642
                                Display::return_icon('invisible.gif', get_lang('ExtendAttemptView')),
643
                                api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix
644
                            );
645
                        }
646
                    }
647
648
                    if (($counter % 2) == 0) {
649
                        $oddclass = 'row_odd';
650
                    } else {
651
                        $oddclass = 'row_even';
652
                    }
653
654
                    $extend_link = '';
655
                    if ($inter_num > 1) {
656
                        $extend_link = Display::url(
657
                            Display::return_icon('invisible.gif', get_lang('ExtendAttemptView')),
658
                            api_get_self().'?action=stats&extend_id='.$my_item_id.'&extend_attempt_id='.$row['iv_id'].$url_suffix
659
                        );
660
                    }
661
662
                    $lesson_status = $row['mystatus'];
663
                    $score = $row['myscore'];
664
                    $subtotal_time = $row['mytime'];
665
666
                    while ($tmp_row = Database::fetch_array($result)) {
667
                        $subtotal_time += $tmp_row['mytime'];
668
                    }
669
                    $title = $row['mytitle'];
670
                    // Selecting the exe_id from stats attempts tables in order to look the max score value.
671
                    $sql = 'SELECT * FROM '.$tbl_stats_exercices.'
672
                            WHERE
673
                                exe_exo_id="'.$row['path'].'" AND
674
                                exe_user_id="'.$user_id.'" AND
675
                                orig_lp_id = "'.$lp_id.'" AND
676
                                orig_lp_item_id = "'.$row['myid'].'" AND
677
                                c_id = '.$course_id.' AND
678
                                status <> "incomplete" AND
679
                                session_id = '.$session_id.'
680
                             ORDER BY exe_date DESC
681
                             LIMIT 1';
682
683
                    $resultLastAttempt = Database::query($sql);
684
                    $num = Database::num_rows($resultLastAttempt);
685
                    $id_last_attempt = null;
686
                    if ($num > 0) {
687
                        while ($rowLA = Database::fetch_array($resultLastAttempt)) {
688
                            $id_last_attempt = $rowLA['exe_id'];
689
                        }
690
                    }
691
692
                    switch ($row['item_type']) {
693
                        case 'sco':
694
                            if (!empty($row['myviewmaxscore']) and $row['myviewmaxscore'] > 0) {
695
                                $maxscore = $row['myviewmaxscore'];
696
                            } elseif ($row['myviewmaxscore'] === '') {
697
                                $maxscore = 0;
698
                            } else {
699
                                $maxscore = $row['mymaxscore'];
700
                            }
701
                            break;
702
                        case 'quiz':
703
                            // Get score and total time from last attempt of a exercise en lp.
704
                            $sql = "SELECT score
705
                                    FROM $TBL_LP_ITEM_VIEW
706
                                    WHERE
707
                                        c_id = $course_id AND
708
                                        lp_item_id = '".(int) $my_id."' AND
709
                                        lp_view_id = '" . (int) $my_lp_view_id."'
710
                                    ORDER BY view_count DESC limit 1";
711
                            $res_score = Database::query($sql);
712
                            $row_score = Database::fetch_array($res_score);
713
714
                            $sql = "SELECT SUM(total_time) as total_time
715
                                    FROM $TBL_LP_ITEM_VIEW
716
                                    WHERE
717
                                        c_id = $course_id AND
718
                                        lp_item_id = '".(int) $my_id."' AND
719
                                        lp_view_id = '" . (int) $my_lp_view_id."'";
720
                            $res_time = Database::query($sql);
721
                            $row_time = Database::fetch_array($res_time);
722
723
                            if (Database::num_rows($res_score) > 0 &&
724
                                Database::num_rows($res_time) > 0
725
                            ) {
726
                                $score = (float) $row_score['score'];
727
                                $subtotal_time = (int) $row_time['total_time'];
728
                            } else {
729
                                $score = 0;
730
                                $subtotal_time = 0;
731
                            }
732
733
                            // Selecting the max score from an attempt.
734
                            $sql = "SELECT SUM(t.ponderation) as maxscore
735
                                    FROM (
736
                                        SELECT DISTINCT
737
                                            question_id, marks, ponderation
738
                                        FROM $tbl_stats_attempts as at
739
                                        INNER JOIN $tbl_quiz_questions as q
740
                                        ON (q.id = at.question_id AND q.c_id = $course_id)
741
                                        WHERE exe_id ='$id_last_attempt'
742
                                    ) as t";
743
744
                            $result = Database::query($sql);
745
                            $row_max_score = Database::fetch_array($result);
746
                            $maxscore = $row_max_score['maxscore'];
747
                            break;
748
                        default:
749
                            $maxscore = $row['mymaxscore'];
750
                            break;
751
                    }
752
753
                    $time_for_total = $subtotal_time;
754
                    $time = learnpathItem::getScormTimeFromParameter(
755
                        'js',
756
                        $subtotal_time
757
                    );
758
                    if (empty($title)) {
759
                        $title = learnpath::rl_get_resource_name(
760
                            $courseInfo['code'],
761
                            $lp_id,
762
                            $row['myid']
763
                        );
764
                    }
765
766
                    $action = null;
767
                    if ($type == 'classic') {
768
                        $action = '<td></td>';
769
                    }
770
771
                    if (in_array($row['item_type'], $chapterTypes)) {
772
                        $title = Security::remove_XSS($title);
773
                        $output .= '<tr class="'.$oddclass.'">
774
                                <td>'.$extend_link.'</td>
775
                                <td colspan="4">
776
                                <h4>'.$title.'</h4>
777
                                </td>
778
                                <td colspan="2">'.learnpathitem::humanize_status($lesson_status).'</td>
779
                                <td colspan="2"></td>
780
                                <td colspan="2"></td>
781
                                '.$action.'
782
                            </tr>';
783
                    } else {
784
                        $correct_test_link = '-';
785
                        $showRowspan = false;
786
                        if ($row['item_type'] == 'quiz') {
787
                            $my_url_suffix = '&course='.$courseCode.'&student_id='.$user_id.'&lp_id='.intval($row['mylpid']).'&origin='.$origin;
788
                            $sql = 'SELECT * FROM '.$tbl_stats_exercices.'
789
                                     WHERE
790
                                        exe_exo_id="' . $row['path'].'" AND
791
                                        exe_user_id="' . $user_id.'" AND
792
                                        orig_lp_id = "' . $lp_id.'" AND
793
                                        orig_lp_item_id = "' . $row['myid'].'" AND
794
                                        c_id = ' . $course_id.' AND
795
                                        status <> "incomplete" AND
796
                                        session_id = ' . $session_id.'
797
                                     ORDER BY exe_date DESC ';
798
799
                            $resultLastAttempt = Database::query($sql);
800
                            $num = Database::num_rows($resultLastAttempt);
801
                            $showRowspan = false;
802
                            if ($num > 0) {
803
                                $linkId = 'link_'.$my_id;
804
                                if ($extendedAttempt == 1 &&
805
                                    $lp_id == $my_lp_id &&
806
                                    $lp_item_id == $my_id
807
                                ) {
808
                                    $showRowspan = true;
809
                                    $correct_test_link = Display::url(
810
                                        Display::return_icon(
811
                                            'view_less_stats.gif',
812
                                            get_lang('HideAllAttempts')
813
                                        ),
814
                                        api_get_self().'?action=stats'.$my_url_suffix.'&session_id='.$session_id.'&lp_item_id='.$my_id.'#'.$linkId,
815
                                        ['id' => $linkId]
816
                                    );
817
                                } else {
818
                                    $correct_test_link = Display::url(
819
                                        Display::return_icon(
820
                                            'view_more_stats.gif',
821
                                            get_lang(
822
                                                'ShowAllAttemptsByExercise'
823
                                            )
824
                                        ),
825
                                        api_get_self().'?action=stats&extend_attempt=1'.$my_url_suffix.'&session_id='.$session_id.'&lp_item_id='.$my_id.'#'.$linkId,
826
                                        ['id' => $linkId]
827
                                    );
828
                                }
829
                            }
830
                        }
831
832
                        $title = Security::remove_XSS($title);
833
                        $action = null;
834
                        if ($type == 'classic') {
835
                            $action = '<td '.($showRowspan ? 'rowspan="2"' : '').'>'.$correct_test_link.'</td>';
836
                        }
837
838
                        if ($lp_id == $my_lp_id && false) {
839
                            $output .= '<tr class ='.$oddclass.'>
840
                                    <td>' . $extend_link.'</td>
841
                                    <td colspan="4">' . $title.'</td>
842
                                    <td colspan="2">&nbsp;</td>
843
                                    <td colspan="2">&nbsp;</td>
844
                                    <td colspan="2">&nbsp;</td>
845
                                    '.$action.'
846
                                </tr>';
847
                            $output .= '</tr>';
848
                        } else {
849
                            if ($lp_id == $my_lp_id && $lp_item_id == $my_id) {
850
                                $output .= "<tr class='$oddclass'>";
851
                            } else {
852
                                $output .= "<tr class='$oddclass'>";
853
                            }
854
855
                            $scoreItem = null;
856
                            if ($row['item_type'] == 'quiz') {
857
                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
858
                                    $scoreItem .= Display::return_icon(
859
                                        'invisible.gif',
860
                                        get_lang('ResultsHiddenByExerciseSetting')
861
                                    );
862
                                } else {
863
                                    $scoreItem .= ExerciseLib::show_score($score, $maxscore, false);
864
                                }
865
                            } else {
866
                                $scoreItem .= $score == 0 ? '/' : ($maxscore == 0 ? $score : $score.'/'.$maxscore);
867
                            }
868
869
                            $timeRow = '<td class="lp_time" colspan="2">'.$time.'</td>';
870
                            if ($hideTime) {
871
                                $timeRow = '';
872
                            }
873
874
                            $output .= '
875
                                <td>'.$extend_link.'</td>
876
                                <td colspan="4">' . $title.'</td>
877
                                <td colspan="2">' . learnpathitem::humanize_status($lesson_status).'</td>
878
                                <td colspan="2">'.$scoreItem.'</td>
879
                                '.$timeRow.'
880
                                '.$action.'
881
                             ';
882
                            $output .= '</tr>';
883
                        }
884
885
                        if (!empty($export_csv)) {
886
                            $temp = array();
887
                            $temp[] = api_html_entity_decode($title, ENT_QUOTES);
888
                            $temp[] = api_html_entity_decode($lesson_status, ENT_QUOTES);
889
890
                            if ($row['item_type'] == 'quiz') {
891
                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
892
                                    $temp[] = '/';
893
                                } else {
894
                                    $temp[] = ($score == 0 ? '0/'.$maxscore : ($maxscore == 0 ? $score : $score.'/'.float_format($maxscore, 1)));
895
                                }
896
                            } else {
897
                                $temp[] = ($score == 0 ? '/' : ($maxscore == 0 ? $score : $score.'/'.float_format($maxscore, 1)));
898
                            }
899
900
                            if ($hideTime === false) {
901
                                $temp[] = $time;
902
                            }
903
                            $csv_content[] = $temp;
904
                        }
905
                    }
906
907
                    $counter++;
908
909
                    $action = null;
910
                    if ($type == 'classic') {
911
                        $action = '<td></td>';
912
                    }
913
914
                    if ($extend_this_attempt || $extend_all) {
915
                        $list1 = learnpath::get_iv_interactions_array($row['iv_id']);
916
                        foreach ($list1 as $id => $interaction) {
917
                            if (($counter % 2) == 0) {
918
                                $oddclass = 'row_odd';
919
                            } else {
920
                                $oddclass = 'row_even';
921
                            }
922
923
                            $timeRow = '<td class="lp_time">'.$interaction['time'].'</td>';
924
                            if ($hideTime) {
925
                                $timeRow = '';
926
                            }
927
928
                            $output .= '<tr class="'.$oddclass.'">
929
                                    <td></td>
930
                                    <td></td>
931
                                    <td></td>
932
                                    <td>'.$interaction['order_id'].'</td>
933
                                    <td>'.$interaction['id'].'</td>
934
                                    <td colspan="2">' . $interaction['type'].'</td>
935
                                    <td>'.urldecode($interaction['student_response']).'</td>
936
                                    <td>'.$interaction['result'].'</td>
937
                                    <td>'.$interaction['latency'].'</td>
938
                                    '.$timeRow.'
939
                                    '.$action.'
940
                               </tr>';
941
                            $counter++;
942
                        }
943
                        $list2 = learnpath::get_iv_objectives_array($row['iv_id']);
944
                        foreach ($list2 as $id => $interaction) {
945
                            if (($counter % 2) == 0) {
946
                                $oddclass = 'row_odd';
947
                            } else {
948
                                $oddclass = 'row_even';
949
                            }
950
                            $output .= '<tr class="'.$oddclass.'">
951
                                    <td></td>
952
                                    <td></td>
953
                                    <td></td>
954
                                    <td>' . $interaction['order_id'].'</td>
955
                                    <td colspan="2">'.$interaction['objective_id'].'</td>
956
                                    <td colspan="2">' . $interaction['status'].'</td>
957
                                    <td>' . $interaction['score_raw'].'</td>
958
                                    <td>' . $interaction['score_max'].'</td>
959
                                    <td>' . $interaction['score_min'].'</td>
960
                                    '.$action.'
961
                               </tr>';
962
                            $counter++;
963
                        }
964
                    }
965
966
                    // Attempts listing by exercise.
967
                    if ($lp_id == $my_lp_id && $lp_item_id == $my_id && $extendedAttempt) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $extendedAttempt of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
968
                        // Get attempts of a exercise.
969
                        if (!empty($lp_id) &&
970
                            !empty($lp_item_id) &&
971
                            $row['item_type'] === 'quiz'
972
                        ) {
973
                            $sql = "SELECT path FROM $TBL_LP_ITEM
974
                                    WHERE
975
                                        c_id = $course_id AND
976
                                        id = '$lp_item_id' AND
977
                                        lp_id = '$lp_id'";
978
                            $res_path = Database::query($sql);
979
                            $row_path = Database::fetch_array($res_path);
980
981
                            if (Database::num_rows($res_path) > 0) {
982
                                $sql = 'SELECT * FROM '.$tbl_stats_exercices.'
983
                                        WHERE
984
                                            exe_exo_id="' . (int) $row_path['path'].'" AND
985
                                            status <> "incomplete" AND
986
                                            exe_user_id="' . $user_id.'" AND
987
                                            orig_lp_id = "' . (int) $lp_id.'" AND
988
                                            orig_lp_item_id = "' . (int) $lp_item_id.'" AND
989
                                            c_id = ' . $course_id.'  AND
990
                                            session_id = ' . $session_id.'
991
                                        ORDER BY exe_date';
992
                                $res_attempts = Database::query($sql);
993
                                $num_attempts = Database::num_rows($res_attempts);
994
                                if ($num_attempts > 0) {
995
                                    $n = 1;
996
                                    while ($row_attempts = Database::fetch_array($res_attempts)) {
997
                                        $my_score = $row_attempts['exe_result'];
998
                                        $my_maxscore = $row_attempts['exe_weighting'];
999
                                        $my_exe_id = $row_attempts['exe_id'];
1000
                                        $my_orig_lp = $row_attempts['orig_lp_id'];
1001
                                        $my_orig_lp_item = $row_attempts['orig_lp_item_id'];
1002
                                        $my_exo_exe_id = $row_attempts['exe_exo_id'];
1003
                                        $mktime_start_date = api_strtotime($row_attempts['start_date'], 'UTC');
1004
                                        $mktime_exe_date = api_strtotime($row_attempts['exe_date'], 'UTC');
1005
                                        if ($mktime_start_date && $mktime_exe_date) {
1006
                                            $mytime = ((int) $mktime_exe_date - (int) $mktime_start_date);
1007
                                            $time_attemp = learnpathItem::getScormTimeFromParameter('js', $mytime);
1008
                                            $time_attemp = str_replace('NaN', '00'.$h.'00\'00"', $time_attemp);
1009
                                        } else {
1010
                                            $time_attemp = ' - ';
1011
                                        }
1012
                                        if (!$is_allowed_to_edit && $result_disabled_ext_all) {
1013
                                            $view_score = Display::return_icon(
1014
                                                'invisible.gif',
1015
                                                get_lang(
1016
                                                    'ResultsHiddenByExerciseSetting'
1017
                                                )
1018
                                            );
1019
                                        } else {
1020
                                            // Show only float when need it
1021
                                            if ($my_score == 0) {
1022
                                                $view_score = ExerciseLib::show_score(
1023
                                                    0,
1024
                                                    $my_maxscore,
1025
                                                    false
1026
                                                );
1027
                                            } else {
1028
                                                if ($my_maxscore == 0) {
1029
                                                    $view_score = $my_score;
1030
                                                } else {
1031
                                                    $view_score = ExerciseLib::show_score(
1032
                                                        $my_score,
1033
                                                        $my_maxscore,
1034
                                                        false
1035
                                                    );
1036
                                                }
1037
                                            }
1038
                                        }
1039
                                        $my_lesson_status = $row_attempts['status'];
1040
1041
                                        if ($my_lesson_status == '') {
1042
                                            $my_lesson_status = learnpathitem::humanize_status('completed');
1043
                                        } elseif ($my_lesson_status == 'incomplete') {
1044
                                            $my_lesson_status = learnpathitem::humanize_status('incomplete');
1045
                                        }
1046
                                        $timeRow = '<td class="lp_time" colspan="2">'.$time_attemp.'</td>';
1047
                                        if ($hideTime) {
1048
                                            $timeRow = '';
1049
                                        }
1050
1051
                                        $output .= '<tr class="'.$oddclass.'" >
1052
                                        <td></td>
1053
                                        <td>' . $extend_attempt_link.'</td>
1054
                                        <td colspan="3">' . get_lang('Attempt').' '.$n.'</td>
1055
                                        <td colspan="2">' . $my_lesson_status.'</td>
1056
                                        <td colspan="2">'.$view_score.'</td>
1057
                                        '.$timeRow;
1058
1059
                                        if ($action == 'classic') {
1060
                                            if ($origin != 'tracking') {
1061
                                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
1062
                                                    $output .= '<td>
1063
                                                            <img src="'.Display::returnIconPath('quiz_na.gif').'" alt="'.get_lang('ShowAttempt').'" title="'.get_lang('ShowAttempt').'">
1064
                                                            </td>';
1065
                                                } else {
1066
                                                    $output .= '<td>
1067
                                                            <a href="../exercise/exercise_show.php?origin=' . $origin.'&id='.$my_exe_id.'&cidReq='.$courseCode.'" target="_parent">
1068
                                                            <img src="'.Display::returnIconPath('quiz.png').'" alt="'.get_lang('ShowAttempt').'" title="'.get_lang('ShowAttempt').'">
1069
                                                            </a></td>';
1070
                                                }
1071
                                            } else {
1072
                                                if (!$is_allowed_to_edit && $result_disabled_ext_all) {
1073
                                                    $output .= '<td>
1074
                                                                <img src="'.Display::returnIconPath('quiz_na.gif').'" alt="'.get_lang('ShowAndQualifyAttempt').'" title="'.get_lang('ShowAndQualifyAttempt').'"></td>';
1075
                                                } else {
1076
                                                    $output .= '<td>
1077
                                                                    <a href="../exercise/exercise_show.php?cidReq=' . $courseCode.'&origin=correct_exercise_in_lp&id='.$my_exe_id.'" target="_parent">
1078
                                                                    <img src="'.Display::returnIconPath('quiz.gif').'" alt="'.get_lang('ShowAndQualifyAttempt').'" title="'.get_lang('ShowAndQualifyAttempt').'"></a></td>';
1079
                                                }
1080
                                            }
1081
                                        }
1082
                                        $output .= '</tr>';
1083
                                        $n++;
1084
                                    }
1085
                                }
1086
                                $output .= '<tr><td colspan="12">&nbsp;</td></tr>';
1087
                            }
1088
                        }
1089
                    }
1090
                }
1091
1092
                $total_time += $time_for_total;
1093
                // QUIZZ IN LP
1094
                $a_my_id = array();
1095
                if (!empty($my_lp_id)) {
1096
                    $a_my_id[] = $my_lp_id;
1097
                }
1098
            }
1099
        }
1100
1101
        // NOT Extend all "left green cross"
1102
        if (!empty($a_my_id)) {
1103
            if ($extendedAttempt) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $extendedAttempt of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1104
                // "Right green cross" extended
1105
                $total_score = self::get_avg_student_score(
1106
                    $user_id,
1107
                    $course_id,
1108
                    $a_my_id,
1109
                    $session_id,
1110
                    false,
1111
                    false
1112
                );
1113
            } else {
1114
                // "Left green cross" extended
1115
                $total_score = self::get_avg_student_score(
1116
                    $user_id,
1117
                    $course_id,
1118
                    $a_my_id,
1119
                    $session_id,
1120
                    false,
1121
                    true
1122
                );
1123
            }
1124
        } else {
1125
            // Extend all "left green cross"
1126
            $total_score = self::get_avg_student_score(
1127
                $user_id,
1128
                $course_id,
1129
                array($lp_id),
1130
                $session_id,
1131
                false,
1132
                false
1133
            );
1134
        }
1135
1136
        $total_time = learnpathItem::getScormTimeFromParameter('js', $total_time);
1137
        $total_time = str_replace('NaN', '00'.$h.'00\'00"', $total_time);
1138
1139
        if (!$is_allowed_to_edit && $result_disabled_ext_all) {
1140
            $final_score = Display::return_icon('invisible.gif', get_lang('ResultsHiddenByExerciseSetting'));
1141
            $finalScoreToCsv = get_lang('ResultsHiddenByExerciseSetting');
1142
        } else {
1143
            if (is_numeric($total_score)) {
1144
                $final_score = $total_score.'%';
1145
            } else {
1146
                $final_score = $total_score;
1147
            }
1148
            $finalScoreToCsv = $final_score;
1149
        }
1150
        $progress = learnpath::getProgress($lp_id, $user_id, $course_id, $session_id);
1151
1152
        if (($counter % 2) == 0) {
1153
            $oddclass = 'row_odd';
1154
        } else {
1155
            $oddclass = 'row_even';
1156
        }
1157
1158
        $action = null;
1159
        if ($type == 'classic') {
1160
            $action = '<td></td>';
1161
        }
1162
1163
        $timeTotal = '<td class="lp_time" colspan="2">'.$total_time.'</div>';
1164
        if ($hideTime) {
1165
            $timeTotal = '';
1166
        }
1167
1168
        $output .= '<tr class="'.$oddclass.'">
1169
                <td></td>
1170
                <td colspan="4">
1171
                    <i>' . get_lang('AccomplishedStepsTotal').'</i>
1172
                </td>
1173
                <td colspan="2">'.$progress.'%</td>
1174
                <td colspan="2">' . $final_score.'</td>
1175
                '.$timeTotal.'
1176
                '.$action.'
1177
           </tr>';
1178
1179
        $output .= '
1180
                    </tbody>
1181
                </table>
1182
            </div>
1183
        ';
1184
1185
        if (!empty($export_csv)) {
1186
            $temp = array(
1187
                '',
1188
                '',
1189
                '',
1190
                ''
1191
            );
1192
            $csv_content[] = $temp;
1193
            $temp = array(
1194
                get_lang('AccomplishedStepsTotal'),
1195
                '',
1196
                $finalScoreToCsv
1197
            );
1198
1199
            if ($hideTime === false) {
1200
                $temp[] = $total_time;
1201
            }
1202
1203
            $csv_content[] = $temp;
1204
            ob_end_clean();
1205
            Export::arrayToCsv($csv_content, 'reporting_learning_path_details');
1206
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1207
        }
1208
1209
        return $output;
1210
    }
1211
1212
    /**
1213
     * @param int $userId
1214
     * @param bool $getCount
1215
     *
1216
     * @return array
1217
     */
1218
    public static function getStats($userId, $getCount = false)
1219
    {
1220
        $courses = [];
1221
        $assignedCourses = [];
1222
        $drhCount = 0;
1223
        $teachersCount = 0;
1224
        $studentsCount = 0;
1225
        $studentBossCount = 0;
1226
        $courseCount = 0;
1227
        $sessionCount = 0;
1228
        $assignedCourseCount = 0;
1229
1230
        if (api_is_drh() && api_drh_can_access_all_session_content()) {
1231
            $studentList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1232
                'drh_all',
1233
                $userId,
1234
                false,
1235
                null,
1236
                null,
1237
                null,
1238
                null,
1239
                null,
1240
                null,
1241
                null,
1242
                array(),
1243
                array(),
1244
                STUDENT
1245
            );
1246
1247
            $students = array();
1248
            if (is_array($studentList)) {
1249
                foreach ($studentList as $studentData) {
1250
                    $students[] = $studentData['user_id'];
1251
                }
1252
            }
1253
1254
            $studentBossesList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1255
                'drh_all',
1256
                $userId,
1257
                $getCount,
1258
                null,
1259
                null,
1260
                null,
1261
                null,
1262
                null,
1263
                null,
1264
                null,
1265
                array(),
1266
                array(),
1267
                STUDENT_BOSS
1268
            );
1269
1270
            if ($getCount) {
1271
                $studentBossCount = $studentBossesList;
1272
            } else {
1273
                $studentBosses = array();
1274
                if (is_array($studentBossesList)) {
1275
                    foreach ($studentBossesList as $studentBossData) {
1276
                        $studentBosses[] = $studentBossData['user_id'];
1277
                    }
1278
                }
1279
            }
1280
1281
            $teacherList = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1282
                'drh_all',
1283
                $userId,
1284
                $getCount,
1285
                null,
1286
                null,
1287
                null,
1288
                null,
1289
                null,
1290
                null,
1291
                null,
1292
                array(),
1293
                array(),
1294
                COURSEMANAGER
1295
            );
1296
1297
            if ($getCount) {
1298
                $teachersCount = $teacherList;
1299
            } else {
1300
                $teachers = array();
1301
                foreach ($teacherList as $teacherData) {
1302
                    $teachers[] = $teacherData['user_id'];
1303
                }
1304
            }
1305
1306
            $humanResources = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
1307
                'drh_all',
1308
                $userId,
1309
                $getCount,
1310
                null,
1311
                null,
1312
                null,
1313
                null,
1314
                null,
1315
                null,
1316
                null,
1317
                array(),
1318
                array(),
1319
                DRH
1320
            );
1321
1322
            if ($getCount) {
1323
                $drhCount = $humanResources;
1324
            } else {
1325
                $humanResourcesList = array();
1326
                if (is_array($humanResources)) {
1327
                    foreach ($humanResources as $item) {
1328
                        $humanResourcesList[] = $item['user_id'];
1329
                    }
1330
                }
1331
            }
1332
1333
            $platformCourses = SessionManager::getAllCoursesFollowedByUser(
1334
                $userId,
1335
                null,
1336
                null,
1337
                null,
1338
                null,
1339
                null,
1340
                $getCount
1341
            );
1342
1343
            if ($getCount) {
1344
                $courseCount = $platformCourses;
1345
            } else {
1346
                foreach ($platformCourses as $course) {
1347
                    $courses[$course['code']] = $course['code'];
1348
                }
1349
            }
1350
1351
            $sessions = SessionManager::get_sessions_followed_by_drh(
1352
                $userId,
1353
                null,
1354
                null,
1355
                false
1356
            );
1357
        } else {
1358
            $studentList = UserManager::getUsersFollowedByUser(
1359
                $userId,
1360
                STUDENT,
1361
                false,
1362
                false,
1363
                false,
1364
                null,
1365
                null,
1366
                null,
1367
                null,
1368
                null,
1369
                null,
1370
                COURSEMANAGER
1371
            );
1372
1373
            $students = array();
1374
            if (is_array($studentList)) {
1375
                foreach ($studentList as $studentData) {
1376
                    $students[] = $studentData['user_id'];
1377
                }
1378
            }
1379
1380
            $studentBossesList = UserManager::getUsersFollowedByUser(
1381
                $userId,
1382
                STUDENT_BOSS,
1383
                false,
1384
                false,
1385
                $getCount,
1386
                null,
1387
                null,
1388
                null,
1389
                null,
1390
                null,
1391
                null,
1392
                COURSEMANAGER
1393
            );
1394
1395
            if ($getCount) {
1396
                $studentBossCount = $studentBossesList;
1397
            } else {
1398
                $studentBosses = array();
1399
                if (is_array($studentBossesList)) {
1400
                    foreach ($studentBossesList as $studentBossData) {
1401
                        $studentBosses[] = $studentBossData['user_id'];
1402
                    }
1403
                }
1404
            }
1405
1406
            $teacherList = UserManager::getUsersFollowedByUser(
1407
                $userId,
1408
                COURSEMANAGER,
1409
                false,
1410
                false,
1411
                $getCount,
1412
                null,
1413
                null,
1414
                null,
1415
                null,
1416
                null,
1417
                null,
1418
                COURSEMANAGER
1419
            );
1420
1421
            if ($getCount) {
1422
                $teachersCount = $teacherList;
1423
            } else {
1424
                $teachers = array();
1425
                foreach ($teacherList as $teacherData) {
1426
                    $teachers[] = $teacherData['user_id'];
1427
                }
1428
            }
1429
1430
            $humanResources = UserManager::getUsersFollowedByUser(
1431
                $userId,
1432
                DRH,
1433
                false,
1434
                false,
1435
                $getCount,
1436
                null,
1437
                null,
1438
                null,
1439
                null,
1440
                null,
1441
                null,
1442
                COURSEMANAGER
1443
            );
1444
1445
            if ($getCount) {
1446
                $drhCount = $humanResources;
1447
            } else {
1448
                $humanResourcesList = array();
1449
                foreach ($humanResources as $item) {
1450
                    $humanResourcesList[] = $item['user_id'];
1451
                }
1452
            }
1453
1454
            $platformCourses = CourseManager::getCoursesFollowedByUser(
1455
                $userId,
1456
                COURSEMANAGER,
1457
                null,
1458
                null,
1459
                null,
1460
                null,
1461
                $getCount,
1462
                null,
1463
                null,
1464
                true
1465
            );
1466
1467
            if ($getCount) {
1468
                $assignedCourseCount = $platformCourses;
1469
            } else {
1470
                foreach ($platformCourses as $course) {
1471
                    $assignedCourses[$course['code']] = $course['code'];
1472
                }
1473
            }
1474
1475
            $platformCourses = CourseManager::getCoursesFollowedByUser(
1476
                $userId,
1477
                COURSEMANAGER,
1478
                null,
1479
                null,
1480
                null,
1481
                null,
1482
                $getCount
1483
            );
1484
1485
            if ($getCount) {
1486
                $courseCount = $platformCourses;
1487
            } else {
1488
                foreach ($platformCourses as $course) {
1489
                    $courses[$course['code']] = $course['code'];
1490
                }
1491
            }
1492
1493
            $sessions = SessionManager::getSessionsFollowedByUser(
1494
                $userId,
1495
                COURSEMANAGER,
1496
                null,
1497
                null,
1498
                false
1499
            );
1500
        }
1501
1502
        if ($getCount) {
1503
            return [
1504
                'drh' => $drhCount,
1505
                'teachers' => $teachersCount,
1506
                'student_count' => count($students),
1507
                'student_list' => $students,
1508
                'student_bosses' => $studentBossCount,
1509
                'courses' => $courseCount,
1510
                'session_count' => count($sessions),
1511
                'session_list' => $sessions,
1512
                'assigned_courses' => $assignedCourseCount
1513
            ];
1514
        }
1515
1516
        return array(
1517
            'drh' => $humanResourcesList,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $humanResourcesList does not seem to be defined for all execution paths leading up to this point.
Loading history...
1518
            'teachers' => $teachers,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $teachers does not seem to be defined for all execution paths leading up to this point.
Loading history...
1519
            'student_list' => $students,
1520
            'student_bosses' => $studentBosses,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $studentBosses does not seem to be defined for all execution paths leading up to this point.
Loading history...
1521
            'courses' => $courses,
1522
            'sessions' => $sessions,
1523
            'assigned_courses' => $assignedCourses
1524
        );
1525
    }
1526
1527
    /**
1528
     * Calculates the time spent on the platform by a user
1529
     * @param   int|array User id
1530
     * @param   string $timeFilter type of time filter: 'last_week' or 'custom'
1531
     * @param   string  $start_date start date date('Y-m-d H:i:s')
1532
     * @param   string  $end_date end date date('Y-m-d H:i:s')
1533
     *
1534
     * @return int $nb_seconds
1535
     */
1536
    public static function get_time_spent_on_the_platform(
1537
        $userId,
1538
        $timeFilter = 'last_7_days',
1539
        $start_date = null,
1540
        $end_date = null
1541
    ) {
1542
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1543
        $condition_time = '';
1544
1545
        if (is_array($userId)) {
1546
            $userList = array_map('intval', $userId);
1547
            $userCondition = " login_user_id IN ('".implode("','", $userList)."')";
1548
        } else {
1549
            $userCondition = " login_user_id = ".intval($userId);
1550
        }
1551
1552
        if (empty($timeFilter)) {
1553
            $timeFilter = 'last_week';
1554
        }
1555
1556
        $today = new DateTime('now', new DateTimeZone('UTC'));
1557
1558
        switch ($timeFilter) {
1559
            case 'last_7_days':
1560
                $newDate = new DateTime('-7 day', new DateTimeZone('UTC'));
1561
                $condition_time = " AND (login_date >= '{$newDate->format('Y-m-d H:i:s')}'";
1562
                $condition_time .= " AND logout_date <= '{$today->format('Y-m-d H:i:s')}') ";
1563
                break;
1564
            case 'last_30_days':
1565
                $newDate = new DateTime('-30 days', new DateTimeZone('UTC'));
1566
                $condition_time = " AND (login_date >= '{$newDate->format('Y-m-d H:i:s')}'";
1567
                $condition_time .= "AND logout_date <= '{$today->format('Y-m-d H:i:s')}') ";
1568
                break;
1569
            case 'custom':
1570
                if (!empty($start_date) && !empty($end_date)) {
1571
                    $start_date = Database::escape_string($start_date);
1572
                    $end_date = Database::escape_string($end_date);
1573
                    $condition_time = ' AND (login_date >= "'.$start_date.'" AND logout_date <= "'.$end_date.'" ) ';
1574
                }
1575
                break;
1576
        }
1577
1578
        $sql = 'SELECT SUM(TIMESTAMPDIFF(SECOND, login_date, logout_date)) diff
1579
    	        FROM '.$tbl_track_login.'
1580
                WHERE '.$userCondition.$condition_time;
1581
        $rs = Database::query($sql);
1582
        $row = Database::fetch_array($rs, 'ASSOC');
1583
        $diff = $row['diff'];
1584
1585
        if ($diff >= 0) {
1586
            return $diff;
1587
        } else {
1588
            return -1;
1589
        }
1590
    }
1591
1592
    /**
1593
     * Calculates the time spent on the course
1594
     * @param integer $user_id
1595
     * @param integer $courseId
1596
     * @param int Session id (optional)
1597
     *
1598
     * @return int Time in seconds
1599
     */
1600
    public static function get_time_spent_on_the_course(
1601
        $user_id,
1602
        $courseId,
1603
        $session_id = 0
1604
    ) {
1605
        $courseId = intval($courseId);
1606
1607
        if (empty($courseId) || empty($user_id)) {
1608
            return 0;
1609
        }
1610
1611
        $session_id  = intval($session_id);
1612
        if (is_array($user_id)) {
1613
            $user_id = array_map('intval', $user_id);
1614
            $conditionUser = " AND user_id IN (".implode(',', $user_id).") ";
1615
        } else {
1616
            $user_id = intval($user_id);
1617
            $conditionUser = " AND user_id = $user_id ";
1618
        }
1619
1620
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1621
        $sql = "SELECT
1622
                SUM(UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) as nb_seconds
1623
                FROM $table
1624
                WHERE 
1625
                    UNIX_TIMESTAMP(logout_course_date) > UNIX_TIMESTAMP(login_course_date) AND 
1626
                    c_id = '$courseId' ";
1627
1628
        if ($session_id != -1) {
1629
            $sql .= "AND session_id = '$session_id' ";
1630
        }
1631
1632
        $sql .= $conditionUser;
1633
        $rs = Database::query($sql);
1634
        $row = Database::fetch_array($rs);
1635
1636
        return $row['nb_seconds'];
1637
    }
1638
1639
    /**
1640
     * Get first connection date for a student
1641
     * @param int $student_id
1642
     *
1643
     * @return string|bool Date format long without day or false if there are no connections
1644
     */
1645
    public static function get_first_connection_date($student_id)
1646
    {
1647
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1648
        $sql = 'SELECT login_date
1649
                FROM '.$table.'
1650
                WHERE login_user_id = ' . intval($student_id).'
1651
                ORDER BY login_date ASC
1652
                LIMIT 0,1';
1653
1654
        $rs = Database::query($sql);
1655
        if (Database::num_rows($rs) > 0) {
1656
            if ($first_login_date = Database::result($rs, 0, 0)) {
1657
                return api_convert_and_format_date(
1658
                    $first_login_date,
1659
                    DATE_FORMAT_SHORT,
1660
                    date_default_timezone_get()
1661
                );
1662
            }
1663
        }
1664
1665
        return false;
1666
    }
1667
1668
    /**
1669
     * Get las connection date for a student
1670
     * @param int $student_id
1671
     * @param bool $warning_message Show a warning message (optional)
1672
     * @param bool $return_timestamp True for returning results in timestamp (optional)
1673
     * @return string|int|bool Date format long without day, false if there are no connections or
1674
     * timestamp if parameter $return_timestamp is true
1675
     */
1676
    public static function get_last_connection_date(
1677
        $student_id,
1678
        $warning_message = false,
1679
        $return_timestamp = false
1680
    ) {
1681
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1682
        $sql = 'SELECT login_date
1683
                FROM ' . $table.'
1684
                WHERE login_user_id = ' . intval($student_id).'
1685
                ORDER BY login_date
1686
                DESC LIMIT 0,1';
1687
1688
        $rs = Database::query($sql);
1689
        if (Database::num_rows($rs) > 0) {
1690
            if ($last_login_date = Database::result($rs, 0, 0)) {
1691
                $last_login_date = api_get_local_time($last_login_date);
1692
                if ($return_timestamp) {
1693
                    return api_strtotime($last_login_date, 'UTC');
1694
                } else {
1695
                    if (!$warning_message) {
1696
                        return api_format_date($last_login_date, DATE_FORMAT_SHORT);
1697
                    } else {
1698
                        $timestamp = api_strtotime($last_login_date, 'UTC');
1699
                        $currentTimestamp = time();
1700
1701
                        //If the last connection is > than 7 days, the text is red
1702
                        //345600 = 7 days in seconds
1703
                        if ($currentTimestamp - $timestamp > 604800) {
1704
                            return '<span style="color: #F00;">'.api_format_date($last_login_date, DATE_FORMAT_SHORT).'</span>';
1705
                        } else {
1706
                            return api_format_date($last_login_date, DATE_FORMAT_SHORT);
1707
                        }
1708
                    }
1709
                }
1710
            }
1711
        }
1712
1713
        return false;
1714
    }
1715
1716
    /**
1717
     * Get las connection date for a student
1718
     * @param array $studentList Student id array
1719
     * @param int $days
1720
     * @param bool $getCount
1721
     * @return int
1722
     */
1723
    public static function getInactiveUsers($studentList, $days, $getCount = true)
1724
    {
1725
        if (empty($studentList)) {
1726
            return 0;
1727
        }
1728
        $days = intval($days);
1729
        $date = api_get_utc_datetime(strtotime($days.' days ago'));
1730
        $studentList = array_map('intval', $studentList);
1731
1732
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1733
        $select = " SELECT login_user_id ";
1734
        if ($getCount) {
1735
            $select = " SELECT count(DISTINCT login_user_id) as count";
1736
        }
1737
        $sql = "$select
1738
                FROM $tbl_track_login
1739
                WHERE
1740
                    login_user_id IN (' ".implode("','", $studentList)."' ) AND
1741
                    login_date < '$date'
1742
                ";
1743
        $rs = Database::query($sql);
1744
        if (Database::num_rows($rs) > 0) {
1745
            if ($getCount) {
1746
                $count = Database::fetch_array($rs);
1747
                return $count['count'];
1748
            }
1749
            return Database::store_result($rs, 'ASSOC');
0 ignored issues
show
Bug Best Practice introduced by
The expression return Database::store_result($rs, 'ASSOC') returns the type array which is incompatible with the documented return type integer.
Loading history...
1750
        }
1751
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
1752
    }
1753
1754
    /**
1755
     * Get first user's connection date on the course
1756
     * @param int User id
1757
     * @param int $courseId
1758
     * @param int Session id (optional, default=0)
1759
     * @param bool $convert_date
1760
     * @return string|bool Date with format long without day or false if there is no date
1761
     */
1762
    public static function get_first_connection_date_on_the_course(
1763
        $student_id,
1764
        $courseId,
1765
        $session_id = 0,
1766
        $convert_date = true
1767
    ) {
1768
        $student_id  = intval($student_id);
1769
        $courseId = intval($courseId);
1770
        $session_id  = intval($session_id);
1771
1772
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1773
        $sql = 'SELECT login_course_date
1774
                FROM '.$tbl_track_login.'
1775
                WHERE
1776
                    user_id = '.$student_id.' AND
1777
                    c_id = '.$courseId.' AND
1778
                    session_id = '.$session_id.'
1779
                ORDER BY login_course_date ASC 
1780
                LIMIT 0,1';
1781
        $rs = Database::query($sql);
1782
        if (Database::num_rows($rs) > 0) {
1783
            if ($first_login_date = Database::result($rs, 0, 0)) {
1784
                if ($convert_date) {
1785
                    return api_convert_and_format_date(
1786
                        $first_login_date,
1787
                        DATE_FORMAT_SHORT
1788
                    );
1789
                } else {
1790
                    return $first_login_date;
1791
                }
1792
            }
1793
        }
1794
1795
        return false;
1796
    }
1797
1798
    /**
1799
     * Get last user's connection date on the course
1800
     * @param     int         User id
1801
     * @param    array $courseInfo real_id and code are used
1802
     * @param    int            Session id (optional, default=0)
1803
     * @param bool $convert_date
1804
     * @return    string|bool    Date with format long without day or false if there is no date
1805
     */
1806
    public static function get_last_connection_date_on_the_course(
1807
        $student_id,
1808
        $courseInfo,
1809
        $session_id = 0,
1810
        $convert_date = true
1811
    ) {
1812
        // protect data
1813
        $student_id  = intval($student_id);
1814
        $courseId = $courseInfo['real_id'];
1815
        $session_id  = intval($session_id);
1816
1817
        $tbl_track_e_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
1818
        $sql = 'SELECT access_date
1819
                FROM '.$tbl_track_e_access.'
1820
                WHERE   access_user_id = '.$student_id.' AND
1821
                        c_id = "'.$courseId.'" AND
1822
                        access_session_id = '.$session_id.'
1823
                ORDER BY access_date DESC
1824
                LIMIT 0,1';
1825
1826
        $rs = Database::query($sql);
1827
        if (Database::num_rows($rs) > 0) {
1828
            if ($last_login_date = Database::result($rs, 0, 0)) {
1829
                if (empty($last_login_date)) {
1830
                    return false;
1831
                }
1832
                //see #5736
1833
                $last_login_date_timestamp = api_strtotime($last_login_date);
1834
                $now = time();
1835
                //If the last connection is > than 7 days, the text is red
1836
                //345600 = 7 days in seconds
1837
                if ($now - $last_login_date_timestamp > 604800) {
1838
                    if ($convert_date) {
1839
                        $last_login_date = api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
1840
                        $icon = api_is_allowed_to_edit() ?
1841
                            '<a href="'.api_get_path(WEB_CODE_PATH).'announcements/announcements.php?action=add&remind_inactive='.$student_id.'&cidReq='.$courseInfo['code'].'" title="'.get_lang('RemindInactiveUser').'">
1842
                              '.Display::return_icon('messagebox_warning.gif').'
1843
                             </a>'
1844
                            : null;
1845
                        return $icon.Display::label($last_login_date, 'warning');
1846
                    } else {
1847
                        return $last_login_date;
1848
                    }
1849
                } else {
1850
                    if ($convert_date) {
1851
                        return api_convert_and_format_date($last_login_date, DATE_FORMAT_SHORT);
1852
                    } else {
1853
                        return $last_login_date;
1854
                    }
1855
                }
1856
            }
1857
        }
1858
        return false;
1859
    }
1860
1861
    /**
1862
     * Get count of the connections to the course during a specified period
1863
     * @param   int  $courseId
1864
     * @param   int     Session id (optional)
1865
     * @param   int     Datetime from which to collect data (defaults to 0)
1866
     * @param   int     Datetime to which to collect data (defaults to now)
1867
     * @return  int     count connections
1868
     */
1869
    public static function get_course_connections_count(
1870
        $courseId,
1871
        $session_id = 0,
1872
        $start = 0,
1873
        $stop = null
1874
    ) {
1875
        if ($start < 0) {
1876
            $start = 0;
1877
        }
1878
        if (!isset($stop) or ($stop < 0)) {
1879
            $stop = api_get_utc_datetime();
1880
        }
1881
1882
        // Given we're storing in cache, round the start and end times
1883
        // to the lower minute
1884
        $roundedStart = substr($start, 0, -2).'00';
1885
        $roundedStop = substr($stop, 0, -2).'00';
1886
        $roundedStart = Database::escape_string($roundedStart);
1887
        $roundedStop = Database::escape_string($roundedStop);
1888
        $month_filter = " AND login_course_date > '$roundedStart' AND login_course_date < '$roundedStop' ";
1889
        $courseId = intval($courseId);
1890
        $session_id = intval($session_id);
1891
        $count = 0;
1892
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1893
        $sql = "SELECT count(*) as count_connections
1894
                FROM $table
1895
                WHERE
1896
                    c_id = $courseId AND
1897
                    session_id = $session_id
1898
                    $month_filter";
1899
1900
        //This query can be very slow (several seconds on an indexed table
1901
        // with 14M rows). As such, we'll try to use APCu if it is
1902
        // available to store the resulting value for a few seconds
1903
        $cacheAvailable = api_get_configuration_value('apc');
1904
        if ($cacheAvailable === true) {
1905
            $apc = apcu_cache_info(true);
1906
            $apc_end = $apc['start_time'] + $apc['ttl'];
1907
            $apc_var = api_get_configuration_value('apc_prefix').'course_access_'.$courseId.'_'.$session_id.'_'.strtotime($roundedStart).'_'.strtotime($roundedStop);
0 ignored issues
show
Bug introduced by
Are you sure api_get_configuration_value('apc_prefix') of type mixed|false can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1907
            $apc_var = /** @scrutinizer ignore-type */ api_get_configuration_value('apc_prefix').'course_access_'.$courseId.'_'.$session_id.'_'.strtotime($roundedStart).'_'.strtotime($roundedStop);
Loading history...
1908
            if (apcu_exists($apc_var) && (time() < $apc_end) &&
1909
                apcu_fetch($apc_var) > 0
1910
            ) {
1911
                $count = apcu_fetch($apc_var);
1912
            } else {
1913
                $rs = Database::query($sql);
1914
                if (Database::num_rows($rs) > 0) {
1915
                    $row = Database::fetch_object($rs);
1916
                    $count = $row->count_connections;
1917
                }
1918
                apcu_clear_cache();
1919
                apcu_store($apc_var, $count, 60);
1920
            }
1921
        } else {
1922
            $rs = Database::query($sql);
1923
            if (Database::num_rows($rs) > 0) {
1924
                $row = Database::fetch_object($rs);
1925
                $count = $row->count_connections;
1926
            }
1927
        }
1928
1929
        return $count;
1930
    }
1931
1932
    /**
1933
     * Get count courses per student
1934
     * @param     int $user_id Student id
1935
     * @param    bool $include_sessions Include sessions (optional)
1936
     * @return  int        count courses
1937
     */
1938
    public static function count_course_per_student($user_id, $include_sessions = true)
1939
    {
1940
        $user_id = intval($user_id);
1941
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1942
        $tbl_session_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1943
1944
        $sql = 'SELECT DISTINCT c_id
1945
                FROM '.$tbl_course_rel_user.'
1946
                WHERE user_id = '.$user_id.' AND relation_type<>'.COURSE_RELATION_TYPE_RRHH;
1947
        $rs = Database::query($sql);
1948
        $nb_courses = Database::num_rows($rs);
1949
1950
        if ($include_sessions) {
1951
            $sql = 'SELECT DISTINCT c_id
1952
                    FROM '.$tbl_session_course_rel_user.'
1953
                    WHERE user_id = '.$user_id;
1954
            $rs = Database::query($sql);
1955
            $nb_courses += Database::num_rows($rs);
1956
        }
1957
1958
        return $nb_courses;
1959
    }
1960
1961
    /**
1962
     * Gets the score average from all tests in a course by student
1963
     *
1964
     * @param $student_id
1965
     * @param $course_code
1966
     * @param int $exercise_id
1967
     * @param null $session_id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $session_id is correct as it would always require null to be passed?
Loading history...
1968
     * @param int $active_filter    2 for consider all tests
1969
     *                              1 for active <> -1
1970
     *                              0 for active <> 0
1971
     * @param int $into_lp  1 for all exercises
1972
     *                      0 for without LP
1973
     * @param mixed id
1974
     * @param string code
1975
     * @param int id (optional), filtered by exercise
1976
     * @param int id (optional), if param $session_id is null
1977
     * it'll return results including sessions, 0 = session is not filtered
1978
     * @return   string    value (number %) Which represents a round integer about the score average.
1979
     */
1980
    public static function get_avg_student_exercise_score(
1981
        $student_id,
1982
        $course_code,
1983
        $exercise_id = 0,
1984
        $session_id = null,
1985
        $active_filter = 1,
1986
        $into_lp = 0
1987
    ) {
1988
        $course_code = Database::escape_string($course_code);
1989
        $course_info = api_get_course_info($course_code);
1990
        if (!empty($course_info)) {
1991
            // table definition
1992
            $tbl_course_quiz = Database::get_course_table(TABLE_QUIZ_TEST);
1993
            $tbl_stats_exercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1994
1995
            // Compose a filter based on optional exercise given
1996
            $condition_quiz = "";
1997
            if (!empty($exercise_id)) {
1998
                $exercise_id = intval($exercise_id);
1999
                $condition_quiz = " AND id = $exercise_id ";
2000
            }
2001
2002
            // Compose a filter based on optional session id given
2003
            $condition_session = '';
2004
            if (isset($session_id)) {
2005
                $session_id = intval($session_id);
2006
                $condition_session = " AND session_id = $session_id ";
2007
            }
2008
            if ($active_filter == 1) {
2009
                $condition_active = 'AND active <> -1';
2010
            } elseif ($active_filter == 0) {
2011
                $condition_active = 'AND active <> 0';
2012
            } else {
2013
                $condition_active = '';
2014
            }
2015
            $condition_into_lp = '';
2016
            $select_lp_id = '';
2017
            if ($into_lp == 0) {
2018
                $condition_into_lp = 'AND orig_lp_id = 0 AND orig_lp_item_id = 0';
2019
            } else {
2020
                $select_lp_id = ', orig_lp_id as lp_id ';
2021
            }
2022
2023
            $sql = "SELECT count(id) 
2024
    		        FROM $tbl_course_quiz
2025
    				WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz ";
2026
            $count_quiz = 0;
2027
            $countQuizResult = Database::query($sql);
2028
            if (!empty($countQuizResult)) {
2029
                $count_quiz = Database::fetch_row($countQuizResult);
2030
            }
2031
2032
            if (!empty($count_quiz[0]) && !empty($student_id)) {
2033
                if (is_array($student_id)) {
2034
                    $student_id = array_map('intval', $student_id);
2035
                    $condition_user = " AND exe_user_id IN (".implode(',', $student_id).") ";
2036
                } else {
2037
                    $student_id = intval($student_id);
2038
                    $condition_user = " AND exe_user_id = '$student_id' ";
2039
                }
2040
2041
                if (empty($exercise_id)) {
2042
                    $sql = "SELECT id FROM $tbl_course_quiz
2043
                            WHERE c_id = {$course_info['real_id']} $condition_active $condition_quiz";
2044
                    $result = Database::query($sql);
2045
                    $exercise_list = array();
2046
                    $exercise_id = null;
2047
                    if (!empty($result) && Database::num_rows($result)) {
2048
                        while ($row = Database::fetch_array($result)) {
2049
                            $exercise_list[] = $row['id'];
2050
                        }
2051
                    }
2052
                    if (!empty($exercise_list)) {
2053
                        $exercise_id = implode("','", $exercise_list);
2054
                    }
2055
                }
2056
2057
                $count_quiz = Database::fetch_row(Database::query($sql));
2058
                $sql = "SELECT
2059
                        SUM(exe_result/exe_weighting*100) as avg_score,
2060
                        COUNT(*) as num_attempts
2061
                        $select_lp_id
2062
                        FROM $tbl_stats_exercise
2063
                        WHERE
2064
                            exe_exo_id IN ('".$exercise_id."')
2065
                            $condition_user AND
2066
                            status = '' AND
2067
                            c_id = {$course_info['real_id']}
2068
                            $condition_session
2069
                            $condition_into_lp
2070
                        ORDER BY exe_date DESC";
2071
2072
                $res = Database::query($sql);
2073
                $row = Database::fetch_array($res);
2074
                $quiz_avg_score = null;
2075
2076
                if (!empty($row['avg_score'])) {
2077
                    $quiz_avg_score = round($row['avg_score'], 2);
2078
                }
2079
2080
                if (!empty($row['num_attempts'])) {
2081
                    $quiz_avg_score = round($quiz_avg_score / $row['num_attempts'], 2);
2082
                }
2083
                if (is_array($student_id)) {
2084
                    $quiz_avg_score = round($quiz_avg_score / count($student_id), 2);
2085
                }
2086
                if ($into_lp == 0) {
2087
                    return $quiz_avg_score;
2088
                } else {
2089
                    if (!empty($row['lp_id'])) {
2090
                        $tbl_lp = Database::get_course_table(TABLE_LP_MAIN);
2091
                        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2092
                        $sql = "SELECT lp.name
2093
                                FROM $tbl_lp as lp, $tbl_course as c
2094
                                WHERE
2095
                                    c.code = '$course_code' AND
2096
                                    lp.id = ".$row['lp_id']." AND
2097
                                    lp.c_id = c.id
2098
                                LIMIT 1;
2099
                        ";
2100
                        $result = Database::query($sql);
2101
                        $row_lp = Database::fetch_row($result);
2102
                        $lp_name = $row_lp[0];
2103
                        return array($quiz_avg_score, $lp_name);
0 ignored issues
show
Bug Best Practice introduced by
The expression return array($quiz_avg_score, $lp_name) returns the type array<integer,null|mixed|double> which is incompatible with the documented return type string.
Loading history...
2104
                    } else {
2105
                        return array($quiz_avg_score, null);
0 ignored issues
show
Bug Best Practice introduced by
The expression return array($quiz_avg_score, null) returns the type array<integer,null|double> which is incompatible with the documented return type string.
Loading history...
2106
                    }
2107
                }
2108
            }
2109
        }
2110
        return null;
2111
    }
2112
2113
    /**
2114
     * Get count student's exercise COMPLETED attempts
2115
     * @param int $student_id
2116
     * @param int $courseId
2117
     * @param int $exercise_id
2118
     * @param int $lp_id
2119
     * @param int $lp_item_id
2120
     * @param int $session_id
2121
     * @param int $find_all_lp  0 = just LP specified
2122
     *                          1 = LP specified or whitout LP,
2123
     *                          2 = all rows
2124
     * @internal param \Student $int id
2125
     * @internal param \Course $string code
2126
     * @internal param \Exercise $int id
2127
     * @internal param \Learning $int path id (optional),
2128
     * for showing attempts inside a learning path $lp_id and $lp_item_id params are required.
2129
     * @internal param \Learning $int path item id (optional),
2130
     * for showing attempts inside a learning path $lp_id and $lp_item_id params are required.
2131
     * @return  int     count of attempts
2132
     */
2133
    public static function count_student_exercise_attempts(
2134
        $student_id,
2135
        $courseId,
2136
        $exercise_id,
2137
        $lp_id = 0,
2138
        $lp_item_id = 0,
2139
        $session_id = 0,
2140
        $find_all_lp = 0
2141
    ) {
2142
        $courseId = intval($courseId);
2143
        $student_id = intval($student_id);
2144
        $exercise_id = intval($exercise_id);
2145
        $session_id = intval($session_id);
2146
2147
        $lp_id = intval($lp_id);
2148
        $lp_item_id = intval($lp_item_id);
2149
        $tbl_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2150
2151
        $sql = "SELECT COUNT(ex.exe_id) as essais 
2152
                FROM $tbl_stats_exercises AS ex
2153
                WHERE  
2154
                    ex.c_id = $courseId AND 
2155
                    ex.exe_exo_id = $exercise_id AND 
2156
                    status = '' AND 
2157
                    exe_user_id= $student_id AND 
2158
                    session_id = $session_id ";
2159
2160
        if ($find_all_lp == 1) {
2161
            $sql .= "AND (orig_lp_id = $lp_id OR orig_lp_id = 0)
2162
                AND (orig_lp_item_id = $lp_item_id OR orig_lp_item_id = 0)";
2163
        } elseif ($find_all_lp == 0) {
2164
            $sql .= "AND orig_lp_id = $lp_id
2165
                AND orig_lp_item_id = $lp_item_id";
2166
        }
2167
2168
        $rs = Database::query($sql);
2169
        $row = Database::fetch_row($rs);
2170
        $count_attempts = $row[0];
2171
2172
        return $count_attempts;
2173
    }
2174
2175
    /**
2176
     * Get count student's exercise progress
2177
     *
2178
     * @param array $exercise_list
2179
     * @param int $user_id
2180
     * @param int $courseId
2181
     * @param int $session_id
2182
     *
2183
     * @return string
2184
     */
2185
    public static function get_exercise_student_progress(
2186
        $exercise_list,
2187
        $user_id,
2188
        $courseId,
2189
        $session_id
2190
    ) {
2191
        $courseId = intval($courseId);
2192
        $user_id = intval($user_id);
2193
        $session_id = intval($session_id);
2194
2195
        if (empty($exercise_list)) {
2196
            return '0%';
2197
        }
2198
        $tbl_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2199
        $exercise_list = array_keys($exercise_list);
2200
        $exercise_list = array_map('intval', $exercise_list);
2201
2202
        $exercise_list_imploded = implode("' ,'", $exercise_list);
2203
2204
        $sql = "SELECT COUNT(DISTINCT ex.exe_exo_id)
2205
                FROM $tbl_stats_exercises AS ex
2206
                WHERE
2207
                    ex.c_id = $courseId AND
2208
                    ex.session_id  = $session_id AND
2209
                    ex.exe_user_id = $user_id AND
2210
                    ex.exe_exo_id IN ('$exercise_list_imploded') ";
2211
2212
        $rs = Database::query($sql);
2213
        $count = 0;
2214
        if ($rs) {
2215
            $row = Database::fetch_row($rs);
2216
            $count = $row[0];
2217
        }
2218
        $count = ($count != 0) ? 100 * round(intval($count) / count($exercise_list), 2).'%' : '0%';
2219
        return $count;
2220
    }
2221
2222
    /**
2223
     * @param array $exercise_list
2224
     * @param int $user_id
2225
     * @param int $courseId
2226
     * @param int $session_id
2227
     * @return string
2228
     */
2229
    public static function get_exercise_student_average_best_attempt(
2230
        $exercise_list,
2231
        $user_id,
2232
        $courseId,
2233
        $session_id
2234
    ) {
2235
        $result = 0;
2236
        if (!empty($exercise_list)) {
2237
            foreach ($exercise_list as $exercise_data) {
2238
                $exercise_id = $exercise_data['id'];
2239
                $best_attempt = Event::get_best_attempt_exercise_results_per_user(
2240
                    $user_id,
2241
                    $exercise_id,
2242
                    $courseId,
2243
                    $session_id
2244
                );
2245
2246
                if (!empty($best_attempt) && !empty($best_attempt['exe_weighting'])) {
2247
                    $result += $best_attempt['exe_result'] / $best_attempt['exe_weighting'];
2248
                }
2249
            }
2250
            $result = $result / count($exercise_list);
2251
            $result = round($result, 2) * 100;
2252
        }
2253
2254
        return $result.'%';
2255
    }
2256
2257
    /**
2258
     * get teacher progress by course and session
2259
     * @param int course id
2260
     * @param int session id
2261
     * @return array
2262
     */
2263
    static function get_teachers_progress_by_course($courseId, $sessionId)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
2264
    {
2265
        $course = api_get_course_info_by_id($courseId);
2266
        $sessionId = intval($sessionId);
2267
        $courseId = intval($courseId);
2268
2269
        $sessionCourseUserTable = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2270
        $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
2271
2272
        //get teachers
2273
        $sql = "SELECT scu.session_id, scu.user_id, s.name
2274
                FROM $sessionCourseUserTable scu, $sessionTable s
2275
                WHERE
2276
                    scu.session_id = s.id
2277
                    AND scu.status = 2
2278
                    AND scu.visibility = 1
2279
                    AND scu.c_id = '%s'
2280
                    AND scu.session_id = %s";
2281
        $query = sprintf($sql, intval($courseId), $sessionId);
2282
        $rs = Database::query($query);
2283
        $teachers = array();
2284
        while ($teacher = Database::fetch_array($rs, 'ASSOC')) {
2285
            $teachers[] = $teacher;
2286
        }
2287
        $data = array();
2288
        foreach ($teachers as $teacher) {
2289
            //total documents added
2290
            $sql = "SELECT count(*) as total
2291
                    FROM c_item_property
2292
                    WHERE lastedit_type = 'DocumentAdded'
2293
                    AND c_id = %s
2294
                    AND insert_user_id = %s
2295
                    AND session_id = %s";
2296
            $query = sprintf(
2297
                $sql,
2298
                $courseId,
2299
                $teacher['user_id'],
2300
                $teacher['session_id']
2301
            );
2302
2303
            $rs = Database::query($query);
2304
            $totalDocuments = 0;
2305
            if ($rs) {
2306
                $row = Database::fetch_row($rs);
2307
                $totalDocuments = $row[0];
2308
            }
2309
            // Total links added
2310
            $sql = "SELECT count(*) as total
2311
                    FROM c_item_property
2312
                    WHERE lastedit_type = 'LinkAdded'
2313
                    AND c_id = %s
2314
                    AND insert_user_id = %s
2315
                    AND session_id = %s";
2316
            $query = sprintf(
2317
                $sql,
2318
                $courseId,
2319
                $teacher['user_id'],
2320
                $teacher['session_id']
2321
            );
2322
            $rs = Database::query($query);
2323
2324
            $totalLinks = 0;
2325
            if ($rs) {
2326
                $row = Database::fetch_row($rs);
2327
                $totalLinks = $row[0];
2328
            }
2329
            //total forums added
2330
            $sql = "SELECT count(*) as total
2331
                    FROM c_item_property
2332
                    WHERE lastedit_type = 'ForumthreadVisible'
2333
                    AND c_id = %s
2334
                    AND insert_user_id = %s
2335
                    AND session_id = %s";
2336
            $query = sprintf(
2337
                $sql,
2338
                $courseId,
2339
                $teacher['user_id'],
2340
                $teacher['session_id']
2341
            );
2342
            $rs = Database::query($query);
2343
2344
            $totalForums = 0;
2345
            if ($rs) {
2346
                $row = Database::fetch_row($rs);
2347
                $totalForums = $row[0];
2348
            }
2349
2350
            //total wikis added
2351
            $sql = "SELECT COUNT(DISTINCT(ref)) as total
2352
                    FROM c_item_property
2353
                    WHERE lastedit_type = 'WikiAdded'
2354
                    AND c_id = %s
2355
                    AND insert_user_id = %s
2356
                    AND session_id = %s";
2357
2358
            $query = sprintf(
2359
                $sql,
2360
                $courseId,
2361
                $teacher['user_id'],
2362
                $teacher['session_id']
2363
            );
2364
2365
            $rs = Database::query($query);
2366
2367
            $totalWikis = 0;
2368
            if ($rs) {
2369
                $row = Database::fetch_row($rs);
2370
                $totalWikis = $row[0];
2371
            }
2372
2373
            // Total works added
2374
            $sql = "SELECT COUNT(*) as total
2375
                    FROM c_item_property
2376
                    WHERE lastedit_type = 'DirectoryCreated'
2377
                    AND tool = 'work'
2378
                    AND c_id = %s
2379
                    AND insert_user_id = %s
2380
                    AND session_id = %s";
2381
            $query = sprintf(
2382
                $sql,
2383
                $courseId,
2384
                $teacher['user_id'],
2385
                $teacher['session_id']
2386
            );
2387
            $rs = Database::query($query);
2388
2389
            $totalWorks = 0;
2390
            if ($rs) {
2391
                $row = Database::fetch_row($rs);
2392
                $totalWorks = $row[0];
2393
            }
2394
            //total announcements added
2395
            $sql = "SELECT COUNT(*) as total
2396
                    FROM c_item_property
2397
                    WHERE lastedit_type = 'AnnouncementAdded'
2398
                    AND c_id = %s
2399
                    AND insert_user_id = %s
2400
                    AND session_id = %s";
2401
            $query = sprintf(
2402
                $sql,
2403
                $courseId,
2404
                $teacher['user_id'],
2405
                $teacher['session_id']
2406
            );
2407
            $rs = Database::query($query);
2408
2409
            $totalAnnouncements = 0;
2410
            if ($rs) {
2411
                $row = Database::fetch_row($rs);
2412
                $totalAnnouncements = $row[0];
2413
            }
2414
            $tutor = api_get_user_info($teacher['user_id']);
2415
            $data[] = array(
2416
                'course' => $course['title'],
2417
                'session' => $teacher['name'],
2418
                'tutor' => $tutor['username'].' - '.$tutor['lastname'].' '.$tutor['firstname'],
2419
                'documents' => $totalDocuments,
2420
                'links' => $totalLinks,
2421
                'forums' => $totalForums,
2422
                'works' => $totalWorks,
2423
                'wikis' => $totalWikis,
2424
                'announcements' => $totalAnnouncements,
2425
            );
2426
        }
2427
2428
        return $data;
2429
    }
2430
2431
    /**
2432
     * Returns the average student progress in the learning paths of the given
2433
     * course, it will take into account the progress that were not started.
2434
     * @param int|array $studentId
2435
     * @param string $courseCode
2436
     * @param array $lpIdList Limit average to listed lp ids
2437
     * @param int $sessionId     Session id (optional),
2438
     * if parameter $session_id is null(default) it'll return results including
2439
     * sessions, 0 = session is not filtered
2440
     * @param bool $returnArray Will return an array of the type:
2441
     * [sum_of_progresses, number] if it is set to true
2442
     * @param boolean $onlySeriousGame Optional. Limit average to lp on seriousgame mode
2443
     * @return double Average progress of the user in this course
2444
     */
2445
    public static function get_avg_student_progress(
2446
        $studentId,
2447
        $courseCode = null,
2448
        $lpIdList = array(),
2449
        $sessionId = null,
2450
        $returnArray = false,
2451
        $onlySeriousGame = false
2452
    ) {
2453
        // If there is at least one learning path and one student.
2454
        if (empty($studentId)) {
2455
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type double.
Loading history...
2456
        }
2457
2458
        $sessionId = intval($sessionId);
2459
        $courseInfo = api_get_course_info($courseCode);
2460
2461
        if (empty($courseInfo)) {
2462
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type double.
Loading history...
2463
        }
2464
2465
        $lPTable = Database::get_course_table(TABLE_LP_MAIN);
2466
        $lpViewTable = Database::get_course_table(TABLE_LP_VIEW);
2467
        $lpConditions = [];
2468
        $lpConditions['c_id = ? '] = $courseInfo['real_id'];
2469
2470
        if ($sessionId > 0) {
2471
            $lpConditions['AND (session_id = ? OR session_id = 0 OR session_id IS NULL)'] = $sessionId;
2472
        } else {
2473
            $lpConditions['AND session_id = ?'] = $sessionId;
2474
        }
2475
2476
        if (is_array($lpIdList) && count($lpIdList) > 0) {
2477
            $placeHolders = [];
2478
            for ($i = 0; $i < count($lpIdList); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
2479
                $placeHolders[] = '?';
2480
            }
2481
            $lpConditions['AND id IN('.implode(', ', $placeHolders).') '] = $lpIdList;
2482
        }
2483
2484
        if ($onlySeriousGame) {
2485
            $lpConditions['AND seriousgame_mode = ? '] = true;
2486
        }
2487
2488
        $resultLP = Database::select(
2489
            'id',
2490
            $lPTable,
2491
            ['where' => $lpConditions]
2492
        );
2493
        $filteredLP = array_keys($resultLP);
2494
2495
        if (empty($filteredLP)) {
2496
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type double.
Loading history...
2497
        }
2498
2499
        $conditions = [
2500
            " c_id = {$courseInfo['real_id']} ",
2501
            " lp_view.lp_id IN(".implode(', ', $filteredLP).") "
2502
        ];
2503
2504
        $groupBy = 'GROUP BY lp_id';
2505
2506
        if (is_array($studentId)) {
2507
            $studentId = array_map('intval', $studentId);
2508
            $conditions[] = " lp_view.user_id IN (".implode(',', $studentId).")  ";
2509
        } else {
2510
            $studentId = intval($studentId);
2511
            $conditions[] = " lp_view.user_id = '$studentId' ";
2512
2513
            if (empty($lpIdList)) {
2514
                $lpList = new LearnpathList(
2515
                    $studentId,
2516
                    $courseCode,
2517
                    $sessionId,
2518
                    null,
2519
                    false,
2520
                    null,
2521
                    true
2522
                );
2523
                $lpList = $lpList->get_flat_list();
2524
                if (!empty($lpList)) {
2525
                    /** @var  $lp */
2526
                    foreach ($lpList as $lpId => $lp) {
2527
                        $lpIdList[] = $lpId;
2528
                    }
2529
                }
2530
            }
2531
        }
2532
2533
        if (!empty($sessionId)) {
2534
            $conditions[] = " session_id = $sessionId ";
2535
        } else {
2536
            $conditions[] = " (session_id = 0 OR session_id IS NULL) ";
2537
        }
2538
2539
        $conditionToString = implode('AND', $conditions);
2540
        $sql = "SELECT lp_id, view_count, progress 
2541
                FROM $lpViewTable lp_view
2542
                WHERE
2543
                    $conditionToString
2544
                    $groupBy
2545
                ORDER BY view_count DESC";
2546
2547
        $result = Database::query($sql);
2548
2549
        $progress = [];
2550
        $viewCount = [];
2551
        while ($row = Database::fetch_array($result, 'ASSOC')) {
2552
            if (!isset($viewCount[$row['lp_id']])) {
2553
                $progress[$row['lp_id']] = $row['progress'];
2554
            }
2555
            $viewCount[$row['lp_id']] = $row['view_count'];
2556
        }
2557
2558
        // Fill with lp ids
2559
        if (!empty($lpIdList)) {
2560
            foreach ($lpIdList as $lpId) {
2561
                if (!isset($progress[$lpId])) {
2562
                    $progress[$lpId] = 0;
2563
                }
2564
            }
2565
        }
2566
2567
        if (!empty($progress)) {
2568
            $sum = array_sum($progress);
2569
            $average = 0;
2570
            if (!empty($lpIdList)) {
2571
                $average = $sum / count($lpIdList);
2572
            }
2573
        } else {
2574
            $average = 0;
2575
            $sum = 0;
2576
        }
2577
2578
        if ($returnArray) {
2579
            return [
0 ignored issues
show
Bug Best Practice introduced by
The expression return array($sum, count($lpIdList)) returns the type array<integer,integer|double> which is incompatible with the documented return type double.
Loading history...
2580
                $sum,
2581
                count($lpIdList)
2582
            ];
2583
        }
2584
2585
        return round($average, 1);
2586
    }
2587
2588
    /**
2589
     * This function gets:
2590
     * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores.
2591
     * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores.
2592
     * 3. And finally it will return the average between 1. and 2.
2593
     * @todo improve performance, when loading 1500 users with 20 lps the script dies
2594
     * This function does not take the results of a Test out of a LP
2595
     *
2596
     * @param mixed $student_id Array of user ids or an user id
2597
     * @param string $course_code
2598
     * @param array $lp_ids List of LP ids
2599
     * @param int $session_id Session id (optional),
2600
     * if param $session_id is null(default) it'll return results
2601
     * including sessions, 0 = session is not filtered
2602
     * @param bool $return_array Returns an array of the
2603
     * type [sum_score, num_score] if set to true
2604
     * @param bool $get_only_latest_attempt_results get only the latest attempts or ALL attempts
2605
     * @param bool $getOnlyBestAttempt
2606
     *
2607
     * @return  string      Value (number %) Which represents a round integer explain in got in 3.
2608
     */
2609
    public static function get_avg_student_score(
2610
        $student_id,
2611
        $course_code,
2612
        $lp_ids = array(),
2613
        $session_id = null,
2614
        $return_array = false,
2615
        $get_only_latest_attempt_results = false,
2616
        $getOnlyBestAttempt = false
2617
    ) {
2618
        $debug = false;
2619
        if ($debug) echo '<h1>Tracking::get_avg_student_score</h1>';
2620
        $tbl_stats_exercices = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2621
        $tbl_stats_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
2622
        $course = api_get_course_info($course_code);
2623
        if (!empty($course)) {
2624
            // Get course tables names
2625
            $tbl_quiz_questions = Database::get_course_table(TABLE_QUIZ_QUESTION);
2626
            $lp_table = Database::get_course_table(TABLE_LP_MAIN);
2627
            $lp_item_table = Database::get_course_table(TABLE_LP_ITEM);
2628
            $lp_view_table = Database::get_course_table(TABLE_LP_VIEW);
2629
            $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW);
2630
            $course_id = $course['real_id'];
2631
2632
            // Compose a filter based on optional learning paths list given
2633
            $condition_lp = '';
2634
            if (count($lp_ids) > 0) {
2635
                $condition_lp = " AND id IN(".implode(',', $lp_ids).") ";
2636
            }
2637
2638
            // Compose a filter based on optional session id
2639
            $session_id = intval($session_id);
2640
            if (count($lp_ids) > 0) {
2641
                $condition_session = " AND session_id = $session_id ";
2642
            } else {
2643
                $condition_session = " WHERE session_id = $session_id ";
2644
            }
2645
2646
            // Check the real number of LPs corresponding to the filter in the
2647
            // database (and if no list was given, get them all)
2648
2649
            if (empty($session_id)) {
2650
                $sql = "SELECT DISTINCT(id), use_max_score
2651
                        FROM $lp_table
2652
                        WHERE 
2653
                            c_id = $course_id AND 
2654
                            (session_id = 0 OR session_id IS NULL) $condition_lp ";
2655
            } else {
2656
                $sql = "SELECT DISTINCT(id), use_max_score
2657
                        FROM $lp_table
2658
                        WHERE c_id = $course_id $condition_lp ";
2659
            }
2660
2661
            $res_row_lp = Database::query($sql);
2662
            $count_row_lp = Database::num_rows($res_row_lp);
2663
2664
            $lp_list = $use_max_score = array();
2665
            while ($row_lp = Database::fetch_array($res_row_lp)) {
2666
                $lp_list[] = $row_lp['id'];
2667
                $use_max_score[$row_lp['id']] = $row_lp['use_max_score'];
2668
            }
2669
2670
            if ($debug) {
2671
                echo '$lp_list: ';
2672
                var_dump($lp_list);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($lp_list) looks like debug code. Are you sure you do not want to remove it?
Loading history...
2673
                echo 'Use max score or not list: ';
2674
                var_dump($use_max_score);
2675
            }
2676
2677
            // prepare filter on users
2678
            if (is_array($student_id)) {
2679
                array_walk($student_id, 'intval');
2680
                $condition_user1 = " AND user_id IN (".implode(',', $student_id).") ";
2681
            } else {
2682
                $condition_user1 = " AND user_id = $student_id ";
2683
            }
2684
2685
            if ($count_row_lp > 0 && !empty($student_id)) {
2686
                // Getting latest LP result for a student
2687
                //@todo problem when a  course have more than 1500 users
2688
                $sql = "SELECT MAX(view_count) as vc, id, progress, lp_id, user_id
2689
                        FROM $lp_view_table
2690
                        WHERE
2691
                            c_id = $course_id AND
2692
                            lp_id IN (".implode(',', $lp_list).")
2693
                            $condition_user1 AND
2694
                            session_id = $session_id
2695
                        GROUP BY lp_id, user_id";
2696
                if ($debug) {
2697
                    echo 'get LP results';
2698
                    var_dump($sql);
2699
                }
2700
2701
                $rs_last_lp_view_id = Database::query($sql);
2702
                $global_result = 0;
2703
2704
                if (Database::num_rows($rs_last_lp_view_id) > 0) {
2705
                    // Cycle through each line of the results (grouped by lp_id, user_id)
2706
                    while ($row_lp_view = Database::fetch_array($rs_last_lp_view_id)) {
2707
                        $count_items = 0;
2708
                        $lpPartialTotal = 0;
2709
                        $list = array();
2710
                        $lp_view_id = $row_lp_view['id'];
2711
                        $lp_id = $row_lp_view['lp_id'];
2712
                        $user_id = $row_lp_view['user_id'];
2713
2714
                        if ($debug) {
2715
                            echo '<h2>LP id '.$lp_id.'</h2>';
2716
                            echo "get_only_latest_attempt_results: $get_only_latest_attempt_results <br />";
2717
                            echo "getOnlyBestAttempt: $getOnlyBestAttempt <br />";
2718
                        }
2719
2720
                        if ($get_only_latest_attempt_results || $getOnlyBestAttempt) {
2721
                            // Getting lp_items done by the user
2722
                            $sql = "SELECT DISTINCT lp_item_id
2723
                                    FROM $lp_item_view_table
2724
                                    WHERE
2725
                                        c_id = $course_id AND
2726
                                        lp_view_id = $lp_view_id
2727
                                    ORDER BY lp_item_id";
2728
                            $res_lp_item = Database::query($sql);
2729
                            if ($debug) {
2730
                                echo 'Getting lp_items done by the user<br />';
2731
                                var_dump($sql);
2732
                            }
2733
2734
                            while ($row_lp_item = Database::fetch_array($res_lp_item, 'ASSOC')) {
2735
                                $my_lp_item_id = $row_lp_item['lp_item_id'];
2736
                                $order = ' view_count DESC';
2737
                                if ($getOnlyBestAttempt) {
2738
                                    $order = ' lp_iv.score DESC';
2739
                                }
2740
2741
                                // Getting the most recent attempt
2742
                                $sql = "SELECT  
2743
                                            lp_iv.id as lp_item_view_id,
2744
                                            lp_iv.score as score,
2745
                                            lp_i.max_score,
2746
                                            lp_iv.max_score as max_score_item_view,
2747
                                            lp_i.path,
2748
                                            lp_i.item_type,
2749
                                            lp_i.id as iid
2750
                                        FROM $lp_item_view_table as lp_iv
2751
                                        INNER JOIN $lp_item_table as lp_i
2752
                                        ON (
2753
                                            lp_i.id = lp_iv.lp_item_id AND 
2754
                                            lp_iv.c_id = lp_i.c_id
2755
                                        )                                            
2756
                                        WHERE
2757
                                            lp_iv.c_id = $course_id AND
2758
                                            lp_i.c_id  = $course_id AND
2759
                                            lp_item_id = $my_lp_item_id AND
2760
                                            lp_view_id = $lp_view_id AND
2761
                                            (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."')
2762
                                        ORDER BY $order
2763
                                        LIMIT 1";
2764
2765
                                $res_lp_item_result = Database::query($sql);
2766
                                while ($row_max_score = Database::fetch_array($res_lp_item_result, 'ASSOC')) {
2767
                                    $list[] = $row_max_score;
2768
                                }
2769
                            }
2770
                        } else {
2771
                            // For the currently analysed view, get the score and
2772
                            // max_score of each item if it is a sco or a TOOL_QUIZ
2773
                            $sql = "SELECT
2774
                                        lp_iv.id as lp_item_view_id,
2775
                                        lp_iv.score as score,
2776
                                        lp_i.max_score,
2777
                                        lp_iv.max_score as max_score_item_view,
2778
                                        lp_i.path,
2779
                                        lp_i.item_type,
2780
                                        lp_i.id as iid
2781
                                      FROM $lp_item_view_table as lp_iv
2782
                                      INNER JOIN $lp_item_table as lp_i
2783
                                      ON lp_i.id = lp_iv.lp_item_id AND
2784
                                         lp_iv.c_id = lp_i.c_id
2785
                                      WHERE 
2786
                                        lp_iv.c_id = $course_id AND 
2787
                                        lp_i.c_id  = $course_id AND
2788
                                        lp_view_id = $lp_view_id AND
2789
                                        (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."')
2790
                                    ";
2791
                            $res_max_score = Database::query($sql);
2792
                            while ($row_max_score = Database::fetch_array($res_max_score, 'ASSOC')) {
2793
                                $list[] = $row_max_score;
2794
                            }
2795
                        }
2796
2797
                        // Go through each scorable element of this view
2798
                        $score_of_scorm_calculate = 0;
2799
                        foreach ($list as $row_max_score) {
2800
                            // Came from the original lp_item
2801
                            $max_score = $row_max_score['max_score'];
2802
                            // Came from the lp_item_view
2803
                            $max_score_item_view = $row_max_score['max_score_item_view'];
2804
                            $score = $row_max_score['score'];
2805
                            if ($debug) echo '<h3>Item Type: '.$row_max_score['item_type'].'</h3>';
2806
2807
                            if ($row_max_score['item_type'] == 'sco') {
2808
                                /* Check if it is sco (easier to get max_score)
2809
                                   when there's no max score, we assume 100 as the max score,
2810
                                   as the SCORM 1.2 says that the value should always be between 0 and 100.
2811
                                */
2812
                                if ($max_score == 0 || is_null($max_score) || $max_score == '') {
2813
                                    // Chamilo style
2814
                                    if ($use_max_score[$lp_id]) {
2815
                                        $max_score = 100;
2816
                                    } else {
2817
                                        // Overwrites max score = 100 to use the one that came in the lp_item_view see BT#1613
2818
                                        $max_score = $max_score_item_view;
2819
                                    }
2820
                                }
2821
                                // Avoid division by zero errors
2822
                                if (!empty($max_score)) {
2823
                                    $lpPartialTotal += $score / $max_score;
2824
                                }
2825
                                if ($debug) {
2826
                                    var_dump("lpPartialTotal: $lpPartialTotal");
2827
                                    var_dump("score: $score");
2828
                                    var_dump("max_score: $max_score");
2829
                                }
2830
                            } else {
2831
                                // Case of a TOOL_QUIZ element
2832
                                $item_id = $row_max_score['iid'];
2833
                                $item_path = $row_max_score['path'];
2834
                                $lp_item_view_id = (int) $row_max_score['lp_item_view_id'];
2835
2836
                                $lpItemCondition = '';
2837
                                if (empty($lp_item_view_id)) {
2838
                                    $lpItemCondition = ' (orig_lp_item_view_id = 0 OR orig_lp_item_view_id IS NULL) ';
2839
                                } else {
2840
                                    $lpItemCondition = " orig_lp_item_view_id = $lp_item_view_id ";
2841
                                }
2842
2843
                                // Get last attempt to this exercise through
2844
                                // the current lp for the current user
2845
                                $order = 'exe_date DESC';
2846
                                if ($getOnlyBestAttempt) {
2847
                                    $order = 'exe_result DESC';
2848
                                }
2849
                                $sql = "SELECT exe_id, exe_result
2850
                                        FROM $tbl_stats_exercices
2851
                                        WHERE
2852
                                            exe_exo_id = '$item_path' AND
2853
                                            exe_user_id = $user_id AND
2854
                                            orig_lp_item_id = $item_id AND
2855
                                            $lpItemCondition AND
2856
                                            c_id = $course_id AND
2857
                                            session_id = $session_id AND
2858
                                            status = ''
2859
                                        ORDER BY $order
2860
                                        LIMIT 1";
2861
2862
                                $result_last_attempt = Database::query($sql);
2863
                                if ($debug) var_dump($sql);
2864
                                $num = Database::num_rows($result_last_attempt);
2865
                                if ($num > 0) {
2866
                                    $attemptResult = Database::fetch_array($result_last_attempt, 'ASSOC');
2867
                                    $id_last_attempt = $attemptResult['exe_id'];
2868
                                    // We overwrite the score with the best one not the one saved in the LP (latest)
2869
                                    if ($getOnlyBestAttempt && $get_only_latest_attempt_results == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
2870
                                        if ($debug) echo "Following score comes from the track_exercise table not in the LP because the score is the best<br />";
2871
                                        $score = $attemptResult['exe_result'];
2872
                                    }
2873
2874
                                    if ($debug) echo "Attempt id: $id_last_attempt with score $score<br />";
2875
                                    // Within the last attempt number tracking, get the sum of
2876
                                    // the max_scores of all questions that it was
2877
                                    // made of (we need to make this call dynamic because of random questions selection)
2878
                                    $sql = "SELECT SUM(t.ponderation) as maxscore FROM
2879
                                            (
2880
                                                SELECT DISTINCT
2881
                                                    question_id,
2882
                                                    marks,
2883
                                                    ponderation
2884
                                                FROM $tbl_stats_attempts AS at
2885
                                                INNER JOIN $tbl_quiz_questions AS q
2886
                                                ON (q.id = at.question_id AND q.c_id = q.c_id)
2887
                                                WHERE
2888
                                                    exe_id ='$id_last_attempt' AND
2889
                                                    q.c_id = $course_id
2890
                                            )
2891
                                            AS t";
2892
2893
                                    $res_max_score_bis = Database::query($sql);
2894
                                    $row_max_score_bis = Database::fetch_array($res_max_score_bis);
2895
2896
                                    if (!empty($row_max_score_bis['maxscore'])) {
2897
                                        $max_score = $row_max_score_bis['maxscore'];
2898
                                    }
2899
                                    if (!empty($max_score) && floatval($max_score) > 0) {
2900
                                        $lpPartialTotal += $score / $max_score;
2901
                                    }
2902
                                    if ($debug) {
2903
                                        var_dump("score: $score");
2904
                                        var_dump("max_score: $max_score");
2905
                                        var_dump("lpPartialTotal: $lpPartialTotal");
2906
                                    }
2907
                                }
2908
                            }
2909
2910
                            if (in_array($row_max_score['item_type'], array('quiz', 'sco'))) {
2911
                                // Normal way
2912
                                if ($use_max_score[$lp_id]) {
2913
                                    $count_items++;
2914
                                } else {
2915
                                    if ($max_score != '') {
2916
                                        $count_items++;
2917
                                    }
2918
                                }
2919
                                if ($debug) echo '$count_items: '.$count_items;
2920
                            }
2921
                        } //end for
2922
2923
                        $score_of_scorm_calculate += $count_items ? (($lpPartialTotal / $count_items) * 100) : 0;
2924
                        $global_result += $score_of_scorm_calculate;
2925
2926
                        if ($debug) {
2927
                            var_dump("count_items: $count_items");
2928
                            var_dump("score_of_scorm_calculate: $score_of_scorm_calculate");
2929
                            var_dump("global_result: $global_result");
2930
                        }
2931
                    } // end while
2932
                }
2933
2934
                $lp_with_quiz = 0;
2935
                foreach ($lp_list as $lp_id) {
2936
                    // Check if LP have a score we assume that all SCO have an score
2937
                    $sql = "SELECT count(id) as count
2938
                            FROM $lp_item_table
2939
                            WHERE
2940
                                c_id = $course_id AND
2941
                                (item_type = 'quiz' OR item_type = 'sco') AND
2942
                                lp_id = ".$lp_id;
2943
                    if ($debug) {
2944
                        var_dump($sql);
2945
                    }
2946
                    $result_have_quiz = Database::query($sql);
2947
                    if (Database::num_rows($result_have_quiz) > 0) {
2948
                        $row = Database::fetch_array($result_have_quiz, 'ASSOC');
2949
                        if (is_numeric($row['count']) && $row['count'] != 0) {
2950
                            $lp_with_quiz++;
2951
                        }
2952
                    }
2953
                }
2954
2955
                if ($debug) echo '<h3>$lp_with_quiz '.$lp_with_quiz.' </h3>';
2956
                if ($debug) echo '<h3>Final return</h3>';
2957
2958
                if ($lp_with_quiz != 0) {
2959
                    if (!$return_array) {
2960
                        $score_of_scorm_calculate = round(($global_result / $lp_with_quiz), 2);
2961
                        if ($debug) var_dump($score_of_scorm_calculate);
2962
                        if (empty($lp_ids)) {
2963
                            if ($debug) echo '<h2>All lps fix: '.$score_of_scorm_calculate.'</h2>';
2964
                        }
2965
                        return $score_of_scorm_calculate;
2966
                    } else {
2967
                        if ($debug) var_dump($global_result, $lp_with_quiz);
2968
                        return array($global_result, $lp_with_quiz);
2969
                    }
2970
                } else {
2971
2972
                    return '-';
2973
                }
2974
            }
2975
        }
2976
2977
        return null;
2978
    }
2979
2980
    /**
2981
     * This function gets:
2982
     * 1. The score average from all SCORM Test items in all LP in a course-> All the answers / All the max scores.
2983
     * 2. The score average from all Tests (quiz) in all LP in a course-> All the answers / All the max scores.
2984
     * 3. And finally it will return the average between 1. and 2.
2985
     * This function does not take the results of a Test out of a LP
2986
     *
2987
     * @param   int|array   Array of user ids or an user id
2988
     * @param   string      $course_code Course code
2989
     * @param   array       $lp_ids List of LP ids
2990
     * @param   int         $session_id Session id (optional), if param $session_id is 0(default)
2991
     * it'll return results including sessions, 0 = session is not filtered
2992
     * @param   bool        Returns an array of the type [sum_score, num_score] if set to true
2993
     * @param   bool        get only the latest attempts or ALL attempts
2994
     * @return  string      Value (number %) Which represents a round integer explain in got in 3.
2995
     */
2996
    public static function getAverageStudentScore(
2997
        $student_id,
2998
        $course_code = '',
2999
        $lp_ids = array(),
3000
        $session_id = 0
3001
    ) {
3002
        if (empty($student_id)) {
3003
            return 0;
3004
        }
3005
3006
        $conditions = array();
3007
        if (!empty($course_code)) {
3008
            $course = api_get_course_info($course_code);
3009
            $courseId = $course['real_id'];
3010
            $conditions[] = " c_id = $courseId";
3011
        }
3012
3013
        // Get course tables names
3014
        $lp_table = Database::get_course_table(TABLE_LP_MAIN);
3015
        $lp_item_table = Database::get_course_table(TABLE_LP_ITEM);
3016
        $lp_view_table = Database::get_course_table(TABLE_LP_VIEW);
3017
        $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3018
3019
        // Compose a filter based on optional learning paths list given
3020
        if (!empty($lp_ids) && count($lp_ids) > 0) {
3021
            $conditions[] = " id IN(".implode(',', $lp_ids).") ";
3022
        }
3023
3024
        // Compose a filter based on optional session id
3025
        $session_id = intval($session_id);
3026
        if (!empty($session_id)) {
3027
            $conditions[] = " session_id = $session_id ";
3028
        }
3029
3030
        if (is_array($student_id)) {
3031
            array_walk($student_id, 'intval');
3032
            $conditions[] = " lp_view.user_id IN (".implode(',', $student_id).") ";
3033
        } else {
3034
            $conditions[] = " lp_view.user_id = $student_id ";
3035
        }
3036
3037
        $conditionsToString = implode('AND ', $conditions);
3038
        $sql = "SELECT
3039
                    SUM(lp_iv.score) sum_score,
3040
                    SUM(lp_i.max_score) sum_max_score
3041
                FROM $lp_table as lp
3042
                INNER JOIN $lp_item_table as lp_i
3043
                ON lp.id = lp_id AND lp.c_id = lp_i.c_id
3044
                INNER JOIN $lp_view_table as lp_view
3045
                ON lp_view.lp_id = lp_i.lp_id AND lp_view.c_id = lp_i.c_id
3046
                INNER JOIN $lp_item_view_table as lp_iv
3047
                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
3048
                WHERE (lp_i.item_type='sco' OR lp_i.item_type='".TOOL_QUIZ."') AND
3049
                $conditionsToString
3050
        ";
3051
        $result = Database::query($sql);
3052
        $row = Database::fetch_array($result, 'ASSOC');
3053
3054
        if (empty($row['sum_max_score'])) {
3055
            return 0;
3056
        }
3057
3058
        return ($row['sum_score'] / $row['sum_max_score']) * 100;
3059
    }
3060
3061
    /**
3062
     * This function gets time spent in learning path for a student inside a course
3063
     * @param int|array $student_id Student id(s)
3064
     * @param string $course_code Course code
3065
     * @param array $lp_ids Limit average to listed lp ids
3066
     * @param int $session_id Session id (optional), if param $session_id is null(default)
3067
     * it'll return results including sessions, 0 = session is not filtered
3068
     * @return int Total time
3069
     */
3070
    public static function get_time_spent_in_lp(
3071
        $student_id,
3072
        $course_code,
3073
        $lp_ids = array(),
3074
        $session_id = 0
3075
    ) {
3076
        $course = api_get_course_info($course_code);
3077
        $student_id = (int) $student_id;
3078
        $session_id = (int) $session_id;
3079
        $total_time = 0;
3080
3081
        if (!empty($course)) {
3082
            $lp_table = Database::get_course_table(TABLE_LP_MAIN);
3083
            $t_lpv = Database::get_course_table(TABLE_LP_VIEW);
3084
            $t_lpiv = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3085
            $course_id = $course['real_id'];
3086
3087
            // Compose a filter based on optional learning paths list given
3088
            $condition_lp = '';
3089
            if (count($lp_ids) > 0) {
3090
                $condition_lp = " AND id IN(".implode(',', $lp_ids).") ";
3091
            }
3092
3093
            // Check the real number of LPs corresponding to the filter in the
3094
            // database (and if no list was given, get them all)
3095
            $sql = "SELECT DISTINCT(id) FROM $lp_table 
3096
                    WHERE c_id = $course_id $condition_lp";
3097
            $res_row_lp = Database::query($sql);
3098
            $count_row_lp = Database::num_rows($res_row_lp);
3099
3100
            // calculates time
3101
            if ($count_row_lp > 0) {
3102
                while ($row_lp = Database::fetch_array($res_row_lp)) {
3103
                    $lp_id = intval($row_lp['id']);
3104
                    $sql = "SELECT SUM(total_time)
3105
                            FROM $t_lpiv AS item_view
3106
                            INNER JOIN $t_lpv AS view
3107
                            ON (
3108
                                item_view.lp_view_id = view.id AND
3109
                                item_view.c_id = view.c_id
3110
                            )
3111
                            WHERE
3112
                                item_view.c_id = $course_id AND
3113
                                view.c_id = $course_id AND
3114
                                view.lp_id = $lp_id AND
3115
                                view.user_id = $student_id AND
3116
                                session_id = $session_id";
3117
3118
                    $rs = Database::query($sql);
3119
                    if (Database::num_rows($rs) > 0) {
3120
                        $total_time += Database::result($rs, 0, 0);
3121
                    }
3122
                }
3123
            }
3124
        }
3125
3126
        return $total_time;
3127
    }
3128
3129
    /**
3130
     * This function gets last connection time to one learning path
3131
     * @param int|array $student_id Student id(s)
3132
     * @param string $course_code      Course code
3133
     * @param int $lp_id    Learning path id
3134
     * @param int $session_id
3135
     * @return int         Total time
3136
     */
3137
    public static function get_last_connection_time_in_lp(
3138
        $student_id,
3139
        $course_code,
3140
        $lp_id,
3141
        $session_id = 0
3142
    ) {
3143
        $course = api_get_course_info($course_code);
3144
        $student_id = intval($student_id);
3145
        $lp_id = intval($lp_id);
3146
        $last_time = 0;
3147
        $session_id = intval($session_id);
3148
3149
        if (!empty($course)) {
3150
            $course_id = $course['real_id'];
3151
            $lp_table = Database::get_course_table(TABLE_LP_MAIN);
3152
            $t_lpv = Database::get_course_table(TABLE_LP_VIEW);
3153
            $t_lpiv = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3154
3155
            // Check the real number of LPs corresponding to the filter in the
3156
            // database (and if no list was given, get them all)
3157
            $sql = "SELECT id FROM $lp_table 
3158
                    WHERE c_id = $course_id AND id = $lp_id ";
3159
            $res_row_lp = Database::query($sql);
3160
            $count_row_lp = Database::num_rows($res_row_lp);
3161
3162
            // calculates last connection time
3163
            if ($count_row_lp > 0) {
3164
                $sql = 'SELECT MAX(start_time)
3165
                        FROM '.$t_lpiv.' AS item_view
3166
                        INNER JOIN '.$t_lpv.' AS view
3167
                        ON (item_view.lp_view_id = view.id AND item_view.c_id = view.c_id)
3168
                        WHERE
3169
                            total_time > 0 AND
3170
                            item_view.c_id = '.$course_id.' AND
3171
                            view.c_id = '.$course_id.' AND
3172
                            view.lp_id = '.$lp_id.' AND 
3173
                            view.user_id = '.$student_id.' AND 
3174
                            view.session_id = '.$session_id;
3175
                $rs = Database::query($sql);
3176
                if (Database::num_rows($rs) > 0) {
3177
                    $last_time = Database::result($rs, 0, 0);
3178
                }
3179
            }
3180
        }
3181
3182
        return $last_time;
3183
    }
3184
3185
    /**
3186
     * gets the list of students followed by coach
3187
     * @param     int     $coach_id Coach id
3188
     * @return     array     List of students
3189
     */
3190
    public static function get_student_followed_by_coach($coach_id)
3191
    {
3192
        $coach_id = intval($coach_id);
3193
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3194
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3195
        $tbl_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
3196
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3197
3198
        $students = [];
3199
        // At first, courses where $coach_id is coach of the course //
3200
        $sql = 'SELECT session_id, c_id
3201
                FROM ' . $tbl_session_course_user.'
3202
                WHERE user_id=' . $coach_id.' AND status=2';
3203
3204
        if (api_is_multiple_url_enabled()) {
3205
            $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3206
            $access_url_id = api_get_current_access_url_id();
3207
            if ($access_url_id != -1) {
3208
                $sql = 'SELECT scu.session_id, scu.c_id
3209
                        FROM '.$tbl_session_course_user.' scu
3210
                        INNER JOIN '.$tbl_session_rel_access_url.'  sru
3211
                        ON (scu.session_id=sru.session_id)
3212
                        WHERE
3213
                            scu.user_id=' . $coach_id.' AND
3214
                            scu.status=2 AND
3215
                            sru.access_url_id = '.$access_url_id;
3216
            }
3217
        }
3218
3219
        $result = Database::query($sql);
3220
3221
        while ($a_courses = Database::fetch_array($result)) {
3222
            $courseId = $a_courses['c_id'];
3223
            $id_session = $a_courses['session_id'];
3224
3225
            $sql = "SELECT DISTINCT srcru.user_id
3226
                    FROM $tbl_session_course_user AS srcru
3227
                    INNER JOIN $tbl_session_user sru
3228
                    ON (srcru.user_id = sru.user_id AND srcru.session_id = sru.session_id)
3229
                    WHERE
3230
                        sru.relation_type<>".SESSION_RELATION_TYPE_RRHH." AND
3231
                        srcru.c_id = '$courseId' AND
3232
                        srcru.session_id = '$id_session'";
3233
3234
            $rs = Database::query($sql);
3235
            while ($row = Database::fetch_array($rs)) {
3236
                $students[$row['user_id']] = $row['user_id'];
3237
            }
3238
        }
3239
3240
        // Then, courses where $coach_id is coach of the session    //
3241
        $sql = 'SELECT session_course_user.user_id
3242
                FROM '.$tbl_session_course_user.' as session_course_user
3243
                INNER JOIN '.$tbl_session_user.' sru
3244
                ON session_course_user.user_id = sru.user_id AND session_course_user.session_id = sru.session_id
3245
                INNER JOIN '.$tbl_session_course.' as session_course
3246
                ON session_course.c_id = session_course_user.c_id
3247
                AND session_course_user.session_id = session_course.session_id
3248
                INNER JOIN '.$tbl_session.' as session
3249
                ON session.id = session_course.session_id
3250
                AND session.id_coach = ' . $coach_id;
3251
        if (api_is_multiple_url_enabled()) {
3252
            $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3253
            $access_url_id = api_get_current_access_url_id();
3254
            if ($access_url_id != -1) {
3255
                $sql = 'SELECT session_course_user.user_id
3256
                        FROM '.$tbl_session_course_user.' as session_course_user
3257
                        INNER JOIN '.$tbl_session_user.' sru
3258
                        ON session_course_user.user_id = sru.user_id AND
3259
                           session_course_user.session_id = sru.session_id
3260
                        INNER JOIN '.$tbl_session_course.' as session_course
3261
                        ON session_course.c_id = session_course_user.c_id AND
3262
                        session_course_user.session_id = session_course.session_id
3263
                        INNER JOIN '.$tbl_session.' as session
3264
                        ON session.id = session_course.session_id AND
3265
                        session.id_coach = '.$coach_id.'
3266
                        INNER JOIN '.$tbl_session_rel_access_url.' session_rel_url
3267
                        ON session.id = session_rel_url.session_id 
3268
                        WHERE access_url_id = '.$access_url_id;
3269
            }
3270
        }
3271
3272
        $result = Database::query($sql);
3273
        while ($row = Database::fetch_array($result)) {
3274
            $students[$row['user_id']] = $row['user_id'];
3275
        }
3276
3277
        return $students;
3278
    }
3279
3280
    /**
3281
     * Get student followed by a coach inside a session
3282
     * @param    int        Session id
3283
     * @param    int        Coach id
3284
     * @return   array    students list
3285
     */
3286
    public static function get_student_followed_by_coach_in_a_session(
3287
        $id_session,
3288
        $coach_id
3289
    ) {
3290
        $coach_id = intval($coach_id);
3291
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3292
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3293
3294
        $students = [];
3295
        // At first, courses where $coach_id is coach of the course //
3296
        $sql = 'SELECT c_id FROM '.$tbl_session_course_user.'
3297
                WHERE session_id="' . $id_session.'" AND user_id='.$coach_id.' AND status=2';
3298
        $result = Database::query($sql);
3299
3300
        while ($a_courses = Database::fetch_array($result)) {
3301
            $courseId = $a_courses['c_id'];
3302
            $sql = "SELECT DISTINCT srcru.user_id
3303
                    FROM $tbl_session_course_user AS srcru
3304
                    WHERE
3305
                        c_id = '$courseId' AND
3306
                        session_id = '".$id_session."'";
3307
            $rs = Database::query($sql);
3308
            while ($row = Database::fetch_array($rs)) {
3309
                $students[$row['user_id']] = $row['user_id'];
3310
            }
3311
        }
3312
3313
        // Then, courses where $coach_id is coach of the session
3314
        $sql = 'SELECT id_coach FROM '.$tbl_session.'
3315
                WHERE id="' . $id_session.'" AND id_coach="'.$coach_id.'"';
3316
        $result = Database::query($sql);
3317
3318
        //He is the session_coach so we select all the users in the session
3319
        if (Database::num_rows($result) > 0) {
3320
            $sql = 'SELECT DISTINCT srcru.user_id
3321
                    FROM ' . $tbl_session_course_user.' AS srcru
3322
                    WHERE session_id="' . $id_session.'"';
3323
            $result = Database::query($sql);
3324
            while ($row = Database::fetch_array($result)) {
3325
                $students[$row['user_id']] = $row['user_id'];
3326
            }
3327
        }
3328
3329
        return $students;
3330
    }
3331
3332
    /**
3333
     * Check if a coach is allowed to follow a student
3334
     * @param    int        Coach id
3335
     * @param    int        Student id
3336
     * @return    bool
3337
     */
3338
    public static function is_allowed_to_coach_student($coach_id, $student_id)
3339
    {
3340
        $coach_id = intval($coach_id);
3341
        $student_id = intval($student_id);
3342
3343
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3344
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3345
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3346
3347
        // At first, courses where $coach_id is coach of the course //
3348
3349
        $sql = 'SELECT 1 FROM '.$tbl_session_course_user.'
3350
                WHERE user_id=' . $coach_id.' AND status=2';
3351
        $result = Database::query($sql);
3352
        if (Database::num_rows($result) > 0) {
3353
            return true;
3354
        }
3355
3356
        // Then, courses where $coach_id is coach of the session
3357
        $sql = 'SELECT session_course_user.user_id
3358
                FROM '.$tbl_session_course_user.' as session_course_user
3359
                INNER JOIN '.$tbl_session_course.' as session_course
3360
                ON session_course.c_id = session_course_user.c_id
3361
                INNER JOIN '.$tbl_session.' as session
3362
                ON session.id = session_course.session_id
3363
                AND session.id_coach = ' . $coach_id.'
3364
                WHERE user_id = ' . $student_id;
3365
        $result = Database::query($sql);
3366
        if (Database::num_rows($result) > 0) {
3367
            return true;
3368
        }
3369
3370
        return false;
3371
    }
3372
3373
    /**
3374
     * Get courses followed by coach
3375
     * @param     int        Coach id
3376
     * @param    int        Session id (optional)
3377
     * @return    array    Courses list
3378
     */
3379
    public static function get_courses_followed_by_coach($coach_id, $id_session = 0)
3380
    {
3381
        $coach_id = intval($coach_id);
3382
        if (!empty($id_session)) {
3383
            $id_session = intval($id_session);
3384
        }
3385
3386
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3387
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3388
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3389
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3390
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3391
3392
        // At first, courses where $coach_id is coach of the course.
3393
3394
        $sql = 'SELECT DISTINCT c.code
3395
                FROM ' . $tbl_session_course_user.' sc
3396
                INNER JOIN '.$tbl_course.' c
3397
                ON (c.id = sc.c_id)
3398
                WHERE user_id = ' . $coach_id.' AND status = 2';
3399
3400
        if (api_is_multiple_url_enabled()) {
3401
            $access_url_id = api_get_current_access_url_id();
3402
            if ($access_url_id != -1) {
3403
                $sql = 'SELECT DISTINCT c.code
3404
                        FROM ' . $tbl_session_course_user.' scu
3405
                        INNER JOIN '.$tbl_course.' c
3406
                        ON (c.code = scu.c_id)
3407
                        INNER JOIN '.$tbl_course_rel_access_url.' cru
3408
                        ON (c.id = cru.c_id)
3409
                        WHERE
3410
                            scu.user_id=' . $coach_id.' AND
3411
                            scu.status=2 AND
3412
                            cru.access_url_id = '.$access_url_id;
3413
            }
3414
        }
3415
3416
        if (!empty($id_session)) {
3417
            $sql .= ' AND session_id='.$id_session;
3418
        }
3419
3420
        $courseList = array();
3421
        $result = Database::query($sql);
3422
        while ($row = Database::fetch_array($result)) {
3423
            $courseList[$row['code']] = $row['code'];
3424
        }
3425
3426
        // Then, courses where $coach_id is coach of the session
3427
        $sql = 'SELECT DISTINCT course.code
3428
                FROM '.$tbl_session_course.' as session_course
3429
                INNER JOIN '.$tbl_session.' as session
3430
                    ON session.id = session_course.session_id
3431
                    AND session.id_coach = '.$coach_id.'
3432
                INNER JOIN '.$tbl_course.' as course
3433
                    ON course.id = session_course.c_id';
3434
3435
        if (api_is_multiple_url_enabled()) {
3436
            $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3437
            $access_url_id = api_get_current_access_url_id();
3438
            if ($access_url_id != -1) {
3439
                $sql = 'SELECT DISTINCT c.code
3440
                    FROM '.$tbl_session_course.' as session_course
3441
                    INNER JOIN '.$tbl_course.' c
3442
                    ON (c.id = session_course.c_id)
3443
                    INNER JOIN '.$tbl_session.' as session
3444
                    ON session.id = session_course.session_id
3445
                        AND session.id_coach = '.$coach_id.'
3446
                    INNER JOIN '.$tbl_course.' as course
3447
                        ON course.id = session_course.c_id
3448
                     INNER JOIN '.$tbl_course_rel_access_url.' course_rel_url
3449
                    ON (course_rel_url.c_id = c.id)';
3450
            }
3451
        }
3452
3453
        if (!empty ($id_session)) {
3454
            $sql .= ' WHERE session_course.session_id='.$id_session;
3455
            if (api_is_multiple_url_enabled())
3456
            $sql .= ' AND access_url_id = '.$access_url_id;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $access_url_id does not seem to be defined for all execution paths leading up to this point.
Loading history...
3457
        } else {
3458
            if (api_is_multiple_url_enabled())
3459
            $sql .= ' WHERE access_url_id = '.$access_url_id;
3460
        }
3461
3462
        $result = Database::query($sql);
3463
        while ($row = Database::fetch_array($result)) {
3464
            $courseList[$row['code']] = $row['code'];
3465
        }
3466
3467
        return $courseList;
3468
    }
3469
3470
    /**
3471
     * Get sessions coached by user
3472
     * @param $coach_id
3473
     * @param int $start
3474
     * @param int $limit
3475
     * @param bool $getCount
3476
     * @param string $keyword
3477
     * @param string $description
3478
     * @return mixed
3479
     */
3480
    public static function get_sessions_coached_by_user(
3481
        $coach_id,
3482
        $start = 0,
3483
        $limit = 0,
3484
        $getCount = false,
3485
        $keyword = '',
3486
        $description = ''
3487
    ) {
3488
        // table definition
3489
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3490
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3491
        $coach_id = intval($coach_id);
3492
3493
        $select = " SELECT * FROM ";
3494
        if ($getCount) {
3495
            $select = " SELECT count(DISTINCT id) as count FROM ";
3496
        }
3497
3498
        $limitCondition = null;
3499
        if (!empty($start) && !empty($limit)) {
3500
            $limitCondition = " LIMIT ".intval($start).", ".intval($limit);
3501
        }
3502
3503
        $keywordCondition = null;
3504
3505
        if (!empty($keyword)) {
3506
            $keyword = Database::escape_string($keyword);
3507
            $keywordCondition = " AND (name LIKE '%$keyword%' ) ";
3508
3509
            if (!empty($description)) {
3510
                $description = Database::escape_string($description);
3511
                $keywordCondition = " AND (name LIKE '%$keyword%' OR description LIKE '%$description%' ) ";
3512
            }
3513
        }
3514
3515
        $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
3516
        $access_url_id = api_get_current_access_url_id();
3517
3518
        $sql = "
3519
            $select
3520
            (
3521
                SELECT DISTINCT
3522
                    id,
3523
                    name,
3524
                    access_start_date,
3525
                    access_end_date
3526
                FROM $tbl_session session
3527
                INNER JOIN $tbl_session_rel_access_url session_rel_url
3528
                ON (session.id = session_rel_url.session_id)
3529
                WHERE
3530
                    id_coach = $coach_id AND
3531
                    access_url_id = $access_url_id
3532
                    $keywordCondition
3533
            UNION
3534
                SELECT DISTINCT
3535
                    session.id,
3536
                    session.name,
3537
                    session.access_start_date,
3538
                    session.access_end_date
3539
                FROM $tbl_session as session
3540
                INNER JOIN $tbl_session_course_user as session_course_user
3541
                ON
3542
                    session.id = session_course_user.session_id AND
3543
                    session_course_user.user_id = $coach_id AND
3544
                    session_course_user.status = 2
3545
                INNER JOIN $tbl_session_rel_access_url session_rel_url
3546
                ON (session.id = session_rel_url.session_id)
3547
                WHERE
3548
                    access_url_id = $access_url_id
3549
                    $keywordCondition
3550
            ) as sessions $limitCondition
3551
            ";
3552
3553
        $rs = Database::query($sql);
3554
        if ($getCount) {
3555
            $row = Database::fetch_array($rs);
3556
            return $row['count'];
3557
        }
3558
3559
        $sessions = [];
3560
        while ($row = Database::fetch_array($rs)) {
3561
            if ($row['access_start_date'] == '0000-00-00 00:00:00') {
3562
                $row['access_start_date'] = null;
3563
            }
3564
3565
            $sessions[$row['id']] = $row;
3566
        }
3567
3568
        if (!empty($sessions)) {
3569
            foreach ($sessions as & $session) {
3570
                if (empty($session['access_start_date'])
3571
                ) {
3572
                    $session['status'] = get_lang('SessionActive');
3573
                }
3574
                else {
3575
                    $time_start = api_strtotime($session['access_start_date'], 'UTC');
3576
                    $time_end = api_strtotime($session['access_end_date'], 'UTC');
3577
                    if ($time_start < time() && time() < $time_end) {
3578
                        $session['status'] = get_lang('SessionActive');
3579
                    } else {
3580
                        if (time() < $time_start) {
3581
                            $session['status'] = get_lang('SessionFuture');
3582
                        } else {
3583
                            if (time() > $time_end) {
3584
                                $session['status'] = get_lang('SessionPast');
3585
                            }
3586
                        }
3587
                    }
3588
                }
3589
            }
3590
        }
3591
3592
        return $sessions;
3593
    }
3594
3595
    /**
3596
     * Get courses list from a session
3597
     * @param    int        Session id
3598
     * @return    array    Courses list
3599
     */
3600
    public static function get_courses_list_from_session($session_id)
3601
    {
3602
        $session_id = intval($session_id);
3603
3604
        // table definition
3605
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3606
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
3607
3608
        $sql = "SELECT DISTINCT code, c_id
3609
                FROM $tbl_session_course sc
3610
                INNER JOIN $courseTable c
3611
                ON sc.c_id = c.id
3612
                WHERE session_id= $session_id";
3613
3614
        $result = Database::query($sql);
3615
3616
        $courses = array();
3617
        while ($row = Database::fetch_array($result)) {
3618
            $courses[$row['code']] = $row;
3619
        }
3620
3621
        return $courses;
3622
    }
3623
3624
    /**
3625
     * Count the number of documents that an user has uploaded to a course
3626
     * @param    int|array   Student id(s)
3627
     * @param    string      Course code
3628
     * @param    int         Session id (optional),
3629
     * if param $session_id is null(default)
3630
     * return count of assignments including sessions, 0 = session is not filtered
3631
     * @return    int        Number of documents
3632
     */
3633
    public static function count_student_uploaded_documents(
3634
        $student_id,
3635
        $course_code,
3636
        $session_id = null
3637
    ) {
3638
        // get the information of the course
3639
        $a_course = api_get_course_info($course_code);
3640
        if (!empty($a_course)) {
3641
            // table definition
3642
            $tbl_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
3643
            $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
3644
            $course_id = $a_course['real_id'];
3645
            if (is_array($student_id)) {
3646
                $studentList = array_map('intval', $student_id);
3647
                $condition_user = " AND ip.insert_user_id IN ('".implode(',', $studentList)."') ";
3648
            } else {
3649
                $student_id = intval($student_id);
3650
                $condition_user = " AND ip.insert_user_id = '$student_id' ";
3651
            }
3652
3653
            $condition_session = null;
3654
            if (isset($session_id)) {
3655
                $session_id = intval($session_id);
3656
                $condition_session = " AND pub.session_id = $session_id ";
3657
            }
3658
3659
            $sql = "SELECT count(ip.tool) AS count
3660
                    FROM $tbl_item_property ip
3661
                    INNER JOIN $tbl_document pub
3662
                    ON (ip.ref = pub.id AND ip.c_id = pub.c_id)
3663
                    WHERE
3664
                        ip.c_id  = $course_id AND
3665
                        pub.c_id  = $course_id AND
3666
                        pub.filetype ='file' AND
3667
                        ip.tool = 'document'
3668
                        $condition_user $condition_session ";
3669
            $rs = Database::query($sql);
3670
            $row = Database::fetch_array($rs, 'ASSOC');
3671
            return $row['count'];
3672
        }
3673
        return null;
3674
    }
3675
3676
    /**
3677
     * Count assignments per student
3678
     * @param $student_id
3679
     * @param null $course_code
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $course_code is correct as it would always require null to be passed?
Loading history...
Documentation Bug introduced by
Are you sure the doc-type for parameter $session_id is correct as it would always require null to be passed?
Loading history...
3680
     * @param null $session_id
3681
     * @return int Count of assignments
3682
     * @internal param array|int $Student id(s)
3683
     * @internal param Course $string code
3684
     * @internal param Session $int id (optional),
3685
     * if param $session_id is null(default) return count of assignments
3686
     * including sessions, 0 = session is not filtered
3687
     */
3688
    public static function count_student_assignments(
3689
        $student_id,
3690
        $course_code = null,
3691
        $session_id = null
3692
    ) {
3693
        if (empty($student_id)) {
3694
            return 0;
3695
        }
3696
3697
        $conditions = array();
3698
3699
        // Get the information of the course
3700
        $a_course = api_get_course_info($course_code);
3701
        if (!empty($a_course)) {
3702
            $course_id = $a_course['real_id'];
3703
            $conditions[] = " ip.c_id  = $course_id AND pub.c_id  = $course_id ";
3704
        }
3705
3706
        // table definition
3707
        $tbl_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
3708
        $tbl_student_publication = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
3709
3710
        if (is_array($student_id)) {
3711
            $studentList = array_map('intval', $student_id);
3712
            $conditions[] = " ip.insert_user_id IN ('".implode("','", $studentList)."') ";
3713
        } else {
3714
            $student_id = intval($student_id);
3715
            $conditions[] = " ip.insert_user_id = '$student_id' ";
3716
        }
3717
3718
        $conditions[] = ' pub.active <> 2 ';
3719
        $conditionToString = implode(' AND ', $conditions);
3720
3721
        $sessionCondition = api_get_session_condition($session_id, true, false, 'pub.session_id');
3722
        $conditionToString .= $sessionCondition;
3723
3724
        $sql = "SELECT count(ip.tool) as count
3725
                FROM $tbl_item_property ip
3726
                INNER JOIN $tbl_student_publication pub
3727
                ON (ip.ref = pub.id AND ip.c_id = pub.c_id)
3728
                WHERE
3729
                    ip.tool='work' AND
3730
                    $conditionToString";
3731
        $rs = Database::query($sql);
3732
3733
        $row = Database::fetch_array($rs, 'ASSOC');
3734
3735
        return $row['count'];
3736
    }
3737
3738
    /**
3739
     * Count messages per student inside forum tool
3740
     * @param    int|array        Student id
3741
     * @param    string    Course code
3742
     * @param    int        Session id (optional), if param $session_id is
3743
     * null(default) return count of messages including sessions, 0 = session is not filtered
3744
     * @return    int        Count of messages
3745
     */
3746
    public static function count_student_messages($student_id, $courseCode = null, $session_id = null)
3747
    {
3748
        if (empty($student_id)) {
3749
            return 0;
3750
        }
3751
3752
        // Table definition.
3753
        $tbl_forum_post = Database::get_course_table(TABLE_FORUM_POST);
3754
        $tbl_forum = Database::get_course_table(TABLE_FORUM);
3755
3756
        $conditions = array();
3757
        if (is_array($student_id)) {
3758
            $studentList = array_map('intval', $student_id);
3759
            $conditions[] = " post.poster_id IN ('".implode("','", $studentList)."') ";
3760
        } else {
3761
            $student_id = intval($student_id);
3762
            $conditions[] = " post.poster_id = '$student_id' ";
3763
        }
3764
3765
        $conditionsToString = implode('AND ', $conditions);
3766
3767
        if (empty($courseCode)) {
3768
            $sql = "SELECT count(poster_id) as count
3769
                    FROM $tbl_forum_post post
3770
                    INNER JOIN $tbl_forum forum
3771
                    ON (forum.forum_id = post.forum_id AND forum.c_id = post.c_id)
3772
                    WHERE $conditionsToString";
3773
3774
            $rs = Database::query($sql);
3775
            $row = Database::fetch_array($rs, 'ASSOC');
3776
            return $row['count'];
3777
        }
3778
3779
        require_once api_get_path(SYS_CODE_PATH).'forum/forumconfig.inc.php';
3780
        require_once api_get_path(SYS_CODE_PATH).'forum/forumfunction.inc.php';
3781
3782
        $courseInfo = api_get_course_info($courseCode);
3783
3784
        $forums = [];
3785
        if (!empty($courseInfo)) {
3786
            $forums = get_forums('', $courseCode, true, $session_id);
3787
            $course_id = $courseInfo['real_id'];
3788
            $conditions[] = " post.c_id  = $course_id ";
3789
        }
3790
3791
        if (!empty($forums)) {
3792
            $idList = array_column($forums, 'forum_id');
3793
            $idListToString = implode("', '", $idList);
3794
            $conditions[] = " post.forum_id  IN ('$idListToString')";
3795
        }
3796
3797
        $conditionsToString = implode('AND ', $conditions);
3798
        $sql = "SELECT count(poster_id) as count
3799
                FROM $tbl_forum_post post
3800
                WHERE $conditionsToString";
3801
3802
        $rs = Database::query($sql);
3803
        $row = Database::fetch_array($rs, 'ASSOC');
3804
        $count = $row['count'];
3805
3806
        return $count;
3807
    }
3808
3809
    /**
3810
     * This function counts the number of post by course
3811
     * @param      string     Course code
3812
     * @param    int        Session id (optional), if param $session_id is
3813
     * null(default) it'll return results including sessions,
3814
     * 0 = session is not filtered
3815
     * @param int $groupId
3816
     * @return    int     The number of post by course
3817
     */
3818
    public static function count_number_of_posts_by_course($course_code, $session_id = null, $groupId = 0)
3819
    {
3820
        $courseInfo = api_get_course_info($course_code);
3821
        if (!empty($courseInfo)) {
3822
            $tbl_posts = Database::get_course_table(TABLE_FORUM_POST);
3823
            $tbl_forums = Database::get_course_table(TABLE_FORUM);
3824
3825
            $condition_session = '';
3826
            if (isset($session_id)) {
3827
                $session_id = intval($session_id);
3828
                $condition_session = api_get_session_condition(
3829
                    $session_id,
3830
                    true,
3831
                    false,
3832
                    'f.session_id'
3833
                );
3834
            }
3835
3836
            $course_id = $courseInfo['real_id'];
3837
            $groupId = intval($groupId);
3838
            if (!empty($groupId)) {
3839
                $groupCondition = " i.to_group_id = $groupId  ";
3840
            } else {
3841
                $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) ";
3842
            }
3843
3844
            $item = Database::get_course_table(TABLE_ITEM_PROPERTY);
3845
            $sql = "SELECT count(*) FROM $tbl_posts p
3846
                    INNER JOIN $tbl_forums f
3847
                    ON f.forum_id = p.forum_id AND p.c_id = f.c_id
3848
                    INNER JOIN $item i
3849
                    ON (tool = '".TOOL_FORUM."' AND f.c_id = i.c_id AND f.iid = i.ref)
3850
                    WHERE
3851
                        p.c_id = $course_id AND
3852
                        f.c_id = $course_id AND
3853
                        $groupCondition
3854
                        $condition_session
3855
                    ";
3856
            $result = Database::query($sql);
3857
            $row = Database::fetch_row($result);
3858
            $count = $row[0];
3859
3860
            return $count;
3861
        } else {
3862
            return null;
3863
        }
3864
    }
3865
3866
    /**
3867
     * This function counts the number of threads by course
3868
     * @param      string     Course code
3869
     * @param    int        Session id (optional),
3870
     * if param $session_id is null(default) it'll return results including
3871
     * sessions, 0 = session is not filtered
3872
     * @param int $groupId
3873
     * @return    int     The number of threads by course
3874
     */
3875
    public static function count_number_of_threads_by_course(
3876
        $course_code,
3877
        $session_id = null,
3878
        $groupId = 0
3879
    ) {
3880
        $course_info = api_get_course_info($course_code);
3881
        if (empty($course_info)) {
3882
            return null;
3883
        }
3884
3885
        $course_id = $course_info['real_id'];
3886
        $tbl_threads = Database::get_course_table(TABLE_FORUM_THREAD);
3887
        $tbl_forums = Database::get_course_table(TABLE_FORUM);
3888
3889
        $condition_session = '';
3890
        if (isset($session_id)) {
3891
            $session_id = intval($session_id);
3892
            $condition_session = ' AND f.session_id = '.$session_id;
3893
        }
3894
3895
        $groupId = intval($groupId);
3896
3897
        if (!empty($groupId)) {
3898
            $groupCondition = " i.to_group_id = $groupId ";
3899
        } else {
3900
            $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) ";
3901
        }
3902
3903
        $item = Database::get_course_table(TABLE_ITEM_PROPERTY);
3904
        $sql = "SELECT count(*)
3905
                FROM $tbl_threads t
3906
                INNER JOIN $tbl_forums f
3907
                ON f.iid = t.forum_id AND f.c_id = t.c_id
3908
                INNER JOIN $item i
3909
                ON (
3910
                    tool = '".TOOL_FORUM_THREAD."' AND
3911
                    f.c_id = i.c_id AND
3912
                    t.iid = i.ref
3913
                )
3914
                WHERE
3915
                    t.c_id = $course_id AND
3916
                    f.c_id = $course_id AND
3917
                    $groupCondition
3918
                    $condition_session
3919
                ";
3920
3921
        $result = Database::query($sql);
3922
        if (Database::num_rows($result)) {
3923
            $row = Database::fetch_row($result);
3924
            $count = $row[0];
3925
3926
            return $count;
3927
        } else {
3928
3929
            return null;
3930
        }
3931
    }
3932
3933
    /**
3934
     * This function counts the number of forums by course
3935
     * @param      string     Course code
3936
     * @param    int        Session id (optional),
3937
     * if param $session_id is null(default) it'll return results
3938
     * including sessions, 0 = session is not filtered
3939
     * @param int $groupId
3940
     * @return    int     The number of forums by course
3941
     */
3942
    public static function count_number_of_forums_by_course(
3943
        $course_code,
3944
        $session_id = null,
3945
        $groupId = 0
3946
    ) {
3947
        $course_info = api_get_course_info($course_code);
3948
        if (empty($course_info)) {
3949
            return null;
3950
        }
3951
        $course_id = $course_info['real_id'];
3952
3953
        $condition_session = '';
3954
        if (isset($session_id)) {
3955
             $session_id = intval($session_id);
3956
             $condition_session = ' AND f.session_id = '.$session_id;
3957
        }
3958
3959
        $groupId = intval($groupId);
3960
        if (!empty($groupId)) {
3961
            $groupCondition = " i.to_group_id = $groupId ";
3962
        } else {
3963
            $groupCondition = " (i.to_group_id = 0 OR i.to_group_id IS NULL) ";
3964
        }
3965
3966
        $tbl_forums = Database::get_course_table(TABLE_FORUM);
3967
        $item = Database::get_course_table(TABLE_ITEM_PROPERTY);
3968
3969
        $sql = "SELECT count(*)
3970
                FROM $tbl_forums f
3971
                INNER JOIN $item i
3972
                ON f.c_id = i.c_id AND f.iid = i.ref AND tool = '".TOOL_FORUM."'
3973
                WHERE
3974
                    f.c_id = $course_id AND
3975
                    $groupCondition
3976
                    $condition_session
3977
                ";
3978
        $result = Database::query($sql);
3979
        if (Database::num_rows($result)) {
3980
            $row = Database::fetch_row($result);
3981
            $count = $row[0];
3982
            return $count;
3983
        } else {
3984
            return null;
3985
        }
3986
    }
3987
3988
    /**
3989
     * This function counts the chat last connections by course in x days
3990
     * @param      string     Course code
3991
     * @param      int     Last x days
3992
     * @param    int        Session id (optional)
3993
     * @return     int     Chat last connections by course in x days
3994
     */
3995
    public static function chat_connections_during_last_x_days_by_course(
3996
        $course_code,
3997
        $last_days,
3998
        $session_id = 0
3999
    ) {
4000
        $course_info = api_get_course_info($course_code);
4001
        if (empty($course_info)) {
4002
            return null;
4003
        }
4004
        $course_id = $course_info['real_id'];
4005
4006
        // Protect data
4007
        $last_days = intval($last_days);
4008
        $session_id = intval($session_id);
4009
        $tbl_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
4010
        $now = api_get_utc_datetime();
4011
4012
        $sql = "SELECT count(*) FROM $tbl_stats_access
4013
                WHERE
4014
                    DATE_SUB('$now',INTERVAL $last_days DAY) <= access_date AND
4015
                    c_id = '$course_id' AND
4016
                    access_tool='".TOOL_CHAT."' AND
4017
                    access_session_id='$session_id' ";
4018
        $result = Database::query($sql);
4019
        if (Database::num_rows($result)) {
4020
            $row = Database::fetch_row($result);
4021
            $count = $row[0];
4022
            return $count;
4023
        } else {
4024
            return null;
4025
        }
4026
    }
4027
4028
    /**
4029
     * This function gets the last student's connection in chat
4030
     * @param      int     Student id
4031
     * @param      string     Course code
4032
     * @param    int        Session id (optional)
4033
     * @return     string    datetime formatted without day (e.g: February 23, 2010 10:20:50 )
4034
     */
4035
    public static function chat_last_connection(
4036
        $student_id,
4037
        $courseId,
4038
        $session_id = 0
4039
    ) {
4040
        $student_id = intval($student_id);
4041
        $courseId = intval($courseId);
4042
        $session_id = intval($session_id);
4043
        $date_time  = '';
4044
4045
        // table definition
4046
        $tbl_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4047
        $sql = "SELECT access_date
4048
                FROM $tbl_stats_access
4049
                WHERE
4050
                     access_tool='".TOOL_CHAT."' AND
4051
                     access_user_id='$student_id' AND
4052
                     c_id = $courseId AND
4053
                     access_session_id = '$session_id'
4054
                ORDER BY access_date DESC limit 1";
4055
        $rs = Database::query($sql);
4056
        if (Database::num_rows($rs) > 0) {
4057
            $row = Database::fetch_array($rs);
4058
            $date_time = api_convert_and_format_date(
4059
                $row['access_date'],
4060
                null,
4061
                date_default_timezone_get()
4062
            );
4063
        }
4064
        return $date_time;
4065
    }
4066
4067
    /**
4068
     * Get count student's visited links
4069
     * @param    int $student_id Student id
4070
     * @param    int $courseId
4071
     * @param    int $session_id Session id (optional)
4072
     * @return    int        count of visited links
4073
     */
4074
    public static function count_student_visited_links($student_id, $courseId, $session_id = 0)
4075
    {
4076
        $student_id  = intval($student_id);
4077
        $courseId = intval($courseId);
4078
        $session_id  = intval($session_id);
4079
4080
        // table definition
4081
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
4082
4083
        $sql = 'SELECT 1
4084
                FROM '.$table.'
4085
                WHERE
4086
                    links_user_id= '.$student_id.' AND
4087
                    c_id = "'.$courseId.'" AND
4088
                    links_session_id = '.$session_id.' ';
4089
4090
        $rs = Database::query($sql);
4091
        return Database::num_rows($rs);
4092
    }
4093
4094
    /**
4095
     * Get count student downloaded documents
4096
     * @param    int        Student id
4097
     * @param    int    $courseId
4098
     * @param    int        Session id (optional)
4099
     * @return    int        Count downloaded documents
4100
     */
4101
    public static function count_student_downloaded_documents($student_id, $courseId, $session_id = 0)
4102
    {
4103
        $student_id  = intval($student_id);
4104
        $courseId = intval($courseId);
4105
        $session_id  = intval($session_id);
4106
4107
        // table definition
4108
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
4109
4110
        $sql = 'SELECT 1
4111
                FROM '.$table.'
4112
                WHERE down_user_id = '.$student_id.'
4113
                AND c_id  = "'.$courseId.'"
4114
                AND down_session_id = '.$session_id.' ';
4115
        $rs = Database::query($sql);
4116
4117
        return Database::num_rows($rs);
4118
    }
4119
4120
    /**
4121
     * Get course list inside a session from a student
4122
     * @param    int        $user_id Student id
4123
     * @param    int        $id_session Session id (optional)
4124
     * @return    array    Courses list
4125
     */
4126
    public static function get_course_list_in_session_from_student($user_id, $id_session = 0)
4127
    {
4128
        $user_id = intval($user_id);
4129
        $id_session = intval($id_session);
4130
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4131
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
4132
4133
        $sql = "SELECT c.code
4134
                FROM $tbl_session_course_user sc
4135
                INNER JOIN $courseTable c
4136
                WHERE
4137
                    user_id= $user_id  AND
4138
                    session_id = $id_session";
4139
        $result = Database::query($sql);
4140
        $courses = array();
4141
        while ($row = Database::fetch_array($result)) {
4142
            $courses[$row['code']] = $row['code'];
4143
        }
4144
4145
        return $courses;
4146
    }
4147
4148
    /**
4149
     * Get inactive students in course
4150
     * @param int   $courseId
4151
     * @param string|int $since  Since login course date (optional, default = 'never')
4152
     * @param int $session_id    (optional)
4153
     * @return array Inactive users
4154
     */
4155
    public static function getInactiveStudentsInCourse(
4156
        $courseId,
4157
        $since = 'never',
4158
        $session_id = 0
4159
    ) {
4160
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
4161
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4162
        $table_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4163
        $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
4164
        $now = api_get_utc_datetime();
4165
        $courseId = (int) $courseId;
4166
        $session_id = (int) $session_id;
4167
4168
        if (empty($courseId)) {
4169
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
4170
        }
4171
4172
        if ($since === 'never') {
4173
            if (empty($session_id)) {
4174
                $sql = 'SELECT course_user.user_id
4175
                        FROM ' . $table_course_rel_user.' course_user
4176
                        LEFT JOIN ' . $tbl_track_login.' stats_login
4177
                        ON course_user.user_id = stats_login.user_id AND
4178
                        relation_type<>' . COURSE_RELATION_TYPE_RRHH.'
4179
                        INNER JOIN ' . $tableCourse.' c
4180
                        ON (c.id = course_user.c_id)
4181
                        WHERE
4182
                            course_user.c_id = ' . $courseId.' AND
4183
                            stats_login.login_course_date IS NULL
4184
                        GROUP BY course_user.user_id';
4185
            } else {
4186
                $sql = 'SELECT session_course_user.user_id
4187
                        FROM '.$tbl_session_course_user.' session_course_user
4188
                        LEFT JOIN ' . $tbl_track_login.' stats_login
4189
                        ON session_course_user.user_id = stats_login.user_id
4190
                        INNER JOIN ' . $tableCourse.' c
4191
                        ON (c.id = session_course_user.c_id)
4192
                        WHERE
4193
                            session_course_user.c_id = ' . $courseId.' AND
4194
                            stats_login.login_course_date IS NULL
4195
                        GROUP BY session_course_user.user_id';
4196
            }
4197
        } else {
4198
            $since = (int) $since;
4199
            if (empty($session_id)) {
4200
                $inner = 'INNER JOIN '.$table_course_rel_user.' course_user
4201
                          ON course_user.user_id = stats_login.user_id AND course_user.c_id = c.id ';
4202
            } else {
4203
                $inner = 'INNER JOIN '.$tbl_session_course_user.' session_course_user
4204
                          ON
4205
                            c.id = session_course_user.c_id AND
4206
                            session_course_user.session_id = '.$session_id.' AND
4207
                            session_course_user.user_id = stats_login.user_id ';
4208
            }
4209
4210
            $sql = 'SELECT 
4211
                    stats_login.user_id, 
4212
                    MAX(login_course_date) max_date
4213
                FROM '.$tbl_track_login.' stats_login
4214
                INNER JOIN '.$tableCourse.' c
4215
                ON (c.id = stats_login.c_id)
4216
                '.$inner.'
4217
                WHERE c.id = '.$courseId.'
4218
                GROUP BY stats_login.user_id
4219
                HAVING DATE_SUB("'.$now.'", INTERVAL '.$since.' DAY) > max_date ';
4220
        }
4221
4222
        $rs = Database::query($sql);
4223
        $users = [];
4224
        while ($user = Database::fetch_array($rs)) {
4225
            $users[] = $user['user_id'];
4226
        }
4227
4228
        return $users;
4229
    }
4230
4231
    /**
4232
     * Get count login per student
4233
     * @param    int    $student_id    Student id
4234
     * @param    int    $courseId
4235
     * @param    int    $session_id    Session id (optional)
4236
     * @return    int        count login
4237
     */
4238
    public static function count_login_per_student($student_id, $courseId, $session_id = 0)
4239
    {
4240
        $student_id  = intval($student_id);
4241
        $courseId = intval($courseId);
4242
        $session_id  = intval($session_id);
4243
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
4244
4245
        $sql = 'SELECT '.$student_id.'
4246
                FROM '.$table.'
4247
                WHERE
4248
                    access_user_id='.$student_id.' AND
4249
                    c_id="'.$courseId.'" AND
4250
                    access_session_id = "'.$session_id.'" ';
4251
4252
        $rs = Database::query($sql);
4253
        $nb_login = Database::num_rows($rs);
4254
4255
        return $nb_login;
4256
    }
4257
4258
    /**
4259
     * Get students followed by a human resources manager
4260
     * @param    int        Drh id
4261
     * @return    array    Student list
4262
     */
4263
    public static function get_student_followed_by_drh($hr_dept_id)
4264
    {
4265
        $hr_dept_id = intval($hr_dept_id);
4266
        $a_students = array();
4267
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
4268
4269
        $sql = 'SELECT DISTINCT user_id FROM '.$tbl_user.' as user
4270
                WHERE hr_dept_id='.$hr_dept_id;
4271
        $rs = Database::query($sql);
4272
4273
        while ($user = Database::fetch_array($rs)) {
4274
            $a_students[$user['user_id']] = $user['user_id'];
4275
        }
4276
4277
        return $a_students;
4278
    }
4279
4280
    /**
4281
     * get count clicks about tools most used by course
4282
     * @param    int      $courseId
4283
     * @param    int        Session id (optional),
4284
     * if param $session_id is null(default) it'll return results
4285
     * including sessions, 0 = session is not filtered
4286
     * @return    array     tools data
4287
     */
4288
    public static function get_tools_most_used_by_course($courseId, $session_id = null)
4289
    {
4290
        $courseId = intval($courseId);
4291
        $data = array();
4292
        $TABLETRACK_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
4293
        $condition_session     = '';
4294
        if (isset($session_id)) {
4295
            $session_id = intval($session_id);
4296
            $condition_session = ' AND access_session_id = '.$session_id;
4297
        }
4298
        $sql = "SELECT
4299
                    access_tool,
4300
                    COUNT(DISTINCT access_user_id),
4301
                    count(access_tool) as count_access_tool
4302
                FROM $TABLETRACK_ACCESS
4303
                WHERE
4304
                    access_tool IS NOT NULL AND
4305
                    access_tool != '' AND
4306
                    c_id = '$courseId'
4307
                    $condition_session
4308
                GROUP BY access_tool
4309
                ORDER BY count_access_tool DESC
4310
                LIMIT 0, 3";
4311
        $rs = Database::query($sql);
4312
        if (Database::num_rows($rs) > 0) {
4313
            while ($row = Database::fetch_array($rs)) {
4314
                $data[] = $row;
4315
            }
4316
        }
4317
        return $data;
4318
    }
4319
4320
    /**
4321
     * get documents most downloaded by course
4322
     * @param      string     Course code
4323
     * @param    int        Session id (optional),
4324
     * if param $session_id is null(default) it'll return results including
4325
     * sessions, 0 = session is not filtered
4326
     * @param    int        Limit (optional, default = 0, 0 = without limit)
4327
     * @return    array     documents downloaded
4328
     */
4329
    public static function get_documents_most_downloaded_by_course(
4330
        $course_code,
4331
        $session_id = 0,
4332
        $limit = 0
4333
    ) {
4334
        $courseId = api_get_course_int_id($course_code);
4335
        $data = array();
4336
4337
        $TABLETRACK_DOWNLOADS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
4338
        $condition_session = '';
4339
        $session_id = intval($session_id);
4340
        if (!empty($session_id)) {
4341
            $condition_session = ' AND down_session_id = '.$session_id;
4342
        }
4343
        $sql = "SELECT
4344
                    down_doc_path,
4345
                    COUNT(DISTINCT down_user_id),
4346
                    COUNT(down_doc_path) as count_down
4347
                FROM $TABLETRACK_DOWNLOADS
4348
                WHERE c_id = $courseId
4349
                    $condition_session
4350
                GROUP BY down_doc_path
4351
                ORDER BY count_down DESC
4352
                LIMIT 0,  $limit";
4353
        $rs = Database::query($sql);
4354
4355
        if (Database::num_rows($rs) > 0) {
4356
            while ($row = Database::fetch_array($rs)) {
4357
                $data[] = $row;
4358
            }
4359
        }
4360
        return $data;
4361
    }
4362
4363
    /**
4364
     * get links most visited by course
4365
     * @param      string     Course code
4366
     * @param    int        Session id (optional),
4367
     * if param $session_id is null(default) it'll
4368
     * return results including sessions, 0 = session is not filtered
4369
     * @return    array     links most visited
4370
     */
4371
    public static function get_links_most_visited_by_course($course_code, $session_id = null)
4372
    {
4373
        $course_code = Database::escape_string($course_code);
4374
        $course_info = api_get_course_info($course_code);
4375
        $course_id = $course_info['real_id'];
4376
        $data = array();
4377
4378
        $TABLETRACK_LINKS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
4379
        $TABLECOURSE_LINKS = Database::get_course_table(TABLE_LINK);
4380
4381
        $condition_session = '';
4382
        if (isset($session_id)) {
4383
            $session_id = intval($session_id);
4384
            $condition_session = ' AND cl.session_id = '.$session_id;
4385
        }
4386
4387
        $sql = "SELECT cl.title, cl.url,count(DISTINCT sl.links_user_id), count(cl.title) as count_visits
4388
                FROM $TABLETRACK_LINKS AS sl, $TABLECOURSE_LINKS AS cl
4389
                WHERE
4390
                    cl.c_id = $course_id AND
4391
                    sl.links_link_id = cl.id AND
4392
                    sl.c_id = $course_id
4393
                    $condition_session
4394
                GROUP BY cl.title, cl.url
4395
                ORDER BY count_visits DESC
4396
                LIMIT 0, 3";
4397
        $rs = Database::query($sql);
4398
        if (Database::num_rows($rs) > 0) {
4399
            while ($row = Database::fetch_array($rs)) {
4400
                $data[] = $row;
4401
            }
4402
        }
4403
        return $data;
4404
    }
4405
4406
    /**
4407
     * Shows the user progress (when clicking in the Progress tab)
4408
     *
4409
     * @param int $user_id
4410
     * @param int $session_id
4411
     * @param string $extra_params
4412
     * @param bool $show_courses
4413
     * @param bool $showAllSessions
4414
     *
4415
     * @return string
4416
     */
4417
    public static function show_user_progress(
4418
        $user_id,
4419
        $session_id = 0,
4420
        $extra_params = '',
4421
        $show_courses = true,
4422
        $showAllSessions = true
4423
    ) {
4424
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
4425
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
4426
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4427
        $tbl_access_rel_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4428
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4429
        $tbl_access_rel_session = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
4430
4431
        $trackingColumns = [
4432
            'course_session' => [
4433
                'course_title' => true,
4434
                'published_exercises' => true,
4435
                'new_exercises' => true,
4436
                'my_average' => true,
4437
                'average_exercise_result' => true,
4438
                'time_spent' => true,
4439
                'lp_progress' => true,
4440
                'score' => true,
4441
                'best_score' => true,
4442
                'last_connection' => true,
4443
                'details' => true,
4444
            ],
4445
        ];
4446
4447
        $trackingColumnsConfig = api_get_configuration_value('tracking_columns');
4448
        if (!empty($trackingColumnsConfig)) {
4449
            $trackingColumns = $trackingColumnsConfig;
4450
        }
4451
4452
        $user_id = intval($user_id);
4453
        $session_id = intval($session_id);
4454
        $urlId = api_get_current_access_url_id();
4455
4456
        if (api_is_multiple_url_enabled()) {
4457
            $sql = "SELECT c.code, title
4458
                    FROM $tbl_course_user cu
4459
                    INNER JOIN $tbl_course c
4460
                    ON (cu.c_id = c.id)
4461
                    INNER JOIN $tbl_access_rel_course a
4462
                    ON (a.c_id = c.id)
4463
                    WHERE
4464
                        cu.user_id = $user_id AND
4465
                        relation_type<> ".COURSE_RELATION_TYPE_RRHH." AND
4466
                        access_url_id = ".$urlId."
4467
                    ORDER BY title";
4468
        } else {
4469
            $sql = "SELECT c.code, title
4470
                    FROM $tbl_course_user u
4471
                    INNER JOIN $tbl_course c ON (c_id = c.id)
4472
                    WHERE
4473
                        u.user_id= $user_id AND
4474
                        relation_type<>".COURSE_RELATION_TYPE_RRHH."
4475
                    ORDER BY title";
4476
        }
4477
4478
        $rs = Database::query($sql);
4479
        $courses = $course_in_session = $temp_course_in_session = array();
4480
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4481
            $courses[$row['code']] = $row['title'];
4482
        }
4483
4484
        $orderBy = " ORDER BY name ";
4485
        $extraInnerJoin = null;
4486
4487
        if (SessionManager::orderCourseIsEnabled() && !empty($session_id)) {
4488
            $orderBy = " ORDER BY s.id, position ";
4489
            $tableSessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
4490
            $extraInnerJoin = " INNER JOIN $tableSessionRelCourse src
4491
                                ON (cu.c_id = src.c_id AND src.session_id = $session_id) ";
4492
        }
4493
4494
        $sessionCondition = '';
4495
        if (!empty($session_id)) {
4496
            $sessionCondition = " AND s.id = $session_id";
4497
        }
4498
4499
        // Get the list of sessions where the user is subscribed as student
4500
        if (api_is_multiple_url_enabled()) {
4501
            $sql = "SELECT DISTINCT c.code, s.id as session_id, name
4502
                    FROM $tbl_session_course_user cu
4503
                    INNER JOIN $tbl_access_rel_session a
4504
                    ON (a.session_id = cu.session_id)
4505
                    INNER JOIN $tbl_session s
4506
                    ON (s.id = a.session_id)
4507
                    INNER JOIN $tbl_course c
4508
                    ON (c.id = cu.c_id)
4509
                    $extraInnerJoin
4510
                    WHERE
4511
                        cu.user_id = $user_id AND
4512
                        access_url_id = ".$urlId."
4513
                        $sessionCondition
4514
                    $orderBy ";
4515
        } else {
4516
            $sql = "SELECT DISTINCT c.code, s.id as session_id, name
4517
                    FROM $tbl_session_course_user cu
4518
                    INNER JOIN $tbl_session s
4519
                    ON (s.id = cu.session_id)
4520
                    INNER JOIN $tbl_course c
4521
                    ON (c.id = cu.c_id)
4522
                    $extraInnerJoin
4523
                    WHERE
4524
                        cu.user_id = $user_id
4525
                        $sessionCondition
4526
                    $orderBy ";
4527
        }
4528
4529
        $rs = Database::query($sql);
4530
        $simple_session_array = array();
4531
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4532
            $course_info = api_get_course_info($row['code']);
4533
            $temp_course_in_session[$row['session_id']]['course_list'][$course_info['real_id']] = $course_info;
4534
            $temp_course_in_session[$row['session_id']]['name'] = $row['name'];
4535
            $simple_session_array[$row['session_id']] = $row['name'];
4536
        }
4537
4538
        foreach ($simple_session_array as $my_session_id => $session_name) {
4539
            $course_list = $temp_course_in_session[$my_session_id]['course_list'];
4540
            $my_course_data = array();
4541
            foreach ($course_list as $courseId => $course_data) {
4542
                $my_course_data[$courseId] = $course_data['title'];
4543
            }
4544
4545
            if (empty($session_id)) {
4546
                $my_course_data = utf8_sort($my_course_data);
4547
            }
4548
4549
            $final_course_data = array();
4550
            foreach ($my_course_data as $course_id => $value) {
4551
                if (isset($course_list[$course_id])) {
4552
                    $final_course_data[$course_id] = $course_list[$course_id];
4553
                }
4554
            }
4555
            $course_in_session[$my_session_id]['course_list'] = $final_course_data;
4556
            $course_in_session[$my_session_id]['name'] = $session_name;
4557
        }
4558
4559
        $html = '';
4560
        // Course list
4561
        if ($show_courses) {
4562
            if (!empty($courses)) {
4563
                $html .= Display::page_subheader(
4564
                    Display::return_icon(
4565
                        'course.png',
4566
                        get_lang('MyCourses'),
4567
                        array(),
4568
                        ICON_SIZE_SMALL
4569
                    ).' '.get_lang('MyCourses')
4570
                );
4571
4572
                $columns = [
4573
                    'course_title' => get_lang('Course'),
4574
                    'time_spent' => get_lang('TimeSpentInTheCourse'),
4575
                    'progress' => get_lang('Progress'),
4576
                    'best_score_in_lp' => get_lang('BestScoreInLearningPath'),
4577
                    'best_score_not_in_lp' => get_lang('BestScoreNotInLearningPath'),
4578
                    'latest_login' => get_lang('LastConnexion'),
4579
                    'details' => get_lang('Details')
4580
                ];
4581
                $availableColumns = [];
4582
                if (isset($trackingColumns['my_progress_courses'])) {
4583
                    $availableColumns = $trackingColumns['my_progress_courses'];
4584
                }
4585
                $html .= '<div class="table-responsive">';
4586
                $html .= '<table class="table table-striped table-hover">';
4587
                $html .= '<thead><tr>';
4588
                foreach ($columns as $columnKey => $name) {
4589
                    if (!empty($availableColumns)) {
4590
                        if (isset($availableColumns[$columnKey]) && $availableColumns[$columnKey] == false) {
4591
                            continue;
4592
                        }
4593
                    }
4594
                    $html .= Display::tag('th', $name);
4595
                }
4596
                $html .= '</tr></thead><tbody>';
4597
4598
                foreach ($courses as $course_code => $course_title) {
4599
                    $courseInfo = api_get_course_info($course_code);
4600
                    $courseId = $courseInfo['real_id'];
4601
4602
                    $total_time_login = self::get_time_spent_on_the_course(
4603
                        $user_id,
4604
                        $courseId
4605
                    );
4606
                    $time = api_time_to_hms($total_time_login);
4607
                    $progress = self::get_avg_student_progress(
4608
                        $user_id,
4609
                        $course_code
4610
                    );
4611
                    $bestScore = self::get_avg_student_score(
4612
                        $user_id,
4613
                        $course_code,
4614
                        array(),
4615
                        null,
4616
                        false,
4617
                        false,
4618
                        true
4619
                    );
4620
4621
                    $exerciseList = ExerciseLib::get_all_exercises(
4622
                        $courseInfo,
4623
                        0,
4624
                        false,
4625
                        null,
4626
                        false,
4627
                        1
4628
                    );
4629
4630
                    $bestScoreAverageNotInLP = 0;
4631
                    if (!empty($exerciseList)) {
4632
                        foreach ($exerciseList as $exerciseData) {
4633
                            $results = Event::get_best_exercise_results_by_user(
4634
                                $exerciseData['id'],
4635
                                $courseInfo['real_id'],
4636
                                0,
4637
                                $user_id
4638
                            );
4639
                            $best = 0;
4640
                            if (!empty($results)) {
4641
                                foreach ($results as $result) {
4642
                                    if (!empty($result['exe_weighting'])) {
4643
                                        $score = $result['exe_result'] / $result['exe_weighting'];
4644
                                        if ($score > $best) {
4645
                                            $best = $score;
4646
                                        }
4647
                                    }
4648
                                }
4649
                            }
4650
                            $bestScoreAverageNotInLP += $best;
4651
                        }
4652
                        $bestScoreAverageNotInLP = round($bestScoreAverageNotInLP / count($exerciseList) * 100, 2);
4653
                    }
4654
4655
                    $last_connection = self::get_last_connection_date_on_the_course(
4656
                        $user_id,
4657
                        $courseInfo
4658
                    );
4659
4660
                    if (is_null($progress) || empty($progress)) {
4661
                        $progress = '0%';
4662
                    } else {
4663
                        $progress = $progress.'%';
4664
                    }
4665
4666
                    if (isset($_GET['course']) &&
4667
                        $course_code == $_GET['course'] &&
4668
                        empty($_GET['session_id'])
4669
                    ) {
4670
                        $html .= '<tr class="row_odd" style="background-color:#FBF09D">';
4671
                    } else {
4672
                        $html .= '<tr class="row_even">';
4673
                    }
4674
                    $url = api_get_course_url($course_code, $session_id);
4675
                    $course_url = Display::url($course_title, $url, array('target' => SESSION_LINK_TARGET));
4676
                    $bestScoreResult = '';
4677
                    if (empty($bestScore)) {
4678
                        $bestScoreResult = '-';
4679
                    } else {
4680
                        $bestScoreResult = $bestScore.'%';
4681
                    }
4682
                    $bestScoreNotInLP = '';
4683
                    if (empty($bestScoreAverageNotInLP)) {
4684
                        $bestScoreNotInLP = '-';
4685
                    } else {
4686
                        $bestScoreNotInLP = $bestScoreAverageNotInLP.'%';
4687
                    }
4688
4689
                    $detailsLink = '';
4690
                    if (isset($_GET['course']) &&
4691
                        $course_code == $_GET['course'] &&
4692
                        empty($_GET['session_id'])
4693
                    ) {
4694
                        $detailsLink .= '<a href="#course_session_header">';
4695
                        $detailsLink .= Display::return_icon('2rightarrow_na.png', get_lang('Details'));
4696
                        $detailsLink .= '</a>';
4697
                    } else {
4698
                        $detailsLink .= '<a href="'.api_get_self().'?course='.$course_code.$extra_params.'#course_session_header">';
4699
                        $detailsLink .= Display::return_icon('2rightarrow.png', get_lang('Details'));
4700
                        $detailsLink .= '</a>';
4701
                    }
4702
4703
                    $result = [
4704
                        'course_title' => $course_url,
4705
                        'time_spent' => $time,
4706
                        'progress' => $progress,
4707
                        'best_score_in_lp' => $bestScoreResult,
4708
                        'best_score_not_in_lp' => $bestScoreNotInLP,
4709
                        'latest_login' => $last_connection,
4710
                        'details' => $detailsLink
4711
                    ];
4712
4713
                    foreach ($result as $columnKey => $data) {
4714
                        if (!empty($availableColumns)) {
4715
                            if (isset($availableColumns[$columnKey]) && $availableColumns[$columnKey] == false) {
4716
                                continue;
4717
                            }
4718
                        }
4719
                        $html .= '<td>'.$data.'</td>';
4720
                    }
4721
4722
                    $html .= '</tr>';
4723
                }
4724
                $html .= '</tbody></table>';
4725
                $html .= '</div>';
4726
            }
4727
        }
4728
4729
        // Session list
4730
        if (!empty($course_in_session)) {
4731
            $main_session_graph = '';
4732
            // Load graphics only when calling to an specific session
4733
            $all_exercise_graph_name_list = array();
4734
            $my_results = array();
4735
            $all_exercise_graph_list = array();
4736
            $all_exercise_start_time = array();
4737
            foreach ($course_in_session as $my_session_id => $session_data) {
4738
                $course_list = $session_data['course_list'];
4739
                $user_count = count(SessionManager::get_users_by_session($my_session_id));
0 ignored issues
show
Bug introduced by
It seems like SessionManager::get_user...session($my_session_id) can also be of type integer; however, parameter $var of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

4739
                $user_count = count(/** @scrutinizer ignore-type */ SessionManager::get_users_by_session($my_session_id));
Loading history...
4740
                $exercise_graph_name_list = array();
4741
                $exercise_graph_list = array();
4742
4743
                foreach ($course_list as $course_data) {
4744
                    $exercise_list = ExerciseLib::get_all_exercises(
4745
                        $course_data,
4746
                        $my_session_id,
4747
                        false,
4748
                        null,
4749
                        false,
4750
                        1
4751
                    );
4752
4753
                    foreach ($exercise_list as $exercise_data) {
4754
                        $exercise_obj = new Exercise($course_data['real_id']);
4755
                        $exercise_obj->read($exercise_data['id']);
4756
                        // Exercise is not necessary to be visible to show results check the result_disable configuration instead
4757
                        //$visible_return = $exercise_obj->is_visible();
4758
                        if ($exercise_data['results_disabled'] == 0 || $exercise_data['results_disabled'] == 2) {
4759
                            $best_average = intval(
4760
                                ExerciseLib::get_best_average_score_by_exercise(
4761
                                    $exercise_data['id'],
4762
                                    $course_data['real_id'],
4763
                                    $my_session_id,
4764
                                    $user_count
4765
                                )
4766
                            );
4767
4768
                            $exercise_graph_list[] = $best_average;
4769
                            $all_exercise_graph_list[] = $best_average;
4770
4771
                            $user_result_data = ExerciseLib::get_best_attempt_by_user(
4772
                                api_get_user_id(),
4773
                                $exercise_data['id'],
4774
                                $course_data['real_id'],
4775
                                $my_session_id
4776
                            );
4777
4778
                            $score = 0;
4779
                            if (!empty($user_result_data['exe_weighting']) && intval($user_result_data['exe_weighting']) != 0) {
4780
                                $score = intval($user_result_data['exe_result'] / $user_result_data['exe_weighting'] * 100);
4781
                            }
4782
                            $time = api_strtotime($exercise_data['start_time']) ? api_strtotime($exercise_data['start_time'], 'UTC') : 0;
4783
                            $all_exercise_start_time[] = $time;
4784
                            $my_results[] = $score;
4785
                            if (count($exercise_list) <= 10) {
4786
                                $title = cut($course_data['title'], 30)." \n ".cut($exercise_data['title'], 30);
4787
                                $exercise_graph_name_list[] = $title;
4788
                                $all_exercise_graph_name_list[] = $title;
4789
                            } else {
4790
                                // if there are more than 10 results, space becomes difficult to find,
4791
                                // so only show the title of the exercise, not the tool
4792
                                $title = cut($exercise_data['title'], 30);
4793
                                $exercise_graph_name_list[] = $title;
4794
                                $all_exercise_graph_name_list[] = $title;
4795
                            }
4796
                        }
4797
                    }
4798
                }
4799
            }
4800
4801
            // Complete graph
4802
            if (!empty($my_results) && !empty($all_exercise_graph_list)) {
4803
                asort($all_exercise_start_time);
4804
4805
                //Fix exams order
4806
                $final_all_exercise_graph_name_list = array();
4807
                $my_results_final = array();
4808
                $final_all_exercise_graph_list = array();
4809
4810
                foreach ($all_exercise_start_time as $key => $time) {
4811
                    $label_time = '';
4812
                    if (!empty($time)) {
4813
                        $label_time = date('d-m-y', $time);
4814
                    }
4815
                    $final_all_exercise_graph_name_list[] = $all_exercise_graph_name_list[$key].' '.$label_time;
4816
                    $my_results_final[] = $my_results[$key];
4817
                    $final_all_exercise_graph_list[] = $all_exercise_graph_list[$key];
4818
                }
4819
                $main_session_graph = self::generate_session_exercise_graph(
4820
                    $final_all_exercise_graph_name_list,
4821
                    $my_results_final,
4822
                    $final_all_exercise_graph_list
4823
                );
4824
            }
4825
4826
            $sessionIcon = Display::return_icon(
4827
                'session.png',
4828
                get_lang('Sessions'),
4829
                array(),
4830
                ICON_SIZE_SMALL
4831
            );
4832
4833
            $anchor = Display::url('', '', ['name' => 'course_session_header']);
4834
            $html .= $anchor.Display::page_subheader(
4835
                $sessionIcon.' '.get_lang('Sessions')
4836
            );
4837
4838
            $html .= '<div class="table-responsive">';
4839
            $html .= '<table class="table table-striped table-hover">';
4840
            $html .= '<thead>';
4841
            $html .= '<tr>
4842
                  '.Display::tag('th', get_lang('Session'), array('width'=>'300px')).'
4843
                  '.Display::tag('th', get_lang('PublishedExercises'), array('width'=>'300px')).'
4844
                  '.Display::tag('th', get_lang('NewExercises')).'
4845
                  '.Display::tag('th', get_lang('AverageExerciseResult')).'
4846
                  '.Display::tag('th', get_lang('Details')).'
4847
                  </tr>';
4848
            $html .= '</thead>';
4849
            $html .= '<tbody>';
4850
4851
            foreach ($course_in_session as $my_session_id => $session_data) {
4852
                $course_list = $session_data['course_list'];
4853
                $session_name = $session_data['name'];
4854
                if ($showAllSessions == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
4855
                    if (isset($session_id) && !empty($session_id)) {
4856
                        if ($session_id != $my_session_id) {
4857
                            continue;
4858
                        }
4859
                    }
4860
                }
4861
4862
                $all_exercises = 0;
4863
                $all_unanswered_exercises_by_user = 0;
4864
                $all_average = 0;
4865
                $stats_array = array();
4866
4867
                foreach ($course_list as $course_data) {
4868
                    // All exercises in the course @todo change for a real count
4869
                    $exercises = ExerciseLib::get_all_exercises($course_data, $my_session_id);
4870
                    $count_exercises = 0;
4871
                    if (is_array($exercises) && !empty($exercises)) {
4872
                        $count_exercises = count($exercises);
4873
                    }
4874
4875
                    // Count of user results
4876
                    $done_exercises = null;
4877
                    $courseInfo = api_get_course_info($course_data['code']);
4878
4879
                    $answered_exercises = 0;
4880
                    if (!empty($exercises)) {
4881
                        foreach ($exercises as $exercise_item) {
4882
                            $attempts = Event::count_exercise_attempts_by_user(
4883
                                api_get_user_id(),
4884
                                $exercise_item['id'],
4885
                                $courseInfo['real_id'],
4886
                                $my_session_id
4887
                            );
4888
                            if ($attempts > 1) {
4889
                                $answered_exercises++;
4890
                            }
4891
                        }
4892
                    }
4893
4894
                    // Average
4895
                    $average = ExerciseLib::get_average_score_by_course(
4896
                        $courseInfo['real_id'],
4897
                        $my_session_id
4898
                    );
4899
                    $all_exercises += $count_exercises;
4900
                    $all_unanswered_exercises_by_user += $count_exercises - $answered_exercises;
4901
                    $all_average += $average;
4902
                }
4903
4904
                if (!empty($course_list)) {
4905
                    $all_average = $all_average / count($course_list);
4906
                }
4907
4908
                if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) {
4909
                    $html .= '<tr style="background-color:#FBF09D">';
4910
                } else {
4911
                    $html .= '<tr>';
4912
                }
4913
                $url = api_get_path(WEB_CODE_PATH)."session/index.php?session_id={$my_session_id}";
4914
4915
                $html .= Display::tag('td', Display::url($session_name, $url, array('target'=>SESSION_LINK_TARGET)));
4916
                $html .= Display::tag('td', $all_exercises);
4917
                $html .= Display::tag('td', $all_unanswered_exercises_by_user);
4918
                $html .= Display::tag('td', ExerciseLib::convert_to_percentage($all_average));
4919
4920
                if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) {
4921
                    $icon = Display::url(
4922
                        Display::return_icon(
4923
                            '2rightarrow_na.png',
4924
                            get_lang('Details')
4925
                        ),
4926
                        api_get_self().'?session_id='.$my_session_id.'#course_session_list'
4927
                    );
4928
                } else {
4929
                    $icon = Display::url(
4930
                        Display::return_icon(
4931
                            '2rightarrow.png',
4932
                            get_lang('Details')
4933
                        ),
4934
                        api_get_self().'?session_id='.$my_session_id.'#course_session_list'
4935
                    );
4936
                }
4937
                $html .= Display::tag('td', $icon);
4938
                $html .= '</tr>';
4939
            }
4940
            $html .= '</tbody>';
4941
            $html .= '</table></div><br />';
4942
            $html .= Display::div(
4943
                $main_session_graph,
4944
                array(
4945
                    'id' => 'session_graph',
4946
                    'class' => 'chart-session',
4947
                    'style' => 'position:relative; text-align: center;',
4948
                )
4949
            );
4950
4951
            // Checking selected session.
4952
            if (isset($_GET['session_id'])) {
4953
                $session_id_from_get = intval($_GET['session_id']);
4954
                $session_data = $course_in_session[$session_id_from_get];
4955
                $course_list = $session_data['course_list'];
4956
4957
                $html .= '<a name= "course_session_list"></a>';
4958
                $html .= Display::tag('h3', $session_data['name'].' - '.get_lang('CourseList'));
4959
4960
                $html .= '<div class="table-responsive">';
4961
                $html .= '<table class="table table-hover table-striped">';
4962
4963
                $columnHeaders = [
4964
                    'course_title' => [
4965
                        get_lang('Course'),
4966
                        array('width'=>'300px')
4967
                    ],
4968
                    'published_exercises' => [
4969
                        get_lang('PublishedExercises')
4970
                    ],
4971
                    'new_exercises' => [
4972
                        get_lang('NewExercises'),
4973
                    ],
4974
                    'my_average' => [
4975
                        get_lang('MyAverage'),
4976
                    ],
4977
                    'average_exercise_result'  => [
4978
                        get_lang('AverageExerciseResult'),
4979
                    ],
4980
                    'time_spent'  => [
4981
                        get_lang('TimeSpentInTheCourse'),
4982
                    ],
4983
                    'lp_progress'  => [
4984
                        get_lang('LPProgress'),
4985
                    ],
4986
                    'score'  => [
4987
                        get_lang('Score').
4988
                        Display::return_icon(
4989
                            'info3.gif',
4990
                            get_lang('ScormAndLPTestTotalAverage'),
4991
                            array('align' => 'absmiddle', 'hspace' => '3px')
4992
                        ),
4993
                    ],
4994
                    'best_score'  => [
4995
                        get_lang('BestScore'),
4996
                    ],
4997
                    'last_connection'  => [
4998
                        get_lang('LastConnexion'),
4999
                    ],
5000
                    'details'  => [
5001
                        get_lang('Details'),
5002
                    ],
5003
                ];
5004
5005
                $html .= '<thead><tr>';
5006
                foreach ($columnHeaders as $key => $columnSetting) {
5007
                    if (isset($trackingColumns['course_session']) &&
5008
                        in_array($key, $trackingColumns['course_session']) &&
5009
                        $trackingColumns['course_session'][$key]
5010
                    ) {
5011
                        $settings = isset($columnSetting[1]) ? $columnSetting[1] : [];
5012
                        $html .= Display::tag(
5013
                             'th',
5014
                             $columnSetting[0],
5015
                             $settings
5016
                         );
5017
                    }
5018
                }
5019
5020
                $html .= '</tr>
5021
                    </thead>
5022
                    <tbody>';
5023
5024
                foreach ($course_list as $course_data) {
5025
                    $course_code = $course_data['code'];
5026
                    $course_title = $course_data['title'];
5027
                    $courseId = $course_data['real_id'];
5028
5029
                    // All exercises in the course @todo change for a real count
5030
                    $exercises = ExerciseLib::get_all_exercises(
5031
                        $course_data,
5032
                        $session_id_from_get
5033
                    );
5034
                    $count_exercises = 0;
5035
                    if (!empty($exercises)) {
5036
                        $count_exercises = count($exercises);
5037
                    }
5038
                    $answered_exercises = 0;
5039
                    foreach ($exercises as $exercise_item) {
5040
                        $attempts = Event::count_exercise_attempts_by_user(
5041
                            api_get_user_id(),
5042
                            $exercise_item['id'],
5043
                            $courseId,
5044
                            $session_id_from_get
5045
                        );
5046
                        if ($attempts > 1) {
5047
                            $answered_exercises++;
5048
                        }
5049
                    }
5050
5051
                    $unanswered_exercises = $count_exercises - $answered_exercises;
5052
5053
                    // Average
5054
                    $average = ExerciseLib::get_average_score_by_course(
5055
                        $courseId,
5056
                        $session_id_from_get
5057
                    );
5058
                    $my_average = ExerciseLib::get_average_score_by_course_by_user(
5059
                        api_get_user_id(),
5060
                        $courseId,
5061
                        $session_id_from_get
5062
                    );
5063
5064
                    $bestScore = self::get_avg_student_score(
5065
                        $user_id,
5066
                        $course_code,
5067
                        array(),
5068
                        $session_id_from_get,
5069
                        false,
5070
                        false,
5071
                        true
5072
                    );
5073
5074
                    $stats_array[$course_code] = array(
5075
                        'exercises' => $count_exercises,
5076
                        'unanswered_exercises_by_user' => $unanswered_exercises,
5077
                        'done_exercises' => $done_exercises,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $done_exercises does not seem to be defined for all execution paths leading up to this point.
Loading history...
5078
                        'average' => $average,
5079
                        'my_average' => $my_average,
5080
                        'best_score' => $bestScore
5081
                    );
5082
5083
                    $last_connection = self::get_last_connection_date_on_the_course(
5084
                        $user_id,
5085
                        $course_data,
5086
                        $session_id_from_get
5087
                    );
5088
5089
                    $progress = self::get_avg_student_progress(
5090
                        $user_id,
5091
                        $course_code,
5092
                        array(),
5093
                        $session_id_from_get
5094
                    );
5095
5096
                    $total_time_login = self::get_time_spent_on_the_course(
5097
                        $user_id,
5098
                        $courseId,
5099
                        $session_id_from_get
5100
                    );
5101
                    $time = api_time_to_hms($total_time_login);
5102
5103
                    $percentage_score = self::get_avg_student_score(
5104
                        $user_id,
5105
                        $course_code,
5106
                        array(),
5107
                        $session_id_from_get
5108
                    );
5109
                    $courseCodeFromGet = isset($_GET['course']) ? $_GET['course'] : null;
5110
5111
                    if ($course_code == $courseCodeFromGet && $_GET['session_id'] == $session_id_from_get) {
5112
                        $html .= '<tr class="row_odd" style="background-color:#FBF09D" >';
5113
                    } else {
5114
                        $html .= '<tr class="row_even">';
5115
                    }
5116
5117
                    $url = api_get_course_url($course_code, $session_id_from_get);
5118
                    $course_url = Display::url(
5119
                        $course_title,
5120
                        $url,
5121
                        array('target' => SESSION_LINK_TARGET)
5122
                    );
5123
5124
                    if (is_numeric($progress)) {
5125
                        $progress = $progress.'%';
5126
                    } else {
5127
                        $progress = '0%';
5128
                    }
5129
                    if (is_numeric($percentage_score)) {
5130
                        $percentage_score = $percentage_score.'%';
5131
                    } else {
5132
                        $percentage_score = '0%';
5133
                    }
5134
5135
                    if (is_numeric($stats_array[$course_code]['best_score'])) {
5136
                        $bestScore = $stats_array[$course_code]['best_score'].'%';
5137
                    } else {
5138
                        $bestScore = '-';
5139
                    }
5140
5141
                    if (empty($last_connection) || is_bool($last_connection)) {
5142
                        $last_connection = '';
5143
                    }
5144
5145
                    if ($course_code == $courseCodeFromGet &&
5146
                        $_GET['session_id'] == $session_id_from_get
5147
                    ) {
5148
                        $details = Display::url(
5149
                            Display::return_icon('2rightarrow_na.png', get_lang('Details')),
5150
                        '#course_session_data'
5151
                        );
5152
                    } else {
5153
                        $url = api_get_self().'?course='.$course_code.'&session_id='.$session_id_from_get.$extra_params.'#course_session_data';
5154
                        $details = Display::url(
5155
                            Display::return_icon(
5156
                                '2rightarrow.png',
5157
                                get_lang('Details')
5158
                            ),
5159
                            $url
5160
                        );
5161
                    }
5162
                    $details .= '</a>';
5163
5164
                    $data = [
5165
                        'course_title' => $course_url,
5166
                        'published_exercises' => $stats_array[$course_code]['exercises'], // exercise available
5167
                        'new_exercises' => $stats_array[$course_code]['unanswered_exercises_by_user'],
5168
                        'my_average' => ExerciseLib::convert_to_percentage($stats_array[$course_code]['my_average']),
5169
                        'average_exercise_result' => $stats_array[$course_code]['average'] == 0 ? '-' : '('.ExerciseLib::convert_to_percentage($stats_array[$course_code]['average']).')',
5170
                        'time_spent' => $time,
5171
                        'lp_progress' => $progress,
5172
                        'score' => $percentage_score,
5173
                        'best_score' => $bestScore,
5174
                        'last_connection' => $last_connection,
5175
                        'details' => $details,
5176
                    ];
5177
5178
                    foreach ($data as $key => $value) {
5179
                        if (in_array($key, $trackingColumns['course_session'])
5180
                            && $trackingColumns['course_session'][$key]
5181
                        ) {
5182
                            $html .= Display::tag('td', $value);
5183
                        }
5184
                    }
5185
                    $html .= '</tr>';
5186
                }
5187
                $html .= '</tbody></table></div>';
5188
            }
5189
        }
5190
5191
        return $html;
5192
    }
5193
5194
    /**
5195
     * Shows the user detail progress (when clicking in the details link)
5196
     * @param   int     $user_id
5197
     * @param   string  $course_code
5198
     * @param   int     $session_id
5199
     * @return  string  html code
5200
     */
5201
    public static function show_course_detail($user_id, $course_code, $session_id)
5202
    {
5203
        $html = '';
5204
        if (isset($course_code)) {
5205
            $user_id = intval($user_id);
5206
            $session_id = intval($session_id);
5207
            $course = Database::escape_string($course_code);
5208
            $course_info = api_get_course_info($course);
5209
            if (empty($course_info)) {
5210
                return '';
5211
            }
5212
5213
            $html .= '<a name="course_session_data"></a>';
5214
            $html .= Display::page_subheader($course_info['title']);
5215
            $html .= '<div class="table-responsive">';
5216
            $html .= '<table class="table table-striped table-hover">';
5217
5218
            //Course details
5219
            $html .= '
5220
                <thead>
5221
                <tr>
5222
                <th>'.get_lang('Exercises').'</th>
5223
                <th>'.get_lang('Attempts').'</th>
5224
                <th>'.get_lang('BestAttempt').'</th>
5225
                <th>'.get_lang('Ranking').'</th>
5226
                <th>'.get_lang('BestResultInCourse').'</th>
5227
                <th>'.get_lang('Statistics').' '.Display::return_icon('info3.gif', get_lang('OnlyBestResultsPerStudent'), array('align' => 'absmiddle', 'hspace' => '3px')).'</th>
5228
                </tr>
5229
                </thead>
5230
                <tbody>';
5231
5232
            if (empty($session_id)) {
5233
                $user_list = CourseManager::get_user_list_from_course_code(
5234
                    $course,
5235
                    $session_id,
5236
                    null,
5237
                    null,
5238
                    STUDENT
5239
                );
5240
            } else {
5241
                $user_list = CourseManager::get_user_list_from_course_code(
5242
                    $course,
5243
                    $session_id,
5244
                    null,
5245
                    null,
5246
                    0
5247
                );
5248
            }
5249
5250
            // Show exercise results of invisible exercises? see BT#4091
5251
            $exercise_list = ExerciseLib::get_all_exercises(
5252
                $course_info,
5253
                $session_id,
5254
                false,
5255
                null,
5256
                false,
5257
                2
5258
            );
5259
5260
            $to_graph_exercise_result = array();
5261
            if (!empty($exercise_list)) {
5262
                $score = $weighting = $exe_id = 0;
5263
                foreach ($exercise_list as $exercices) {
5264
                    $exercise_obj = new Exercise($course_info['real_id']);
5265
                    $exercise_obj->read($exercices['id']);
5266
                    $visible_return = $exercise_obj->is_visible();
5267
                    $score = $weighting = $attempts = 0;
5268
5269
                    // Getting count of attempts by user
5270
                    $attempts = Event::count_exercise_attempts_by_user(
5271
                        api_get_user_id(),
5272
                        $exercices['id'],
5273
                        $course_info['real_id'],
5274
                        $session_id
5275
                    );
5276
5277
                    $html .= '<tr class="row_even">';
5278
                    $url = api_get_path(WEB_CODE_PATH)."exercise/overview.php?cidReq={$course_info['code']}&id_session=$session_id&exerciseId={$exercices['id']}";
5279
5280
                    if ($visible_return['value'] == true) {
5281
                        $exercices['title'] = Display::url(
5282
                            $exercices['title'],
5283
                            $url,
5284
                            array('target' => SESSION_LINK_TARGET)
5285
                        );
5286
                    } elseif ($exercices['active'] == -1) {
5287
                        $exercices['title'] = sprintf(get_lang('XParenthesisDeleted'), $exercices['title']);
5288
                    }
5289
5290
                    $html .= Display::tag('td', $exercices['title']);
5291
5292
                    // Exercise configuration show results or show only score
5293
                    if ($exercices['results_disabled'] == 0 || $exercices['results_disabled'] == 2) {
5294
                        //For graphics
5295
                        $best_exercise_stats = Event::get_best_exercise_results_by_user(
5296
                            $exercices['id'],
5297
                            $course_info['real_id'],
5298
                            $session_id
5299
                        );
5300
5301
                        $to_graph_exercise_result[$exercices['id']] = array(
5302
                            'title' => $exercices['title'],
5303
                            'data' => $best_exercise_stats
5304
                        );
5305
5306
                        $latest_attempt_url = '';
5307
                        $best_score = $position = $percentage_score_result = '-';
5308
                        $graph = $normal_graph = null;
5309
5310
                        // Getting best results
5311
                        $best_score_data = ExerciseLib::get_best_attempt_in_course(
5312
                            $exercices['id'],
5313
                            $course_info['real_id'],
5314
                            $session_id
5315
                        );
5316
5317
                        $best_score = '';
5318
                        if (!empty($best_score_data)) {
5319
                            $best_score = ExerciseLib::show_score(
5320
                                $best_score_data['exe_result'],
5321
                                $best_score_data['exe_weighting']
5322
                            );
5323
                        }
5324
5325
                        if ($attempts > 0) {
5326
                            $exercise_stat = ExerciseLib::get_best_attempt_by_user(
5327
                                api_get_user_id(),
5328
                                $exercices['id'],
5329
                                $course_info['real_id'],
5330
                                $session_id
5331
                            );
5332
                            if (!empty($exercise_stat)) {
5333
                                // Always getting the BEST attempt
5334
                                $score = $exercise_stat['exe_result'];
5335
                                $weighting = $exercise_stat['exe_weighting'];
5336
                                $exe_id = $exercise_stat['exe_id'];
5337
5338
                                $latest_attempt_url .= api_get_path(WEB_CODE_PATH).'exercise/result.php?id='.$exe_id.'&cidReq='.$course_info['code'].'&show_headers=1&id_session='.$session_id;
5339
                                $percentage_score_result = Display::url(
5340
                                    ExerciseLib::show_score($score, $weighting),
5341
                                    $latest_attempt_url
5342
                                );
5343
                                $my_score = 0;
5344
                                if (!empty($weighting) && intval($weighting) != 0) {
5345
                                    $my_score = $score / $weighting;
5346
                                }
5347
                                //@todo this function slows the page
5348
                                if (is_int($user_list)) {
5349
                                    $user_list = array($user_list);
5350
                                }
5351
                                $position = ExerciseLib::get_exercise_result_ranking(
5352
                                    $my_score,
5353
                                    $exe_id,
5354
                                    $exercices['id'],
5355
                                    $course_info['code'],
5356
                                    $session_id,
5357
                                    $user_list
5358
                                );
5359
5360
                                $graph = self::generate_exercise_result_thumbnail_graph(
5361
                                    $to_graph_exercise_result[$exercices['id']]
5362
                                );
5363
                                $normal_graph = self::generate_exercise_result_graph(
5364
                                    $to_graph_exercise_result[$exercices['id']]
5365
                                );
5366
                            }
5367
                        }
5368
                        $html .= Display::div(
5369
                            $normal_graph,
5370
                            array(
5371
                                'id' => 'main_graph_'.$exercices['id'],
5372
                                'class' => 'dialog',
5373
                                'style' => 'display:none'
5374
                            )
5375
                        );
5376
5377
                        if (empty($graph)) {
5378
                            $graph = '-';
5379
                        } else {
5380
                            $graph = Display::url(
5381
                                '<img src="'.$graph.'" >',
5382
                                $normal_graph,
5383
                                array(
5384
                                    'id' => $exercices['id'],
5385
                                    'class' => 'expand-image',
5386
                                )
5387
                            );
5388
                        }
5389
5390
                        $html .= Display::tag('td', $attempts);
5391
                        $html .= Display::tag('td', $percentage_score_result);
5392
                        $html .= Display::tag('td', $position);
5393
                        $html .= Display::tag('td', $best_score);
5394
                        $html .= Display::tag('td', $graph);
5395
                        //$html .= Display::tag('td', $latest_attempt_url,       array('align'=>'center', 'width'=>'25'));
5396
5397
                    } else {
5398
                        // Exercise configuration NO results
5399
                        $html .= Display::tag('td', $attempts);
5400
                        $html .= Display::tag('td', '-');
5401
                        $html .= Display::tag('td', '-');
5402
                        $html .= Display::tag('td', '-');
5403
                        $html .= Display::tag('td', '-');
5404
                    }
5405
                    $html .= '</tr>';
5406
                }
5407
            } else {
5408
                $html .= '<tr><td colspan="5">'.get_lang('NoEx').'</td></tr>';
5409
            }
5410
            $html .= '</tbody></table></div>';
5411
5412
            $columnHeaders = [
5413
                'lp' => get_lang('LearningPath'),
5414
                'time' => get_lang('LatencyTimeSpent'),
5415
                'progress' => get_lang('Progress'),
5416
                'score' => get_lang('Score'),
5417
                'best_score' => get_lang('BestScore'),
5418
                'last_connection' => get_lang('LastConnexion'),
5419
            ];
5420
5421
            $headers = '';
5422
            $trackingColumns = api_get_configuration_value('tracking_columns');
5423
            if (isset($trackingColumns['my_progress_lp'])) {
5424
                foreach ($columnHeaders as $key => $value) {
5425
                    if (!isset($trackingColumns['my_progress_lp'][$key]) ||
5426
                        $trackingColumns['my_progress_lp'][$key] == false
5427
                    ) {
5428
                        unset($columnHeaders[$key]);
5429
                    }
5430
                }
5431
            }
5432
5433
            $columnHeadersKeys = array_keys($columnHeaders);
5434
            foreach ($columnHeaders as $key => $columnName) {
5435
                $headers .= Display::tag(
5436
                    'th',
5437
                    $columnName
5438
                );
5439
            }
5440
5441
            // LP table results
5442
            $html .= '<div class="table-responsive">';
5443
            $html .= '<table class="table table-striped table-hover">';
5444
            $html .= '<thead><tr>';
5445
            $html .= $headers;
5446
            $html .= '</tr></thead><tbody>';
5447
5448
            $list = new LearnpathList(
5449
                api_get_user_id(),
5450
                $course_info['code'],
5451
                $session_id,
5452
                'lp.publicatedOn ASC',
5453
                true,
5454
                null,
5455
                true
5456
            );
5457
5458
            $lp_list = $list->get_flat_list();
5459
5460
            if (!empty($lp_list) > 0) {
5461
                foreach ($lp_list as $lp_id => $learnpath) {
5462
                    $progress = self::get_avg_student_progress(
5463
                        $user_id,
5464
                        $course,
5465
                        array($lp_id),
5466
                        $session_id
5467
                    );
5468
                    $last_connection_in_lp = self::get_last_connection_time_in_lp(
5469
                        $user_id,
5470
                        $course,
5471
                        $lp_id,
5472
                        $session_id
5473
                    );
5474
5475
                    $time_spent_in_lp = self::get_time_spent_in_lp(
5476
                        $user_id,
5477
                        $course,
5478
                        array($lp_id),
5479
                        $session_id
5480
                    );
5481
                    $percentage_score = self::get_avg_student_score(
5482
                        $user_id,
5483
                        $course,
5484
                        array($lp_id),
5485
                        $session_id
5486
                    );
5487
5488
                    $bestScore = self::get_avg_student_score(
5489
                        $user_id,
5490
                        $course,
5491
                        array($lp_id),
5492
                        $session_id,
5493
                        false,
5494
                        false,
5495
                        true
5496
                    );
5497
5498
                    if (is_numeric($progress)) {
5499
                        $progress = $progress.'%';
5500
                    }
5501
                    if (is_numeric($percentage_score)) {
5502
                        $percentage_score = $percentage_score.'%';
5503
                    } else {
5504
                        $percentage_score = '0%';
5505
                    }
5506
5507
                    if (is_numeric($bestScore)) {
5508
                        $bestScore = $bestScore.'%';
5509
                    } else {
5510
                        $bestScore = '-';
5511
                    }
5512
5513
                    $time_spent_in_lp = api_time_to_hms($time_spent_in_lp);
5514
                    $last_connection = '-';
5515
                    if (!empty($last_connection_in_lp)) {
5516
                        $last_connection = api_convert_and_format_date(
5517
                            $last_connection_in_lp,
5518
                            DATE_TIME_FORMAT_LONG
5519
                        );
5520
                    }
5521
5522
                    $url = api_get_path(WEB_CODE_PATH)."lp/lp_controller.php?cidReq={$course_code}&id_session=$session_id&lp_id=$lp_id&action=view";
5523
                    $html .= '<tr class="row_even">';
5524
5525
                    if (in_array('lp', $columnHeadersKeys)) {
5526
                        if ($learnpath['lp_visibility'] == 0) {
5527
                            $html .= Display::tag('td', $learnpath['lp_name']);
5528
                        } else {
5529
                            $html .= Display::tag(
5530
                                'td',
5531
                                Display::url(
5532
                                    $learnpath['lp_name'],
5533
                                    $url,
5534
                                    array('target' => SESSION_LINK_TARGET)
5535
                                )
5536
                            );
5537
                        }
5538
                    }
5539
5540
                    if (in_array('time', $columnHeadersKeys)) {
5541
                        $html .= Display::tag(
5542
                            'td',
5543
                            $time_spent_in_lp
5544
                        );
5545
                    }
5546
5547
                    if (in_array('progress', $columnHeadersKeys)) {
5548
                        $html .= Display::tag(
5549
                            'td',
5550
                            $progress
5551
                        );
5552
                    }
5553
5554
                    if (in_array('score', $columnHeadersKeys)) {
5555
                        $html .= Display::tag('td', $percentage_score);
5556
                    }
5557
                    if (in_array('best_score', $columnHeadersKeys)) {
5558
                        $html .= Display::tag('td', $bestScore);
5559
                    }
5560
5561
                    if (in_array('last_connection', $columnHeadersKeys)) {
5562
                        $html .= Display::tag('td', $last_connection, array('width'=>'180px'));
5563
                    }
5564
                    $html .= '</tr>';
5565
                }
5566
            } else {
5567
                $html .= '<tr>
5568
                        <td colspan="4" align="center">
5569
                            '.get_lang('NoLearnpath').'
5570
                        </td>
5571
                      </tr>';
5572
            }
5573
            $html .= '</tbody></table></div>';
5574
5575
            $html .= self::displayUserSkills($user_id, $course_info['id'], $session_id);
5576
        }
5577
5578
        return $html;
5579
    }
5580
5581
    /**
5582
     * Generates an histogram
5583
     * @param array $names list of exercise names
5584
     * @param array $my_results my results 0 to 100
5585
     * @param array $average average scores 0-100
5586
     * @return string
5587
     */
5588
    public static function generate_session_exercise_graph($names, $my_results, $average)
5589
    {
5590
        /* Create and populate the pData object */
5591
        $myData = new pData();
5592
        $myData->addPoints($names, 'Labels');
5593
        $myData->addPoints($my_results, 'Serie1');
5594
        $myData->addPoints($average, 'Serie2');
5595
        $myData->setSerieWeight('Serie1', 1);
5596
        $myData->setSerieTicks('Serie2', 4);
5597
        $myData->setSerieDescription('Labels', 'Months');
5598
        $myData->setAbscissa('Labels');
5599
        $myData->setSerieDescription('Serie1', get_lang('MyResults'));
5600
        $myData->setSerieDescription('Serie2', get_lang('AverageScore'));
5601
        $myData->setAxisUnit(0, '%');
5602
        $myData->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
5603
        // Cache definition
5604
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
5605
        $myCache = new pCache(array('CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)));
5606
        $chartHash = $myCache->getHash($myData);
5607
5608
        if ($myCache->isInCache($chartHash)) {
5609
            //if we already created the img
5610
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
5611
            $myCache->saveFromCache($chartHash, $imgPath);
5612
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
5613
        } else {
5614
            /* Define width, height and angle */
5615
            $mainWidth = 860;
5616
            $mainHeight = 500;
5617
            $angle = 50;
5618
5619
            /* Create the pChart object */
5620
            $myPicture = new pImage($mainWidth, $mainHeight, $myData);
5621
5622
            /* Turn of Antialiasing */
5623
            $myPicture->Antialias = false;
5624
5625
            /* Draw the background */
5626
            $settings = array('R' => 255, 'G' => 255, 'B' => 255);
5627
            $myPicture->drawFilledRectangle(0, 0, $mainWidth, $mainHeight, $settings);
5628
5629
            /* Add a border to the picture */
5630
            $myPicture->drawRectangle(
5631
                0,
5632
                0,
5633
                $mainWidth - 1,
5634
                $mainHeight - 1,
5635
                array('R' => 0, 'G' => 0, 'B' => 0)
5636
            );
5637
5638
            /* Set the default font */
5639
            $myPicture->setFontProperties(
5640
                array(
5641
                    'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
5642
                    'FontSize' => 10)
5643
            );
5644
            /* Write the chart title */
5645
            $myPicture->drawText(
5646
                $mainWidth / 2,
5647
                30,
5648
                get_lang('ExercisesInTimeProgressChart'),
5649
                array(
5650
                    'FontSize' => 12,
5651
                    'Align' => TEXT_ALIGN_BOTTOMMIDDLE
5652
                )
5653
            );
5654
5655
            /* Set the default font */
5656
            $myPicture->setFontProperties(
5657
                array(
5658
                    'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
5659
                    'FontSize' => 6
5660
                )
5661
            );
5662
5663
            /* Define the chart area */
5664
            $myPicture->setGraphArea(60, 60, $mainWidth - 60, $mainHeight - 150);
5665
5666
            /* Draw the scale */
5667
            $scaleSettings = array(
5668
                'XMargin' => 10,
5669
                'YMargin' => 10,
5670
                'Floating' => true,
5671
                'GridR' => 200,
5672
                'GridG' => 200,
5673
                'GridB' => 200,
5674
                'DrawSubTicks' => true,
5675
                'CycleBackground' => true,
5676
                'LabelRotation' => $angle,
5677
                'Mode' => SCALE_MODE_ADDALL_START0,
5678
            );
5679
            $myPicture->drawScale($scaleSettings);
5680
5681
            /* Turn on Antialiasing */
5682
            $myPicture->Antialias = true;
5683
5684
            /* Enable shadow computing */
5685
            $myPicture->setShadow(
5686
                true,
5687
                array(
5688
                    'X' => 1,
5689
                    'Y' => 1,
5690
                    'R' => 0,
5691
                    'G' => 0,
5692
                    'B' => 0,
5693
                    'Alpha' => 10
5694
                )
5695
            );
5696
5697
            /* Draw the line chart */
5698
            $myPicture->setFontProperties(
5699
                array(
5700
                    'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
5701
                    'FontSize' => 10
5702
                )
5703
            );
5704
            $myPicture->drawSplineChart();
5705
            $myPicture->drawPlotChart(
5706
                array(
5707
                    'DisplayValues' => true,
5708
                    'PlotBorder' => true,
5709
                    'BorderSize' => 1,
5710
                    'Surrounding' => -60,
5711
                    'BorderAlpha' => 80
5712
                )
5713
            );
5714
5715
            /* Write the chart legend */
5716
            $myPicture->drawLegend(
5717
                $mainWidth / 2 + 50,
5718
                50,
5719
                array(
5720
                    'Style' => LEGEND_BOX,
5721
                    'Mode' => LEGEND_HORIZONTAL,
5722
                    'FontR' => 0,
5723
                    'FontG' => 0,
5724
                    'FontB' => 0,
5725
                    'R' => 220,
5726
                    'G' => 220,
5727
                    'B' => 220,
5728
                    'Alpha' => 100
5729
                )
5730
            );
5731
5732
            $myCache->writeToCache($chartHash, $myPicture);
5733
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
5734
            $myCache->saveFromCache($chartHash, $imgPath);
5735
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
5736
        }
5737
5738
        $html = '<img src="'.$imgPath.'">';
5739
5740
        return $html;
5741
    }
5742
5743
    /**
5744
     * Returns a thumbnail of the function generate_exercise_result_graph
5745
     * @param  array $attempts
5746
     */
5747
    static function generate_exercise_result_thumbnail_graph($attempts)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
5748
    {
5749
        //$exercise_title = $attempts['title'];
5750
        $attempts = $attempts['data'];
5751
        $my_exercise_result_array = $exercise_result = array();
5752
        if (empty($attempts)) {
5753
            return null;
5754
        }
5755
5756
        foreach ($attempts as $attempt) {
5757
            if (api_get_user_id() == $attempt['exe_user_id']) {
5758
                if ($attempt['exe_weighting'] != 0) {
5759
                    $my_exercise_result_array[] = $attempt['exe_result'] / $attempt['exe_weighting'];
5760
                }
5761
            } else {
5762
                if ($attempt['exe_weighting'] != 0) {
5763
                    $exercise_result[] = $attempt['exe_result'] / $attempt['exe_weighting'];
5764
                }
5765
            }
5766
        }
5767
5768
        //Getting best result
5769
        rsort($my_exercise_result_array);
5770
        $my_exercise_result = 0;
5771
        if (isset($my_exercise_result_array[0])) {
5772
            $my_exercise_result = $my_exercise_result_array[0] * 100;
5773
        }
5774
5775
        $max     = 100;
5776
        $pieces  = 5;
5777
        $part    = round($max / $pieces);
5778
        $x_axis = array();
5779
        $final_array = array();
5780
        $my_final_array = array();
5781
5782
        for ($i = 1; $i <= $pieces; $i++) {
5783
            $sum = 1;
5784
            if ($i == 1) {
5785
                $sum = 0;
5786
            }
5787
            $min = ($i - 1) * $part + $sum;
5788
            $max = ($i) * $part;
5789
            $x_axis[] = $min." - ".$max;
5790
            $count = 0;
5791
            foreach ($exercise_result as $result) {
5792
                $percentage = $result * 100;
5793
                //echo $percentage.' - '.$min.' - '.$max."<br />";
5794
                if ($percentage >= $min && $percentage <= $max) {
5795
                    //echo ' is > ';
5796
                    $count++;
5797
                }
5798
            }
5799
            //echo '<br />';
5800
            $final_array[] = $count;
5801
5802
            if ($my_exercise_result >= $min && $my_exercise_result <= $max) {
5803
                $my_final_array[] = 1;
5804
            } else {
5805
                $my_final_array[] = 0;
5806
            }
5807
        }
5808
5809
        //Fix to remove the data of the user with my data
5810
        for ($i = 0; $i <= count($my_final_array); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
5811
            if (!empty($my_final_array[$i])) {
5812
                $my_final_array[$i] = $final_array[$i] + 1; //Add my result
5813
                $final_array[$i] = 0;
5814
            }
5815
        }
5816
5817
        // Dataset definition
5818
        $dataSet = new pData();
5819
        $dataSet->addPoints($final_array, 'Serie1');
5820
        $dataSet->addPoints($my_final_array, 'Serie2');
5821
        $dataSet->normalize(100, "%");
5822
        $dataSet->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
5823
5824
        // Cache definition
5825
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
5826
        $myCache = new pCache(array('CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)));
5827
        $chartHash = $myCache->getHash($dataSet);
5828
        if ($myCache->isInCache($chartHash)) {
5829
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
5830
            $myCache->saveFromCache($chartHash, $imgPath);
5831
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
5832
        } else {
5833
            /* Create the pChart object */
5834
            $widthSize = 80;
5835
            $heightSize = 35;
5836
            $fontSize = 2;
5837
5838
            $myPicture = new pImage($widthSize, $heightSize, $dataSet);
5839
5840
            /* Turn of Antialiasing */
5841
            $myPicture->Antialias = false;
5842
5843
            /* Add a border to the picture */
5844
            $myPicture->drawRectangle(
5845
                0,
5846
                0,
5847
                $widthSize - 1,
5848
                $heightSize - 1,
5849
                array('R' => 0, 'G' => 0, 'B' => 0)
5850
            );
5851
5852
            /* Set the default font */
5853
            $myPicture->setFontProperties(
5854
                array(
5855
                    'FontName' => api_get_path(
5856
                            SYS_FONTS_PATH
5857
                        ).'opensans/OpenSans-Regular.ttf',
5858
                    'FontSize' => $fontSize
5859
                )
5860
            );
5861
5862
            /* Do not write the chart title */
5863
5864
            /* Define the chart area */
5865
            $myPicture->setGraphArea(5, 5, $widthSize - 5, $heightSize - 5);
5866
5867
            /* Draw the scale */
5868
            $scaleSettings = array(
5869
                'GridR' => 200,
5870
                'GridG' => 200,
5871
                'GridB' => 200,
5872
                'DrawSubTicks' => true,
5873
                'CycleBackground' => true,
5874
                'Mode' => SCALE_MODE_MANUAL,
5875
                'ManualScale' => array(
5876
                    '0' => array(
5877
                        'Min' => 0,
5878
                        'Max' => 100
5879
                    )
5880
                )
5881
            );
5882
            $myPicture->drawScale($scaleSettings);
5883
5884
            /* Turn on shadow computing */
5885
            $myPicture->setShadow(
5886
                true,
5887
                array(
5888
                    'X' => 1,
5889
                    'Y' => 1,
5890
                    'R' => 0,
5891
                    'G' => 0,
5892
                    'B' => 0,
5893
                    'Alpha' => 10
5894
                )
5895
            );
5896
5897
            /* Draw the chart */
5898
            $myPicture->setShadow(
5899
                true,
5900
                array(
5901
                    'X' => 1,
5902
                    'Y' => 1,
5903
                    'R' => 0,
5904
                    'G' => 0,
5905
                    'B' => 0,
5906
                    'Alpha' => 10
5907
                )
5908
            );
5909
            $settings = array(
5910
                'DisplayValues' => true,
5911
                'DisplaySize' => $fontSize,
5912
                'DisplayR' => 0,
5913
                'DisplayG' => 0,
5914
                'DisplayB' => 0,
5915
                'DisplayOrientation' => ORIENTATION_HORIZONTAL,
5916
                'Gradient' => false,
5917
                'Surrounding' => 5,
5918
                'InnerSurrounding' => 5
5919
            );
5920
            $myPicture->drawStackedBarChart($settings);
5921
5922
            /* Save and write in cache */
5923
            $myCache->writeToCache($chartHash, $myPicture);
5924
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
5925
            $myCache->saveFromCache($chartHash, $imgPath);
5926
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
5927
        }
5928
5929
        return $imgPath;
5930
    }
5931
5932
    /**
5933
     * Generates a big graph with the number of best results
5934
     * @param	array
5935
     */
5936
    static function generate_exercise_result_graph($attempts)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
5937
    {
5938
        $exercise_title = strip_tags($attempts['title']);
5939
        $attempts       = $attempts['data'];
5940
        $my_exercise_result_array = $exercise_result = array();
5941
        if (empty($attempts)) {
5942
            return null;
5943
        }
5944
        foreach ($attempts as $attempt) {
5945
            if (api_get_user_id() == $attempt['exe_user_id']) {
5946
                if ($attempt['exe_weighting'] != 0) {
5947
                    $my_exercise_result_array[] = $attempt['exe_result'] / $attempt['exe_weighting'];
5948
                }
5949
            } else {
5950
                if ($attempt['exe_weighting'] != 0) {
5951
                    $exercise_result[] = $attempt['exe_result'] / $attempt['exe_weighting'];
5952
                }
5953
            }
5954
        }
5955
5956
        //Getting best result
5957
        rsort($my_exercise_result_array);
5958
        $my_exercise_result = 0;
5959
        if (isset($my_exercise_result_array[0])) {
5960
            $my_exercise_result = $my_exercise_result_array[0] * 100;
5961
        }
5962
5963
        $max = 100;
5964
        $pieces = 5;
5965
        $part = round($max / $pieces);
5966
        $x_axis = array();
5967
        $final_array = array();
5968
        $my_final_array = array();
5969
5970
        for ($i = 1; $i <= $pieces; $i++) {
5971
            $sum = 1;
5972
            if ($i == 1) {
5973
                $sum = 0;
5974
            }
5975
            $min = ($i - 1) * $part + $sum;
5976
            $max = ($i) * $part;
5977
            $x_axis[] = $min." - ".$max;
5978
            $count = 0;
5979
            foreach ($exercise_result as $result) {
5980
                $percentage = $result * 100;
5981
                if ($percentage >= $min && $percentage <= $max) {
5982
                    $count++;
5983
                }
5984
            }
5985
            $final_array[] = $count;
5986
5987
            if ($my_exercise_result >= $min && $my_exercise_result <= $max) {
5988
                $my_final_array[] = 1;
5989
            } else {
5990
                $my_final_array[] = 0;
5991
            }
5992
        }
5993
5994
        //Fix to remove the data of the user with my data
5995
5996
        for ($i = 0; $i <= count($my_final_array); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
5997
            if (!empty($my_final_array[$i])) {
5998
                $my_final_array[$i] = $final_array[$i] + 1; //Add my result
5999
                $final_array[$i] = 0;
6000
            }
6001
        }
6002
6003
        // Dataset definition
6004
        $dataSet = new pData();
6005
        $dataSet->addPoints($final_array, 'Serie1');
6006
        $dataSet->addPoints($my_final_array, 'Serie2');
6007
        $dataSet->addPoints($x_axis, 'Serie3');
6008
6009
        $dataSet->setSerieDescription('Serie1', get_lang('Score'));
6010
        $dataSet->setSerieDescription('Serie2', get_lang('MyResults'));
6011
        $dataSet->setAbscissa('Serie3');
6012
6013
        $dataSet->setXAxisName(get_lang('Score'));
6014
        $dataSet->normalize(100, "%");
6015
6016
        $dataSet->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
6017
6018
        // Cache definition
6019
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
6020
        $myCache = new pCache(array('CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)));
6021
        $chartHash = $myCache->getHash($dataSet);
6022
6023
        if ($myCache->isInCache($chartHash)) {
6024
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
6025
            $myCache->saveFromCache($chartHash, $imgPath);
6026
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
6027
        } else {
6028
            /* Create the pChart object */
6029
            $widthSize = 480;
6030
            $heightSize = 250;
6031
            $fontSize = 8;
6032
            $myPicture = new pImage($widthSize, $heightSize, $dataSet);
6033
6034
            /* Turn of Antialiasing */
6035
            $myPicture->Antialias = false;
6036
6037
            /* Add a border to the picture */
6038
            $myPicture->drawRectangle(0, 0, $widthSize - 1, $heightSize - 1, array('R' => 0, 'G' => 0, 'B' => 0));
6039
6040
            /* Set the default font */
6041
            $myPicture->setFontProperties(
6042
                array(
6043
                    'FontName' => api_get_path(
6044
                            SYS_FONTS_PATH
6045
                        ).'opensans/OpenSans-Regular.ttf',
6046
                    'FontSize' => 10
6047
                )
6048
            );
6049
6050
            /* Write the chart title */
6051
            $myPicture->drawText(
6052
                250,
6053
                20,
6054
                $exercise_title,
6055
                array(
6056
                    'FontSize' => 12,
6057
                    'Align' => TEXT_ALIGN_BOTTOMMIDDLE
6058
                )
6059
            );
6060
6061
            /* Define the chart area */
6062
            $myPicture->setGraphArea(50, 50, $widthSize - 20, $heightSize - 30);
6063
6064
            /* Draw the scale */
6065
            $scaleSettings = array(
6066
                'GridR' => 200,
6067
                'GridG' => 200,
6068
                'GridB' => 200,
6069
                'DrawSubTicks' => true,
6070
                'CycleBackground' => true,
6071
                'Mode' => SCALE_MODE_MANUAL,
6072
                'ManualScale' => array(
6073
                    '0' => array(
6074
                        'Min' => 0,
6075
                        'Max' => 100
6076
                    )
6077
                )
6078
            );
6079
            $myPicture->drawScale($scaleSettings);
6080
6081
            /* Turn on shadow computing */
6082
            $myPicture->setShadow(true, array('X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10));
6083
6084
            /* Draw the chart */
6085
            $myPicture->setShadow(true, array('X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10));
6086
            $settings = array(
6087
                'DisplayValues' => true,
6088
                'DisplaySize' => $fontSize,
6089
                'DisplayR' => 0,
6090
                'DisplayG' => 0,
6091
                'DisplayB' => 0,
6092
                'DisplayOrientation' => ORIENTATION_HORIZONTAL,
6093
                'Gradient' => false,
6094
                'Surrounding' => 30,
6095
                'InnerSurrounding' => 25
6096
            );
6097
            $myPicture->drawStackedBarChart($settings);
6098
6099
            $legendSettings = array(
6100
                'Mode' => LEGEND_HORIZONTAL,
6101
                'Style' => LEGEND_NOBORDER,
6102
            );
6103
            $myPicture->drawLegend($widthSize / 2, 30, $legendSettings);
6104
6105
            /* Write and save into cache */
6106
            $myCache->writeToCache($chartHash, $myPicture);
6107
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
6108
            $myCache->saveFromCache($chartHash, $imgPath);
6109
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
6110
        }
6111
6112
        return $imgPath;
6113
    }
6114
6115
    /**
6116
    * @param FormValidator $form
6117
    * @return mixed
6118
    */
6119
    public static function setUserSearchForm($form)
6120
    {
6121
        global $_configuration;
6122
        $form->addElement('text', 'keyword', get_lang('Keyword'));
6123
        $form->addElement(
6124
            'select',
6125
            'active',
6126
            get_lang('Status'),
6127
            array(1 => get_lang('Active'), 0 => get_lang('Inactive'))
6128
        );
6129
6130
        $form->addElement(
6131
            'select',
6132
            'sleeping_days',
6133
            get_lang('InactiveDays'),
6134
            array(
6135
                '',
6136
                1 => 1,
6137
                5 => 5,
6138
                15 => 15,
6139
                30 => 30,
6140
                60 => 60,
6141
                90 => 90,
6142
                120 => 120,
6143
            )
6144
        );
6145
6146
        $form->addButtonSearch(get_lang('Search'));
6147
6148
        return $form;
6149
    }
6150
6151
    /**
6152
     * Get the progress of a exercise
6153
     * @param   int $sessionId  The session ID (session.id)
6154
     * @param   int $courseId   The course ID (course.id)
6155
     * @param   int $exerciseId The quiz ID (c_quiz.id)
6156
     * @param   string $date_from
6157
     * @param   string $date_to
6158
     * @param   array   $options    An array of options you can pass to the query (limit, where and order)
6159
     * @return array An array with the data of exercise(s) progress
6160
     */
6161
    public static function get_exercise_progress(
6162
        $sessionId = 0,
6163
        $courseId = 0,
6164
        $exerciseId = 0,
6165
        $date_from = null,
6166
        $date_to = null,
6167
        $options = array()
6168
    ) {
6169
        $sessionId  = intval($sessionId);
6170
        $courseId   = intval($courseId);
6171
        $exerciseId = intval($exerciseId);
6172
        $date_from  = Database::escape_string($date_from);
6173
        $date_to    = Database::escape_string($date_to);
6174
        /*
6175
         * This method gets the data by blocks, as previous attempts at one single
6176
         * query made it take ages. The logic of query division is described below
6177
         */
6178
        // Get tables names
6179
        $tuser = Database::get_main_table(TABLE_MAIN_USER);
6180
        $tquiz = Database::get_course_table(TABLE_QUIZ_TEST);
6181
        $tquiz_answer = Database::get_course_table(TABLE_QUIZ_ANSWER);
6182
        $tquiz_question = Database::get_course_table(TABLE_QUIZ_QUESTION);
6183
        $tquiz_rel_question = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
6184
        $ttrack_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
6185
        $ttrack_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
6186
6187
        $sessions = array();
6188
        $courses = array();
6189
        // if session ID is defined but course ID is empty, get all the courses
6190
        // from that session
6191
        if (!empty($sessionId) && empty($courseId)) {
6192
            // $courses is an array of course int id as index and course details hash as value
6193
            $courses = SessionManager::get_course_list_by_session_id($sessionId);
6194
            $sessions[$sessionId] = api_get_session_info($sessionId);
6195
        } elseif (empty($sessionId) && !empty($courseId)) {
6196
            // if, to the contrary, course is defined but not sessions, get the sessions that include this course
6197
            // $sessions is an array like: [0] => ('id' => 3, 'name' => 'Session 35'), [1] => () etc;
6198
            $course = api_get_course_info_by_id($courseId);
6199
            $sessionsTemp = SessionManager::get_session_by_course($courseId);
6200
            $courses[$courseId] = $course;
6201
            foreach ($sessionsTemp as $sessionItem) {
6202
                $sessions[$sessionItem['id']] = $sessionItem;
6203
            }
6204
        } elseif (!empty($courseId) && !empty($sessionId)) {
6205
            //none is empty
6206
            $course = api_get_course_info_by_id($courseId);
6207
            $courses[$courseId] = array($course['code']);
6208
            $courses[$courseId]['code'] = $course['code'];
6209
            $sessions[$sessionId] = api_get_session_info($sessionId);
6210
        } else {
6211
            //both are empty, not enough data, return an empty array
6212
            return array();
6213
        }
6214
        // Now we have two arrays of courses and sessions with enough data to proceed
6215
        // If no course could be found, we shouldn't return anything.
6216
        // Sessions can be empty (then we only return the pure-course-context results)
6217
        if (count($courses) < 1) {
0 ignored issues
show
Bug introduced by
It seems like $courses can also be of type integer; however, parameter $var of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

6217
        if (count(/** @scrutinizer ignore-type */ $courses) < 1) {
Loading history...
6218
            return array();
6219
        }
6220
6221
        $data = array();
6222
        // The following loop is less expensive than what it seems:
6223
        // - if a course was defined, then we only loop through sessions
6224
        // - if a session was defined, then we only loop through courses
6225
        // - if a session and a course were defined, then we only loop once
6226
        foreach ($courses as $courseIdx => $courseData) {
6227
            $where = '';
6228
            $whereParams = array();
6229
            $whereSessionParams = '';
6230
            if (count($sessions > 0)) {
6231
                foreach ($sessions as $sessionIdx => $sessionData) {
6232
                    if (!empty($sessionIdx)) {
6233
                        $whereSessionParams .= $sessionIdx.',';
6234
                    }
6235
                }
6236
                $whereSessionParams = substr($whereSessionParams, 0, -1);
6237
            }
6238
6239
            if (!empty($exerciseId)) {
6240
                $exerciseId = intval($exerciseId);
6241
                $where .= ' AND q.id = %d ';
6242
                $whereParams[] = $exerciseId;
6243
            }
6244
6245
            /*
6246
             * This feature has been disabled for now, to avoid having to
6247
             * join two very large tables
6248
            //2 = show all questions (wrong and correct answered)
6249
            if ($answer != 2) {
6250
                $answer = intval($answer);
6251
                //$where .= ' AND qa.correct = %d';
6252
                //$whereParams[] = $answer;
6253
            }
6254
            */
6255
6256
            $limit = '';
6257
            if (!empty($options['limit'])) {
6258
                $limit = " LIMIT ".$options['limit'];
6259
            }
6260
6261
            if (!empty($options['where'])) {
6262
                $where .= ' AND '.Database::escape_string($options['where']);
6263
            }
6264
6265
            $order = '';
6266
            if (!empty($options['order'])) {
6267
                $order = " ORDER BY ".$options['order'];
6268
            }
6269
6270
            if (!empty($date_to) && !empty($date_from)) {
6271
                $where .= sprintf(" AND (te.start_date BETWEEN '%s 00:00:00' AND '%s 23:59:59')", $date_from, $date_to);
6272
            }
6273
6274
            $sql = "SELECT
6275
                te.session_id,
6276
                ta.id as attempt_id,
6277
                te.exe_user_id as user_id,
6278
                te.exe_id as exercise_attempt_id,
6279
                ta.question_id,
6280
                ta.answer as answer_id,
6281
                ta.tms as time,
6282
                te.exe_exo_id as quiz_id,
6283
                CONCAT ('c', q.c_id, '_e', q.id) as exercise_id,
6284
                q.title as quiz_title,
6285
                qq.description as description
6286
                FROM $ttrack_exercises te
6287
                INNER JOIN $ttrack_attempt ta 
6288
                ON ta.exe_id = te.exe_id
6289
                INNER JOIN $tquiz q 
6290
                ON q.id = te.exe_exo_id
6291
                INNER JOIN $tquiz_rel_question rq 
6292
                ON rq.exercice_id = q.id AND rq.c_id = q.c_id
6293
                INNER JOIN $tquiz_question qq
6294
                ON
6295
                    qq.id = rq.question_id AND
6296
                    qq.c_id = rq.c_id AND
6297
                    qq.position = rq.question_order AND
6298
                    ta.question_id = rq.question_id
6299
                WHERE
6300
                    te.c_id = $courseIdx ".(empty($whereSessionParams) ? '' : "AND te.session_id IN ($whereSessionParams)")."
6301
                    AND q.c_id = $courseIdx
6302
                    $where $order $limit";
6303
            $sql_query = vsprintf($sql, $whereParams);
6304
6305
            // Now browse through the results and get the data
6306
            $rs = Database::query($sql_query);
6307
            $userIds = array();
6308
            $questionIds = array();
6309
            $answerIds = array();
6310
            while ($row = Database::fetch_array($rs)) {
6311
                //only show if exercise is visible
6312
                if (api_get_item_visibility($courseData, 'quiz', $row['exercise_id'])) {
6313
                    $userIds[$row['user_id']] = $row['user_id'];
6314
                    $questionIds[$row['question_id']] = $row['question_id'];
6315
                    $answerIds[$row['question_id']][$row['answer_id']] = $row['answer_id'];
6316
                    $row['session'] = $sessions[$row['session_id']];
6317
                    $data[] = $row;
6318
                }
6319
            }
6320
            // Now fill questions data. Query all questions and answers for this test to avoid
6321
            $sqlQuestions = "SELECT tq.c_id, tq.id as question_id, tq.question, tqa.id_auto,
6322
                            tqa.answer, tqa.correct, tq.position, tqa.id_auto as answer_id
6323
                            FROM $tquiz_question tq, $tquiz_answer tqa
6324
                            WHERE
6325
                                tqa.question_id = tq.id AND
6326
                                tqa.c_id = tq.c_id AND
6327
                                tq.c_id = $courseIdx AND
6328
                                tq.id IN (".implode(',', $questionIds).")";
6329
6330
            $resQuestions = Database::query($sqlQuestions);
6331
            $answer = array();
6332
            $question = array();
6333
            while ($rowQuestion = Database::fetch_assoc($resQuestions)) {
6334
                $questionId = $rowQuestion['question_id'];
6335
                $answerId = $rowQuestion['answer_id'];
6336
                $answer[$questionId][$answerId] = array(
6337
                    'position' => $rowQuestion['position'],
6338
                    'question' => $rowQuestion['question'],
6339
                    'answer' => $rowQuestion['answer'],
6340
                    'correct' => $rowQuestion['correct']
6341
                );
6342
                $question[$questionId]['question'] = $rowQuestion['question'];
6343
            }
6344
6345
            // Now fill users data
6346
            $sqlUsers = "SELECT user_id, username, lastname, firstname
6347
                         FROM $tuser
6348
                         WHERE user_id IN (".implode(',', $userIds).")";
6349
            $resUsers = Database::query($sqlUsers);
6350
            while ($rowUser = Database::fetch_assoc($resUsers)) {
6351
                $users[$rowUser['user_id']] = $rowUser;
6352
            }
6353
6354
            foreach ($data as $id => $row) {
6355
                $rowQuestId = $row['question_id'];
6356
                $rowAnsId = $row['answer_id'];
6357
                $data[$id]['session'] = $sessions[$row['session_id']]['name'];
6358
                $data[$id]['firstname'] = $users[$row['user_id']]['firstname'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $users does not seem to be defined for all execution paths leading up to this point.
Loading history...
6359
                $data[$id]['lastname'] = $users[$row['user_id']]['lastname'];
6360
                $data[$id]['username'] = $users[$row['user_id']]['username'];
6361
                $data[$id]['answer'] = $answer[$rowQuestId][$rowAnsId]['answer'];
6362
                $data[$id]['correct'] = ($answer[$rowQuestId][$rowAnsId]['correct'] == 0 ? get_lang('No') : get_lang('Yes'));
6363
                $data[$id]['question'] = $question[$rowQuestId]['question'];
6364
                $data[$id]['question_id'] = $rowQuestId;
6365
                $data[$id]['description'] = $row['description'];
6366
            }
6367
6368
            /*
6369
            The minimum expected array structure at the end is:
6370
            attempt_id,
6371
            session name,
6372
            exercise_id,
6373
            quiz_title,
6374
            username,
6375
            lastname,
6376
            firstname,
6377
            time,
6378
            question_id,
6379
            question,
6380
            answer,
6381
            */
6382
        }
6383
        return $data;
6384
    }
6385
6386
    /**
6387
     * @param User $user
6388
     * @param string $tool
6389
     * @param Course $course
6390
     * @param SessionEntity |null $session Optional.
6391
     * @return \Chamilo\CourseBundle\Entity\CStudentPublication|null
6392
     * @throws \Doctrine\ORM\NonUniqueResultException
6393
     */
6394
    public static function getLastStudentPublication(
6395
        User $user,
6396
        $tool,
6397
        Course $course,
6398
        SessionEntity $session = null
6399
    ) {
6400
        return Database::getManager()
6401
            ->createQuery("
6402
                SELECT csp
6403
                FROM ChamiloCourseBundle:CStudentPublication csp
6404
                INNER JOIN ChamiloCourseBundle:CItemProperty cip
6405
                    WITH (
6406
                        csp.iid = cip.ref AND
6407
                        csp.session = cip.session AND
6408
                        csp.cId = cip.course AND
6409
                        csp.userId = cip.lasteditUserId
6410
                    )
6411
                WHERE
6412
                    cip.session = :session AND cip.course = :course AND cip.lasteditUserId = :user AND cip.tool = :tool
6413
                ORDER BY csp.iid DESC
6414
            ")
6415
            ->setMaxResults(1)
6416
            ->setParameters([
6417
                'tool' => $tool,
6418
                'session' => $session,
6419
                'course' => $course,
6420
                'user' => $user
6421
            ])
6422
            ->getOneOrNullResult();
6423
    }
6424
6425
    /**
6426
     * Get the HTML code for show a block with the achieved user skill on course/session
6427
     * @param int $userId
6428
     * @param int $courseId Optional.
6429
     * @param int $sessionId Optional.
6430
     * @return string
6431
     */
6432
    public static function displayUserSkills($userId, $courseId = 0, $sessionId = 0)
6433
    {
6434
        if (Skill::isAllowed($userId, false) === false) {
6435
            return '';
6436
        }
6437
        $skillManager = new Skill();
6438
        $html = $skillManager->getUserSkillsTable($userId, $courseId, $sessionId)['table'];
6439
        return $html;
6440
    }
6441
6442
    /**
6443
     * Gets the IP of a given user, using the last login before the given date
6444
     * @param int User ID
6445
     * @param string Datetime
6446
     * @param bool Whether to return the IP as a link or just as an IP
6447
     * @param string If defined and return_as_link if true, will be used as the text to be shown as the link
6448
     * @return string IP address (or false on error)
6449
     * @assert (0,0) === false
6450
     */
6451
    public static function get_ip_from_user_event(
6452
        $user_id,
6453
        $event_date,
6454
        $return_as_link = false,
6455
        $body_replace = null
6456
    ) {
6457
        if (empty($user_id) || empty($event_date)) {
6458
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
6459
        }
6460
        $user_id = intval($user_id);
6461
        $event_date = Database::escape_string($event_date);
6462
        $table_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
6463
        $sql_ip = "SELECT login_date, user_ip 
6464
                   FROM $table_login
6465
                   WHERE login_user_id = $user_id AND login_date < '$event_date'
6466
                   ORDER BY login_date DESC LIMIT 1";
6467
        $ip = '';
6468
        $res_ip = Database::query($sql_ip);
6469
        if ($res_ip !== false && Database::num_rows($res_ip) > 0) {
6470
            $row_ip = Database::fetch_row($res_ip);
6471
            if ($return_as_link) {
6472
                $ip = Display::url(
6473
                    (empty($body_replace) ? $row_ip[1] : $body_replace), 'http://www.whatsmyip.org/ip-geo-location/?ip='.$row_ip[1],
6474
                    array('title' => get_lang('TraceIP'), 'target' => '_blank')
6475
                );
6476
            } else {
6477
                $ip = $row_ip[1];
6478
            }
6479
        }
6480
6481
        return $ip;
6482
    }
6483
6484
    /**
6485
     * @param int $userId
6486
     * @param array $courseInfo
6487
     * @param int $sessionId
6488
     * @return array
6489
     */
6490
    public static function getToolInformation(
6491
        $userId,
6492
        $courseInfo,
6493
        $sessionId = 0
6494
    ) {
6495
        $csvContent = array();
6496
        $courseToolInformation = '';
6497
        $headerTool = array(
6498
            array(get_lang('Title')),
6499
            array(get_lang('CreatedAt')),
6500
            array(get_lang('UpdatedAt')),
6501
        );
6502
6503
        $headerListForCSV = array();
6504
        foreach ($headerTool as $item) {
6505
            $headerListForCSV[] = $item[0];
6506
        }
6507
6508
        $courseForumInformationArray = getForumCreatedByUser(
6509
            $userId,
6510
            $courseInfo['real_id'],
6511
            $sessionId
6512
        );
6513
6514
        if (!empty($courseForumInformationArray)) {
6515
            $csvContent[] = array();
6516
            $csvContent[] = [get_lang('Forums')];
6517
            $csvContent[] = $headerListForCSV;
6518
            foreach ($courseForumInformationArray as $row) {
6519
                $csvContent[] = $row;
6520
            }
6521
6522
            $courseToolInformation .= Display::page_subheader2(
6523
                get_lang('Forums')
6524
            );
6525
            $courseToolInformation .= Display::return_sortable_table(
6526
                $headerTool,
6527
                $courseForumInformationArray
6528
            );
6529
        }
6530
6531
        $courseWorkInformationArray = getWorkCreatedByUser(
6532
            $userId,
6533
            $courseInfo['real_id'],
6534
            $sessionId
6535
        );
6536
6537
        if (!empty($courseWorkInformationArray)) {
6538
            $csvContent[] = null;
6539
            $csvContent[] = [get_lang('Works')];
6540
            $csvContent[] = $headerListForCSV;
6541
6542
            foreach ($courseWorkInformationArray as $row) {
6543
                $csvContent[] = $row;
6544
            }
6545
            $csvContent[] = null;
6546
6547
            $courseToolInformation .= Display::page_subheader2(
6548
                get_lang('Works')
6549
            );
6550
            $courseToolInformation .= Display::return_sortable_table(
6551
                $headerTool,
6552
                $courseWorkInformationArray
6553
            );
6554
        }
6555
6556
        $courseToolInformationTotal = null;
6557
        if (!empty($courseToolInformation)) {
6558
            $sessionTitle = null;
6559
            if (!empty($sessionId)) {
6560
                $sessionTitle = ' ('.api_get_session_name($sessionId).')';
6561
            }
6562
6563
            $courseToolInformationTotal .= Display::page_subheader(
6564
                $courseInfo['title'].$sessionTitle
6565
            );
6566
            $courseToolInformationTotal .= $courseToolInformation;
6567
        }
6568
6569
        return array(
6570
            'array' => $csvContent,
6571
            'html' => $courseToolInformationTotal
6572
        );
6573
    }
6574
}
6575
6576
/**
6577
 * @todo move into a proper file
6578
 * @package chamilo.tracking
6579
 */
6580
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...
6581
{
6582
    /**
6583
     * @return mixed
6584
     */
6585
    public static function count_item_resources()
6586
    {
6587
        $session_id = api_get_session_id();
6588
        $course_id = api_get_course_int_id();
6589
6590
        $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
6591
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
6592
6593
        $sql = "SELECT count(tool) AS total_number_of_items
6594
                FROM $table_item_property track_resource, $table_user user
6595
                WHERE
6596
                    track_resource.c_id = $course_id AND
6597
                    track_resource.insert_user_id = user.user_id AND
6598
                    session_id ".(empty($session_id) ? ' IS NULL ' : " = $session_id ");
6599
6600
        if (isset($_GET['keyword'])) {
6601
            $keyword = Database::escape_string(trim($_GET['keyword']));
6602
            $sql .= " AND (
6603
                        user.username LIKE '%".$keyword."%' OR
6604
                        lastedit_type LIKE '%".$keyword."%' OR
6605
                        tool LIKE '%".$keyword."%'
6606
                    )";
6607
        }
6608
6609
        $sql .= " AND tool IN (
6610
                    'document',
6611
                    'learnpath',
6612
                    'quiz',
6613
                    'glossary',
6614
                    'link',
6615
                    'course_description',
6616
                    'announcement',
6617
                    'thematic',
6618
                    'thematic_advance',
6619
                    'thematic_plan'
6620
                )";
6621
        $res = Database::query($sql);
6622
        $obj = Database::fetch_object($res);
6623
6624
        return $obj->total_number_of_items;
6625
    }
6626
6627
    /**
6628
     * @param $from
6629
     * @param $number_of_items
6630
     * @param $column
6631
     * @param $direction
6632
     * @return array
6633
     */
6634
    public static function get_item_resources_data($from, $number_of_items, $column, $direction)
6635
    {
6636
        $session_id = api_get_session_id();
6637
        $course_id = api_get_course_int_id();
6638
6639
        $table_item_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
6640
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
6641
        $table_session = Database::get_main_table(TABLE_MAIN_SESSION);
6642
        $session_id = intval($session_id);
6643
6644
        $sql = "SELECT
6645
                    tool as col0,
6646
                    lastedit_type as col1,
6647
                    ref as ref,
6648
                    user.username as col3,
6649
                    insert_date as col6,
6650
                    visibility as col7,
6651
                    user.user_id as user_id
6652
                FROM $table_item_property track_resource, $table_user user
6653
                WHERE
6654
                  track_resource.c_id = $course_id AND
6655
                  track_resource.insert_user_id = user.user_id AND
6656
                  session_id ".(empty($session_id) ? ' IS NULL ' : " = $session_id ");
6657
6658
        if (isset($_GET['keyword'])) {
6659
            $keyword = Database::escape_string(trim($_GET['keyword']));
6660
            $sql .= " AND (
6661
                        user.username LIKE '%".$keyword."%' OR
6662
                        lastedit_type LIKE '%".$keyword."%' OR
6663
                        tool LIKE '%".$keyword."%'
6664
                     ) ";
6665
        }
6666
6667
        $sql .= " AND tool IN (
6668
                    'document',
6669
                    'learnpath',
6670
                    'quiz',
6671
                    'glossary',
6672
                    'link',
6673
                    'course_description',
6674
                    'announcement',
6675
                    'thematic',
6676
                    'thematic_advance',
6677
                    'thematic_plan'
6678
                )";
6679
6680
        if ($column == 0) {
6681
            $column = '0';
6682
        }
6683
        if ($column != '' && $direction != '') {
6684
            if ($column != 2 && $column != 4) {
6685
                $sql .= " ORDER BY col$column $direction";
6686
            }
6687
        } else {
6688
            $sql .= " ORDER BY col6 DESC ";
6689
        }
6690
6691
        $from = intval($from);
6692
        if ($from) {
6693
            $number_of_items = intval($number_of_items);
6694
            $sql .= " LIMIT $from, $number_of_items ";
6695
        }
6696
6697
        $res = Database::query($sql);
6698
        $resources = array();
6699
        $thematic_tools = array('thematic', 'thematic_advance', 'thematic_plan');
6700
        while ($row = Database::fetch_array($res)) {
6701
            $ref = $row['ref'];
6702
            $table_name = self::get_tool_name_table($row['col0']);
6703
            $table_tool = Database::get_course_table($table_name['table_name']);
6704
6705
            $id = $table_name['id_tool'];
6706
            $recorset = false;
6707
6708
            if (in_array($row['col0'], array('thematic_plan', 'thematic_advance'))) {
6709
                $tbl_thematic = Database::get_course_table(TABLE_THEMATIC);
6710
                $sql = "SELECT thematic_id FROM $table_tool
6711
                        WHERE c_id = $course_id AND id = $ref";
6712
                $rs_thematic  = Database::query($sql);
6713
                if (Database::num_rows($rs_thematic)) {
6714
                    $row_thematic = Database::fetch_array($rs_thematic);
6715
                    $thematic_id = $row_thematic['thematic_id'];
6716
6717
                    $sql = "SELECT session.id, session.name, user.username
6718
                            FROM $tbl_thematic t, $table_session session, $table_user user
6719
                            WHERE
6720
                              t.c_id = $course_id AND
6721
                              t.session_id = session.id AND
6722
                              session.id_coach = user.user_id AND
6723
                              t.id = $thematic_id";
6724
                    $recorset = Database::query($sql);
6725
                }
6726
            } else {
6727
                $sql = "SELECT session.id, session.name, user.username
6728
                          FROM $table_tool tool, $table_session session, $table_user user
6729
                          WHERE
6730
                              tool.c_id = $course_id AND
6731
                              tool.session_id = session.id AND
6732
                              session.id_coach = user.user_id AND
6733
                              tool.$id = $ref";
6734
                $recorset = Database::query($sql);
6735
            }
6736
6737
            if (!empty($recorset)) {
6738
                $obj = Database::fetch_object($recorset);
6739
6740
                $name_session = '';
6741
                $coach_name = '';
6742
                if (!empty($obj)) {
6743
                    $name_session = $obj->name;
6744
                    $coach_name   = $obj->username;
6745
                }
6746
6747
                $url_tool = api_get_path(WEB_CODE_PATH).$table_name['link_tool'];
6748
                $row[0] = '';
6749
                if ($row['col6'] != 2) {
6750
                    if (in_array($row['col0'], $thematic_tools)) {
6751
                        $exp_thematic_tool = explode('_', $row['col0']);
6752
                        $thematic_tool_title = '';
6753
                        if (is_array($exp_thematic_tool)) {
6754
                            foreach ($exp_thematic_tool as $exp) {
6755
                                $thematic_tool_title .= api_ucfirst($exp);
6756
                            }
6757
                        } else {
6758
                            $thematic_tool_title = api_ucfirst($row['col0']);
6759
                        }
6760
6761
                        $row[0] = '<a href="'.$url_tool.'?'.api_get_cidreq().'&action=thematic_details">'.get_lang($thematic_tool_title).'</a>';
6762
                    } else {
6763
                        $row[0] = '<a href="'.$url_tool.'?'.api_get_cidreq().'">'.get_lang('Tool'.api_ucfirst($row['col0'])).'</a>';
6764
                    }
6765
                } else {
6766
                    $row[0] = api_ucfirst($row['col0']);
6767
                }
6768
                $row[1] = get_lang($row[1]);
6769
                $row[6] = api_convert_and_format_date($row['col6'], null, date_default_timezone_get());
6770
                $row[5] = '';
6771
                //@todo Improve this code please
6772
                switch ($table_name['table_name']) {
6773
                    case 'document':
6774
                        $sql = "SELECT tool.title as title FROM $table_tool tool
6775
                                WHERE c_id = $course_id AND id = $ref";
6776
                        $rs_document = Database::query($sql);
6777
                        $obj_document = Database::fetch_object($rs_document);
6778
                        if ($obj_document) {
6779
                            $row[5] = $obj_document->title;
6780
                        }
6781
                        break;
6782
                    case 'announcement':
6783
                        $sql = "SELECT title FROM $table_tool
6784
                                WHERE c_id = $course_id AND id = $ref";
6785
                        $rs_document = Database::query($sql);
6786
                        $obj_document = Database::fetch_object($rs_document);
6787
                        if ($obj_document) {
6788
                            $row[5] = $obj_document->title;
6789
                        }
6790
                        break;
6791
                    case 'glossary':
6792
                        $sql = "SELECT name FROM $table_tool
6793
                                WHERE c_id = $course_id AND glossary_id = $ref";
6794
                        $rs_document = Database::query($sql);
6795
                        $obj_document = Database::fetch_object($rs_document);
6796
                        if ($obj_document) {
6797
                            $row[5] = $obj_document->name;
6798
                        }
6799
                        break;
6800
                    case 'lp':
6801
                        $sql = "SELECT name
6802
                                FROM $table_tool WHERE c_id = $course_id AND id = $ref";
6803
                        $rs_document = Database::query($sql);
6804
                        $obj_document = Database::fetch_object($rs_document);
6805
                        $row[5] = $obj_document->name;
6806
                        break;
6807
                    case 'quiz':
6808
                        $sql = "SELECT title FROM $table_tool
6809
                                WHERE c_id = $course_id AND id = $ref";
6810
                        $rs_document = Database::query($sql);
6811
                        $obj_document = Database::fetch_object($rs_document);
6812
                        if ($obj_document) {
6813
                            $row[5] = $obj_document->title;
6814
                        }
6815
                        break;
6816
                    case 'course_description':
6817
                        $sql = "SELECT title FROM $table_tool
6818
                                WHERE c_id = $course_id AND id = $ref";
6819
                        $rs_document = Database::query($sql);
6820
                        $obj_document = Database::fetch_object($rs_document);
6821
                        if ($obj_document) {
6822
                            $row[5] = $obj_document->title;
6823
                        }
6824
                        break;
6825
                    case 'thematic':
6826
                        $rs = Database::query("SELECT title FROM $table_tool WHERE c_id = $course_id AND id = $ref");
6827
                        if (Database::num_rows($rs) > 0) {
6828
                            $obj = Database::fetch_object($rs);
6829
                            if ($obj) {
6830
                                $row[5] = $obj->title;
6831
                            }
6832
                        }
6833
                        break;
6834
                    case 'thematic_advance':
6835
                        $rs = Database::query("SELECT content FROM $table_tool WHERE c_id = $course_id AND id = $ref");
6836
                        if (Database::num_rows($rs) > 0) {
6837
                            $obj = Database::fetch_object($rs);
6838
                            if ($obj) {
6839
                                $row[5] = $obj->content;
6840
                            }
6841
                        }
6842
                        break;
6843
                    case 'thematic_plan':
6844
                        $rs = Database::query("SELECT title FROM $table_tool WHERE c_id = $course_id AND id = $ref");
6845
                        if (Database::num_rows($rs) > 0) {
6846
                            $obj = Database::fetch_object($rs);
6847
                            if ($obj) {
6848
                                $row[5] = $obj->title;
6849
                            }
6850
                        }
6851
                        break;
6852
                    default:
6853
                        break;
6854
                }
6855
6856
                $row2 = $name_session;
6857
                if (!empty($coach_name)) {
6858
                    $row2 .= '<br />'.get_lang('Coach').': '.$coach_name;
6859
                }
6860
                $row[2] = $row2;
6861
                if (!empty($row['col3'])) {
6862
                    $userInfo = api_get_user_info($row['user_id']);
6863
                    $row['col3'] = Display::url(
6864
                        $row['col3'],
6865
                        $userInfo['profile_url']
6866
                    );
6867
                    $row[3] = $row['col3'];
6868
6869
                    $ip = Tracking::get_ip_from_user_event(
6870
                        $row['user_id'],
6871
                        $row['col6'],
6872
                        true
6873
                    );
6874
                    if (empty($ip)) {
6875
                        $ip = get_lang('Unknown');
6876
                    }
6877
                    $row[4] = $ip;
6878
                }
6879
6880
                $resources[] = $row;
6881
            }
6882
        }
6883
6884
        return $resources;
6885
    }
6886
6887
    /**
6888
     * @param string $tool
6889
     *
6890
     * @return array
6891
     */
6892
    public static function get_tool_name_table($tool)
6893
    {
6894
        switch ($tool) {
6895
            case 'document':
6896
                $table_name = TABLE_DOCUMENT;
6897
                $link_tool = 'document/document.php';
6898
                $id_tool = 'id';
6899
                break;
6900
            case 'learnpath':
6901
                $table_name = TABLE_LP_MAIN;
6902
                $link_tool = 'lp/lp_controller.php';
6903
                $id_tool = 'id';
6904
                break;
6905
            case 'quiz':
6906
                $table_name = TABLE_QUIZ_TEST;
6907
                $link_tool = 'exercise/exercise.php';
6908
                $id_tool = 'id';
6909
                break;
6910
            case 'glossary':
6911
                $table_name = TABLE_GLOSSARY;
6912
                $link_tool = 'glossary/index.php';
6913
                $id_tool = 'glossary_id';
6914
                break;
6915
            case 'link':
6916
                $table_name = TABLE_LINK;
6917
                $link_tool = 'link/link.php';
6918
                $id_tool = 'id';
6919
                break;
6920
            case 'course_description':
6921
                $table_name = TABLE_COURSE_DESCRIPTION;
6922
                $link_tool = 'course_description/';
6923
                $id_tool = 'id';
6924
                break;
6925
            case 'announcement':
6926
                $table_name = TABLE_ANNOUNCEMENT;
6927
                $link_tool = 'announcements/announcements.php';
6928
                $id_tool = 'id';
6929
                break;
6930
            case 'thematic':
6931
                $table_name = TABLE_THEMATIC;
6932
                $link_tool = 'course_progress/index.php';
6933
                $id_tool = 'id';
6934
                break;
6935
            case 'thematic_advance':
6936
                $table_name = TABLE_THEMATIC_ADVANCE;
6937
                $link_tool = 'course_progress/index.php';
6938
                $id_tool = 'id';
6939
                break;
6940
            case 'thematic_plan':
6941
                $table_name = TABLE_THEMATIC_PLAN;
6942
                $link_tool = 'course_progress/index.php';
6943
                $id_tool = 'id';
6944
                break;
6945
            default:
6946
                $table_name = $tool;
6947
            break;
6948
        }
6949
6950
        return array(
6951
            'table_name' => $table_name,
6952
            'link_tool' => $link_tool,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $link_tool does not seem to be defined for all execution paths leading up to this point.
Loading history...
6953
            'id_tool' => $id_tool
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id_tool does not seem to be defined for all execution paths leading up to this point.
Loading history...
6954
        );
6955
    }
6956
6957
    /**
6958
     * @return string
6959
     */
6960
    public static function display_additional_profile_fields()
6961
    {
6962
        // getting all the extra profile fields that are defined by the platform administrator
6963
        $extra_fields = UserManager::get_extra_fields(0, 50, 5, 'ASC');
6964
6965
        // creating the form
6966
        $return = '<form action="courseLog.php" method="get" name="additional_profile_field_form" id="additional_profile_field_form">';
6967
6968
        // the select field with the additional user profile fields (= this is where we select the field of which we want to see
6969
        // the information the users have entered or selected.
6970
        $return .= '<select class="chzn-select" name="additional_profile_field[]" multiple>';
6971
        $return .= '<option value="-">'.get_lang('SelectFieldToAdd').'</option>';
6972
        $extra_fields_to_show = 0;
6973
        foreach ($extra_fields as $key=>$field) {
6974
            // show only extra fields that are visible + and can be filtered, added by J.Montoya
6975
            if ($field[6] == 1 && $field[8] == 1) {
6976
                if (isset($_GET['additional_profile_field']) && $field[0] == $_GET['additional_profile_field']) {
6977
                    $selected = 'selected="selected"';
6978
                } else {
6979
                    $selected = '';
6980
                }
6981
                $extra_fields_to_show++;
6982
                $return .= '<option value="'.$field[0].'" '.$selected.'>'.$field[3].'</option>';
6983
            }
6984
        }
6985
        $return .= '</select>';
6986
6987
        // the form elements for the $_GET parameters (because the form is passed through GET
6988
        foreach ($_GET as $key=>$value) {
6989
            if ($key <> 'additional_profile_field') {
6990
                $return .= '<input type="hidden" name="'.Security::remove_XSS($key).'" value="'.Security::remove_XSS($value).'" />';
6991
            }
6992
        }
6993
        // the submit button
6994
        $return .= '<button class="save" type="submit">'.get_lang('AddAdditionalProfileField').'</button>';
6995
        $return .= '</form>';
6996
        if ($extra_fields_to_show > 0) {
6997
            return $return;
6998
        } else {
6999
            return '';
7000
        }
7001
    }
7002
7003
    /**
7004
     * This function gets all the information of a certrain ($field_id)
7005
     * additional profile field for a specific list of users is more efficent
7006
     * than get_addtional_profile_information_of_field() function
7007
     * It gets the information of all the users so that it can be displayed
7008
     * in the sortable table or in the csv or xls export
7009
     *
7010
     * @author    Julio Montoya <[email protected]>
7011
     * @param    int field id
7012
     * @param    array list of user ids
7013
     * @return    array
7014
     * @since    Nov 2009
7015
     * @version    1.8.6.2
7016
     */
7017
    public static function getAdditionalProfileInformationOfFieldByUser($field_id, $users)
7018
    {
7019
        // Database table definition
7020
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
7021
        $table_user_field_values = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
7022
        $extraField = Database::get_main_table(TABLE_EXTRA_FIELD);
7023
        $result_extra_field = UserManager::get_extra_field_information($field_id);
0 ignored issues
show
Deprecated Code introduced by
The function UserManager::get_extra_field_information() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

7023
        $result_extra_field = /** @scrutinizer ignore-deprecated */ UserManager::get_extra_field_information($field_id);
Loading history...
7024
        $return = [];
7025
        if (!empty($users)) {
7026
            if ($result_extra_field['field_type'] == UserManager::USER_FIELD_TYPE_TAG) {
7027
                foreach ($users as $user_id) {
7028
                    $user_result = UserManager::get_user_tags($user_id, $field_id);
7029
                    $tag_list = array();
7030
                    foreach ($user_result as $item) {
7031
                        $tag_list[] = $item['tag'];
7032
                    }
7033
                    $return[$user_id][] = implode(', ', $tag_list);
7034
                }
7035
            } else {
7036
                $new_user_array = array();
7037
                foreach ($users as $user_id) {
7038
                    $new_user_array[] = "'".$user_id."'";
7039
                }
7040
                $users = implode(',', $new_user_array);
7041
                $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
7042
                // Selecting only the necessary information NOT ALL the user list
7043
                $sql = "SELECT user.user_id, v.value
7044
                        FROM $table_user user
7045
                        INNER JOIN $table_user_field_values v
7046
                        ON (user.user_id = v.item_id)
7047
                        INNER JOIN $extraField f
7048
                        ON (f.id = v.field_id)
7049
                        WHERE
7050
                            f.extra_field_type = $extraFieldType AND
7051
                            v.field_id=".intval($field_id)." AND
7052
                            user.user_id IN ($users)";
7053
7054
                $result = Database::query($sql);
7055
                while ($row = Database::fetch_array($result)) {
7056
                    // get option value for field type double select by id
7057
                    if (!empty($row['value'])) {
7058
                        if ($result_extra_field['field_type'] ==
7059
                            ExtraField::FIELD_TYPE_DOUBLE_SELECT
7060
                        ) {
7061
                            $id_double_select = explode(';', $row['value']);
7062
                            if (is_array($id_double_select)) {
7063
                                $value1 = $result_extra_field['options'][$id_double_select[0]]['option_value'];
7064
                                $value2 = $result_extra_field['options'][$id_double_select[1]]['option_value'];
7065
                                $row['value'] = ($value1.';'.$value2);
7066
                            }
7067
                        }
7068
7069
                        if ($result_extra_field['field_type'] == ExtraField::FIELD_TYPE_SELECT_WITH_TEXT_FIELD) {
7070
                            $parsedValue = explode('::', $row['value']);
7071
7072
                            if ($parsedValue) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $parsedValue of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
7073
                                $value1 = $result_extra_field['options'][$parsedValue[0]]['display_text'];
7074
                                $value2 = $parsedValue[1];
7075
7076
                                $row['value'] = "$value1: $value2";
7077
                            }
7078
                        }
7079
7080
                        if ($result_extra_field['field_type'] == ExtraField::FIELD_TYPE_TRIPLE_SELECT) {
7081
                            list($level1, $level2, $level3) = explode(';', $row['value']);
7082
7083
                            $row['value'] = $result_extra_field['options'][$level1]['display_text'].' / ';
7084
                            $row['value'] .= $result_extra_field['options'][$level2]['display_text'].' / ';
7085
                            $row['value'] .= $result_extra_field['options'][$level3]['display_text'];
7086
                        }
7087
                    }
7088
                    // get other value from extra field
7089
                    $return[$row['user_id']][] = $row['value'];
7090
                }
7091
            }
7092
        }
7093
        return $return;
7094
    }
7095
7096
    /**
7097
     * count the number of students in this course (used for SortableTable)
7098
     * Deprecated
7099
     */
7100
    public function count_student_in_course()
7101
    {
7102
        global $nbStudents;
7103
        return $nbStudents;
7104
    }
7105
7106
    public function sort_users($a, $b)
7107
    {
7108
        $tracking = Session::read('tracking_column');
7109
        return strcmp(
7110
            trim(api_strtolower($a[$tracking])),
7111
            trim(api_strtolower($b[$tracking]))
7112
        );
7113
    }
7114
7115
    public function sort_users_desc($a, $b)
7116
    {
7117
        $tracking = Session::read('tracking_column');
7118
        return strcmp(
7119
            trim(api_strtolower($b[$tracking])),
7120
            trim(api_strtolower($a[$tracking]))
7121
        );
7122
    }
7123
7124
    /**
7125
     * Get number of users for sortable with pagination
7126
     * @return int
7127
     */
7128
    public static function get_number_of_users()
7129
    {
7130
        global $user_ids;
7131
        return count($user_ids);
7132
    }
7133
7134
    /**
7135
     * Get data for users list in sortable with pagination
7136
     * @param $from
7137
     * @param $number_of_items
7138
     * @param $column
7139
     * @param $direction
7140
     * @param $includeInvitedUsers boolean Whether include the invited users
7141
     * @return array
7142
     */
7143
    public static function get_user_data(
7144
        $from,
7145
        $number_of_items,
7146
        $column,
7147
        $direction,
7148
        $includeInvitedUsers = false
7149
    ) {
7150
        global $user_ids, $course_code, $export_csv, $csv_content, $session_id;
7151
7152
        $course_code = Database::escape_string($course_code);
7153
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
7154
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
7155
7156
        $access_url_id = api_get_current_access_url_id();
7157
7158
        // get all users data from a course for sortable with limit
7159
        if (is_array($user_ids)) {
7160
            $user_ids = array_map('intval', $user_ids);
7161
            $condition_user = " WHERE user.user_id IN (".implode(',', $user_ids).") ";
7162
        } else {
7163
            $user_ids = intval($user_ids);
7164
            $condition_user = " WHERE user.user_id = $user_ids ";
7165
        }
7166
7167
        if (!empty($_GET['user_keyword'])) {
7168
            $keyword = trim(Database::escape_string($_GET['user_keyword']));
7169
            $condition_user .= " AND (
7170
                user.firstname LIKE '%".$keyword."%' OR
7171
                user.lastname LIKE '%".$keyword."%'  OR
7172
                user.username LIKE '%".$keyword."%'  OR
7173
                user.email LIKE '%".$keyword."%'
7174
             ) ";
7175
        }
7176
7177
        $url_table = null;
7178
        $url_condition = null;
7179
        if (api_is_multiple_url_enabled()) {
7180
            $url_table = ", ".$tbl_url_rel_user." as url_users";
7181
            $url_condition = " AND user.user_id = url_users.user_id AND access_url_id='$access_url_id'";
7182
        }
7183
7184
        $invitedUsersCondition = '';
7185
        if (!$includeInvitedUsers) {
7186
            $invitedUsersCondition = " AND user.status != ".INVITEE;
7187
        }
7188
7189
        $sql = "SELECT  user.user_id as user_id,
7190
                    user.official_code  as col0,
7191
                    user.lastname       as col1,
7192
                    user.firstname      as col2,
7193
                    user.username       as col3
7194
                FROM $tbl_user as user $url_table
7195
                $condition_user $url_condition $invitedUsersCondition";
7196
7197
        if (!in_array($direction, array('ASC', 'DESC'))) {
7198
            $direction = 'ASC';
7199
        }
7200
7201
        $column = intval($column);
7202
        $from = intval($from);
7203
        $number_of_items = intval($number_of_items);
7204
7205
        $sql .= " ORDER BY col$column $direction ";
7206
        $sql .= " LIMIT $from,$number_of_items";
7207
7208
        $res = Database::query($sql);
7209
        $users = array();
7210
7211
        $course_info = api_get_course_info($course_code);
7212
        $total_surveys = 0;
7213
        $total_exercises = ExerciseLib::get_all_exercises(
7214
            $course_info,
7215
            $session_id,
7216
            false,
7217
            null,
7218
            false,
7219
            3
7220
        );
7221
7222
        if (empty($session_id)) {
7223
            $survey_user_list = array();
7224
            $survey_list = SurveyManager::get_surveys($course_code, $session_id);
7225
7226
            $total_surveys = count($survey_list);
7227
            foreach ($survey_list as $survey) {
7228
                $user_list = SurveyManager::get_people_who_filled_survey(
7229
                    $survey['survey_id'],
7230
                    false,
7231
                    $course_info['real_id']
7232
                );
7233
7234
                foreach ($user_list as $user_id) {
7235
                    isset($survey_user_list[$user_id]) ? $survey_user_list[$user_id]++ : $survey_user_list[$user_id] = 1;
7236
                }
7237
            }
7238
        }
7239
7240
        while ($user = Database::fetch_array($res, 'ASSOC')) {
7241
            $courseInfo = api_get_course_info($course_code);
7242
            $courseId = $courseInfo['real_id'];
7243
7244
            $user['official_code'] = $user['col0'];
7245
            $user['lastname'] = $user['col1'];
7246
            $user['firstname'] = $user['col2'];
7247
            $user['username'] = $user['col3'];
7248
7249
            $user['time'] = api_time_to_hms(
7250
                Tracking::get_time_spent_on_the_course(
7251
                    $user['user_id'],
7252
                    $courseId,
7253
                    $session_id
7254
                )
7255
            );
7256
7257
            $avg_student_score = Tracking::get_avg_student_score(
7258
                $user['user_id'],
7259
                $course_code,
7260
                array(),
7261
                $session_id
7262
            );
7263
7264
            $avg_student_progress = Tracking::get_avg_student_progress(
7265
                $user['user_id'],
7266
                $course_code,
7267
                array(),
7268
                $session_id
7269
            );
7270
7271
            if (empty($avg_student_progress)) {
7272
                $avg_student_progress = 0;
7273
            }
7274
            $user['average_progress'] = $avg_student_progress.'%';
7275
7276
            $total_user_exercise = Tracking::get_exercise_student_progress(
7277
                $total_exercises,
7278
                $user['user_id'],
7279
                $courseId,
7280
                $session_id
7281
            );
7282
7283
            $user['exercise_progress'] = $total_user_exercise;
7284
7285
            $total_user_exercise = Tracking::get_exercise_student_average_best_attempt(
7286
                $total_exercises,
7287
                $user['user_id'],
7288
                $courseId,
7289
                $session_id
7290
            );
7291
7292
            $user['exercise_average_best_attempt'] = $total_user_exercise;
7293
7294
            if (is_numeric($avg_student_score)) {
7295
                $user['student_score']  = $avg_student_score.'%';
7296
            } else {
7297
                $user['student_score']  = $avg_student_score;
7298
            }
7299
7300
            $user['count_assignments'] = Tracking::count_student_assignments(
7301
                $user['user_id'],
7302
                $course_code,
7303
                $session_id
7304
            );
7305
            $user['count_messages'] = Tracking::count_student_messages(
7306
                $user['user_id'],
7307
                $course_code,
7308
                $session_id
7309
            );
7310
            $user['first_connection'] = Tracking::get_first_connection_date_on_the_course(
7311
                $user['user_id'],
7312
                $courseId,
7313
                $session_id
7314
            );
7315
            $user['last_connection'] = Tracking::get_last_connection_date_on_the_course(
7316
                $user['user_id'],
7317
                $courseInfo,
7318
                $session_id,
7319
                $export_csv === false
7320
            );
7321
7322
            if (empty($session_id)) {
7323
                $user['survey'] = (isset($survey_user_list[$user['user_id']]) ? $survey_user_list[$user['user_id']] : 0).' / '.$total_surveys;
7324
            }
7325
7326
            $user['link'] = '<center>
7327
                             <a href="../mySpace/myStudents.php?student='.$user['user_id'].'&details=true&course='.$course_code.'&origin=tracking_course&id_session='.$session_id.'">
7328
                             '.Display::return_icon('2rightarrow.png', get_lang('Details')).'
7329
                             </a>
7330
                         </center>';
7331
7332
            // store columns in array $users
7333
            $is_western_name_order = api_is_western_name_order();
7334
            $user_row = array();
7335
            $user_row['official_code'] = $user['official_code']; //0
7336
            if ($is_western_name_order) {
7337
                $user_row['firstname'] = $user['firstname'];
7338
                $user_row['lastname'] = $user['lastname'];
7339
            } else {
7340
                $user_row['lastname'] = $user['lastname'];
7341
                $user_row['firstname'] = $user['firstname'];
7342
            }
7343
            $user_row['username'] = $user['username'];
7344
            $user_row['time'] = $user['time'];
7345
            $user_row['average_progress'] = $user['average_progress'];
7346
            $user_row['exercise_progress'] = $user['exercise_progress'];
7347
            $user_row['exercise_average_best_attempt'] = $user['exercise_average_best_attempt'];
7348
            $user_row['student_score'] = $user['student_score'];
7349
            $user_row['count_assignments'] = $user['count_assignments'];
7350
            $user_row['count_messages'] = $user['count_messages'];
7351
7352
            $userGroupManager = new UserGroup();
7353
            $user_row['classes'] = $userGroupManager->getLabelsFromNameList($user['user_id'], UserGroup::NORMAL_CLASS);
7354
7355
            if (empty($session_id)) {
7356
                $user_row['survey'] = $user['survey'];
7357
            }
7358
7359
            $user_row['first_connection'] = $user['first_connection'];
7360
            $user_row['last_connection'] = $user['last_connection'];
7361
7362
            // we need to display an additional profile field
7363
            if (isset($_GET['additional_profile_field'])) {
7364
                $data = Session::read('additional_user_profile_info');
7365
                $extraFieldInfo = Session::read('extra_field_info');
7366
                foreach ($_GET['additional_profile_field'] as $fieldId) {
7367
                    if (isset($data[$fieldId]) && isset($data[$fieldId][$user['user_id']])) {
7368
                        if (is_array($data[$fieldId][$user['user_id']])) {
7369
                            $user_row[$extraFieldInfo[$fieldId]['variable']] = implode(
7370
                                ', ',
7371
                                $data[$fieldId][$user['user_id']]
7372
                            );
7373
                        } else {
7374
                            $user_row[$extraFieldInfo[$fieldId]['variable']] = $data[$fieldId][$user['user_id']];
7375
                        }
7376
                    } else {
7377
                        $user_row[$extraFieldInfo[$fieldId]['variable']] = '';
7378
                    }
7379
                }
7380
            }
7381
7382
            $user_row['link'] = $user['link'];
7383
7384
            if ($export_csv) {
7385
                if (empty($session_id)) {
7386
                    unset($user_row['classes']);
7387
                    unset($user_row['link']);
7388
                } else {
7389
                    unset($user_row['classes']);
7390
                    unset($user_row['link']);
7391
                }
7392
7393
                $csv_content[] = $user_row;
7394
            }
7395
7396
            $users[] = array_values($user_row);
7397
        }
7398
7399
        Session::erase('additional_user_profile_info');
7400
        Session::erase('extra_field_info');
7401
7402
        return $users;
7403
    }
7404
7405
    /**
7406
     * Get data for users list in sortable with pagination
7407
     * @param $from
7408
     * @param $number_of_items
7409
     * @param $column
7410
     * @param $direction
7411
     * @param $includeInvitedUsers boolean Whether include the invited users
7412
     * @return array
7413
     */
7414
    public static function getTotalTimeReport(
7415
        $from,
7416
        $number_of_items,
7417
        $column,
7418
        $direction,
7419
        $includeInvitedUsers = false
7420
    ) {
7421
        global $user_ids, $course_code, $export_csv, $csv_content, $session_id;
7422
7423
        $course_code = Database::escape_string($course_code);
7424
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
7425
        $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
7426
        $access_url_id = api_get_current_access_url_id();
7427
7428
        // get all users data from a course for sortable with limit
7429
        if (is_array($user_ids)) {
7430
            $user_ids = array_map('intval', $user_ids);
7431
            $condition_user = " WHERE user.user_id IN (".implode(',', $user_ids).") ";
7432
        } else {
7433
            $user_ids = intval($user_ids);
7434
            $condition_user = " WHERE user.user_id = $user_ids ";
7435
        }
7436
7437
        $url_table = null;
7438
        $url_condition = null;
7439
        if (api_is_multiple_url_enabled()) {
7440
            $url_table = ", ".$tbl_url_rel_user." as url_users";
7441
            $url_condition = " AND user.user_id = url_users.user_id AND access_url_id='$access_url_id'";
7442
        }
7443
7444
        $invitedUsersCondition = '';
7445
        if (!$includeInvitedUsers) {
7446
            $invitedUsersCondition = " AND user.status != ".INVITEE;
7447
        }
7448
7449
        $sql = "SELECT  user.user_id as user_id,
7450
                    user.official_code  as col0,
7451
                    user.lastname       as col1,
7452
                    user.firstname      as col2,
7453
                    user.username       as col3
7454
                FROM $tbl_user as user $url_table
7455
                $condition_user $url_condition $invitedUsersCondition";
7456
7457
        if (!in_array($direction, array('ASC', 'DESC'))) {
7458
            $direction = 'ASC';
7459
        }
7460
7461
        $column = intval($column);
7462
        $from = intval($from);
7463
        $number_of_items = intval($number_of_items);
7464
7465
        $sql .= " ORDER BY col$column $direction ";
7466
        $sql .= " LIMIT $from,$number_of_items";
7467
7468
        $res = Database::query($sql);
7469
        $users = array();
7470
7471
        $course_info = api_get_course_info($course_code);
7472
7473
        while ($user = Database::fetch_array($res, 'ASSOC')) {
7474
            $courseInfo = api_get_course_info($course_code);
7475
            $courseId = $courseInfo['real_id'];
7476
7477
            $user['official_code'] = $user['col0'];
7478
            $user['lastname'] = $user['col1'];
7479
            $user['firstname'] = $user['col2'];
7480
            $user['username'] = $user['col3'];
7481
7482
            $totalCourseTime = Tracking::get_time_spent_on_the_course(
7483
                $user['user_id'],
7484
                $courseId,
7485
                $session_id
7486
            );
7487
7488
            $user['time'] = api_time_to_hms($totalCourseTime);
7489
            $totalLpTime = Tracking::get_time_spent_in_lp(
7490
                $user['user_id'],
7491
                $course_code,
7492
                array(),
7493
                $session_id
7494
            );
7495
7496
            $user['total_lp_time'] = $totalLpTime;
7497
            $warning = '';
7498
            if ($totalLpTime > $totalCourseTime) {
7499
                $warning = '&nbsp;'.Display::label(get_lang('TimeDifference'), 'danger');
7500
            }
7501
7502
            $user['total_lp_time'] = api_time_to_hms($totalLpTime).$warning;
7503
7504
            $user['first_connection'] = Tracking::get_first_connection_date_on_the_course(
7505
                $user['user_id'],
7506
                $courseId,
7507
                $session_id
7508
            );
7509
            $user['last_connection'] = Tracking::get_last_connection_date_on_the_course(
7510
                $user['user_id'],
7511
                $courseInfo,
7512
                $session_id,
7513
                $export_csv === false
7514
            );
7515
7516
            $user['link'] = '<center>
7517
                             <a href="../mySpace/myStudents.php?student='.$user['user_id'].'&details=true&course='.$course_code.'&origin=tracking_course&id_session='.$session_id.'">
7518
                             '.Display::return_icon('2rightarrow.png', get_lang('Details')).'
7519
                             </a>
7520
                         </center>';
7521
7522
            // store columns in array $users
7523
            $is_western_name_order = api_is_western_name_order();
7524
            $user_row = array();
7525
            $user_row['official_code'] = $user['official_code']; //0
7526
            if ($is_western_name_order) {
7527
                $user_row['firstname'] = $user['firstname'];
7528
                $user_row['lastname'] = $user['lastname'];
7529
            } else {
7530
                $user_row['lastname'] = $user['lastname'];
7531
                $user_row['firstname'] = $user['firstname'];
7532
            }
7533
            $user_row['username'] = $user['username'];
7534
            $user_row['time'] = $user['time'];
7535
            $user_row['total_lp_time'] = $user['total_lp_time'];
7536
            $user_row['first_connection'] = $user['first_connection'];
7537
            $user_row['last_connection'] = $user['last_connection'];
7538
7539
            $user_row['link'] = $user['link'];
7540
            $users[] = array_values($user_row);
7541
        }
7542
7543
        return $users;
7544
    }
7545
7546
    /**
7547
     * @param string $current
7548
     */
7549
    public static function actionsLeft($current, $sessionId = 0)
7550
    {
7551
        $usersLink = Display::url(
7552
            Display::return_icon('user.png', get_lang('StudentsTracking'), array(), ICON_SIZE_MEDIUM),
7553
            'courseLog.php?'.api_get_cidreq(true, false)
7554
        );
7555
7556
        $groupsLink = Display::url(
7557
            Display::return_icon('group.png', get_lang('GroupReporting'), array(), ICON_SIZE_MEDIUM),
7558
            'course_log_groups.php?'.api_get_cidreq()
7559
        );
7560
7561
        $resourcesLink = Display::url(
7562
            Display::return_icon('tools.png', get_lang('ResourcesTracking'), array(), ICON_SIZE_MEDIUM),
7563
            'course_log_resources.php?'.api_get_cidreq(true, false)
7564
        );
7565
7566
        $courseLink = Display::url(
7567
            Display::return_icon('course.png', get_lang('CourseTracking'), array(), ICON_SIZE_MEDIUM),
7568
            'course_log_tools.php?'.api_get_cidreq(true, false)
7569
        );
7570
7571
        $examLink = Display::url(
7572
            Display::return_icon('quiz.png', get_lang('ExamTracking'), array(), ICON_SIZE_MEDIUM),
7573
            api_get_path(WEB_CODE_PATH).'tracking/exams.php?'.api_get_cidreq()
7574
        );
7575
7576
        $eventsLink = Display::url(
7577
            Display::return_icon('security.png', get_lang('EventsReport'), array(), ICON_SIZE_MEDIUM),
7578
            api_get_path(WEB_CODE_PATH).'tracking/course_log_events.php?'.api_get_cidreq()
7579
        );
7580
7581
        $attendanceLink = '';
7582
        if (!empty($sessionId)) {
7583
            $attendanceLink = Display::url(
7584
                Display::return_icon('attendance_list.png', get_lang('Logins'), '', ICON_SIZE_MEDIUM),
7585
                api_get_path(WEB_CODE_PATH).'attendance/index.php?'.api_get_cidreq().'&action=calendar_logins'
7586
            );
7587
        }
7588
7589
        switch ($current) {
7590
            case 'users':
7591
                $usersLink = Display::url(
7592
                        Display::return_icon(
7593
                        'user_na.png',
7594
                        get_lang('StudentsTracking'),
7595
                        array(),
7596
                        ICON_SIZE_MEDIUM
7597
                    ),
7598
                    '#'
7599
                );
7600
                break;
7601
            case 'groups':
7602
                $groupsLink = Display::url(
7603
                    Display::return_icon('group_na.png', get_lang('GroupReporting'), array(), ICON_SIZE_MEDIUM),
7604
                    '#'
7605
                );
7606
                break;
7607
            case 'courses':
7608
                $courseLink = Display::url(
7609
                    Display::return_icon('course_na.png', get_lang('CourseTracking'), array(), ICON_SIZE_MEDIUM),
7610
                    '#'
7611
                );
7612
                break;
7613
            case 'resources':
7614
                $resourcesLink = Display::url(
7615
                    Display::return_icon(
7616
                    'tools_na.png',
7617
                    get_lang('ResourcesTracking'),
7618
                    array(),
7619
                    ICON_SIZE_MEDIUM
7620
                    ), '#'
7621
                );
7622
                break;
7623
            case 'exams':
7624
                $examLink = Display::url(
7625
                    Display::return_icon('quiz_na.png', get_lang('ExamTracking'), array(), ICON_SIZE_MEDIUM),
7626
                    '#'
7627
                );
7628
                break;
7629
            case 'logs':
7630
                $eventsLink = Display::url(
7631
                    Display::return_icon('security_na.png', get_lang('EventsReport'), array(), ICON_SIZE_MEDIUM),
7632
                    '#'
7633
                );
7634
                break;
7635
            case 'attendance':
7636
                if (!empty($sessionId)) {
7637
                    $attendanceLink = Display::url(
7638
                        Display::return_icon('attendance_list.png', get_lang('Logins'), '', ICON_SIZE_MEDIUM),
7639
                        '#'
7640
                    );
7641
                }
7642
                break;
7643
        }
7644
7645
        $items = [
7646
            $usersLink,
7647
            $groupsLink,
7648
            $courseLink,
7649
            $resourcesLink,
7650
            $examLink,
7651
            $eventsLink,
7652
            $attendanceLink
7653
        ];
7654
7655
        return implode('', $items).'&nbsp;';
7656
    }
7657
}
7658