Completed
Push — master ( 27e209...a08afa )
by Julito
186:04 queued 150:53
created

TrackingCourseLog::get_item_resources_data()   F

Complexity

Conditions 41
Paths > 20000

Size

Total Lines 251
Code Lines 172

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 41
eloc 172
nc 145344
nop 4
dl 0
loc 251
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use 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 = []
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 = []

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

4760
                $user_count = count(/** @scrutinizer ignore-type */ SessionManager::get_users_by_session($my_session_id));
Loading history...
4761
                $exercise_graph_name_list = [];
4762
                $exercise_graph_list = [];
4763
4764
                foreach ($course_list as $course_data) {
4765
                    $exercise_list = ExerciseLib::get_all_exercises(
4766
                        $course_data,
4767
                        $my_session_id,
4768
                        false,
4769
                        null,
4770
                        false,
4771
                        1
4772
                    );
4773
4774
                    foreach ($exercise_list as $exercise_data) {
4775
                        $exercise_obj = new Exercise($course_data['real_id']);
4776
                        $exercise_obj->read($exercise_data['id']);
4777
                        // Exercise is not necessary to be visible to show results check the result_disable configuration instead
4778
                        //$visible_return = $exercise_obj->is_visible();
4779
                        if ($exercise_data['results_disabled'] == 0 || $exercise_data['results_disabled'] == 2) {
4780
                            $best_average = intval(
4781
                                ExerciseLib::get_best_average_score_by_exercise(
4782
                                    $exercise_data['id'],
4783
                                    $course_data['real_id'],
4784
                                    $my_session_id,
4785
                                    $user_count
4786
                                )
4787
                            );
4788
4789
                            $exercise_graph_list[] = $best_average;
4790
                            $all_exercise_graph_list[] = $best_average;
4791
4792
                            $user_result_data = ExerciseLib::get_best_attempt_by_user(
4793
                                api_get_user_id(),
4794
                                $exercise_data['id'],
4795
                                $course_data['real_id'],
4796
                                $my_session_id
4797
                            );
4798
4799
                            $score = 0;
4800
                            if (!empty($user_result_data['exe_weighting']) && intval($user_result_data['exe_weighting']) != 0) {
4801
                                $score = intval($user_result_data['exe_result'] / $user_result_data['exe_weighting'] * 100);
4802
                            }
4803
                            $time = api_strtotime($exercise_data['start_time']) ? api_strtotime($exercise_data['start_time'], 'UTC') : 0;
4804
                            $all_exercise_start_time[] = $time;
4805
                            $my_results[] = $score;
4806
                            if (count($exercise_list) <= 10) {
4807
                                $title = cut($course_data['title'], 30)." \n ".cut($exercise_data['title'], 30);
4808
                                $exercise_graph_name_list[] = $title;
4809
                                $all_exercise_graph_name_list[] = $title;
4810
                            } else {
4811
                                // if there are more than 10 results, space becomes difficult to find,
4812
                                // so only show the title of the exercise, not the tool
4813
                                $title = cut($exercise_data['title'], 30);
4814
                                $exercise_graph_name_list[] = $title;
4815
                                $all_exercise_graph_name_list[] = $title;
4816
                            }
4817
                        }
4818
                    }
4819
                }
4820
            }
4821
4822
            // Complete graph
4823
            if (!empty($my_results) && !empty($all_exercise_graph_list)) {
4824
                asort($all_exercise_start_time);
4825
4826
                //Fix exams order
4827
                $final_all_exercise_graph_name_list = [];
4828
                $my_results_final = [];
4829
                $final_all_exercise_graph_list = [];
4830
4831
                foreach ($all_exercise_start_time as $key => $time) {
4832
                    $label_time = '';
4833
                    if (!empty($time)) {
4834
                        $label_time = date('d-m-y', $time);
4835
                    }
4836
                    $final_all_exercise_graph_name_list[] = $all_exercise_graph_name_list[$key].' '.$label_time;
4837
                    $my_results_final[] = $my_results[$key];
4838
                    $final_all_exercise_graph_list[] = $all_exercise_graph_list[$key];
4839
                }
4840
                $main_session_graph = self::generate_session_exercise_graph(
4841
                    $final_all_exercise_graph_name_list,
4842
                    $my_results_final,
4843
                    $final_all_exercise_graph_list
4844
                );
4845
            }
4846
4847
            $sessionIcon = Display::return_icon(
4848
                'session.png',
4849
                get_lang('Sessions'),
4850
                [],
4851
                ICON_SIZE_SMALL
4852
            );
4853
4854
            $anchor = Display::url('', '', ['name' => 'course_session_header']);
4855
            $html .= $anchor.Display::page_subheader(
4856
                $sessionIcon.' '.get_lang('Sessions')
4857
            );
4858
4859
            $html .= '<div class="table-responsive">';
4860
            $html .= '<table class="table table-striped table-hover">';
4861
            $html .= '<thead>';
4862
            $html .= '<tr>
4863
                  '.Display::tag('th', get_lang('Session'), ['width'=>'300px']).'
4864
                  '.Display::tag('th', get_lang('PublishedExercises'), ['width'=>'300px']).'
4865
                  '.Display::tag('th', get_lang('NewExercises')).'
4866
                  '.Display::tag('th', get_lang('AverageExerciseResult')).'
4867
                  '.Display::tag('th', get_lang('Details')).'
4868
                  </tr>';
4869
            $html .= '</thead>';
4870
            $html .= '<tbody>';
4871
4872
            foreach ($course_in_session as $my_session_id => $session_data) {
4873
                $course_list = $session_data['course_list'];
4874
                $session_name = $session_data['name'];
4875
                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...
4876
                    if (isset($session_id) && !empty($session_id)) {
4877
                        if ($session_id != $my_session_id) {
4878
                            continue;
4879
                        }
4880
                    }
4881
                }
4882
4883
                $all_exercises = 0;
4884
                $all_unanswered_exercises_by_user = 0;
4885
                $all_average = 0;
4886
                $stats_array = [];
4887
4888
                foreach ($course_list as $course_data) {
4889
                    // All exercises in the course @todo change for a real count
4890
                    $exercises = ExerciseLib::get_all_exercises($course_data, $my_session_id);
4891
                    $count_exercises = 0;
4892
                    if (is_array($exercises) && !empty($exercises)) {
4893
                        $count_exercises = count($exercises);
4894
                    }
4895
4896
                    // Count of user results
4897
                    $done_exercises = null;
4898
                    $courseInfo = api_get_course_info($course_data['code']);
4899
4900
                    $answered_exercises = 0;
4901
                    if (!empty($exercises)) {
4902
                        foreach ($exercises as $exercise_item) {
4903
                            $attempts = Event::count_exercise_attempts_by_user(
4904
                                api_get_user_id(),
4905
                                $exercise_item['id'],
4906
                                $courseInfo['real_id'],
4907
                                $my_session_id
4908
                            );
4909
                            if ($attempts > 1) {
4910
                                $answered_exercises++;
4911
                            }
4912
                        }
4913
                    }
4914
4915
                    // Average
4916
                    $average = ExerciseLib::get_average_score_by_course(
4917
                        $courseInfo['real_id'],
4918
                        $my_session_id
4919
                    );
4920
                    $all_exercises += $count_exercises;
4921
                    $all_unanswered_exercises_by_user += $count_exercises - $answered_exercises;
4922
                    $all_average += $average;
4923
                }
4924
4925
                if (!empty($course_list)) {
4926
                    $all_average = $all_average / count($course_list);
4927
                }
4928
4929
                if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) {
4930
                    $html .= '<tr style="background-color:#FBF09D">';
4931
                } else {
4932
                    $html .= '<tr>';
4933
                }
4934
                $url = api_get_path(WEB_CODE_PATH)."session/index.php?session_id={$my_session_id}";
4935
4936
                $html .= Display::tag('td', Display::url($session_name, $url, ['target'=>SESSION_LINK_TARGET]));
4937
                $html .= Display::tag('td', $all_exercises);
4938
                $html .= Display::tag('td', $all_unanswered_exercises_by_user);
4939
                $html .= Display::tag('td', ExerciseLib::convert_to_percentage($all_average));
4940
4941
                if (isset($_GET['session_id']) && $my_session_id == $_GET['session_id']) {
4942
                    $icon = Display::url(
4943
                        Display::return_icon(
4944
                            '2rightarrow_na.png',
4945
                            get_lang('Details')
4946
                        ),
4947
                        api_get_self().'?session_id='.$my_session_id.'#course_session_list'
4948
                    );
4949
                } else {
4950
                    $icon = Display::url(
4951
                        Display::return_icon(
4952
                            '2rightarrow.png',
4953
                            get_lang('Details')
4954
                        ),
4955
                        api_get_self().'?session_id='.$my_session_id.'#course_session_list'
4956
                    );
4957
                }
4958
                $html .= Display::tag('td', $icon);
4959
                $html .= '</tr>';
4960
            }
4961
            $html .= '</tbody>';
4962
            $html .= '</table></div><br />';
4963
            $html .= Display::div(
4964
                $main_session_graph,
4965
                [
4966
                    'id' => 'session_graph',
4967
                    'class' => 'chart-session',
4968
                    'style' => 'position:relative; text-align: center;',
4969
                ]
4970
            );
4971
4972
            // Checking selected session.
4973
            if (isset($_GET['session_id'])) {
4974
                $session_id_from_get = intval($_GET['session_id']);
4975
                $session_data = $course_in_session[$session_id_from_get];
4976
                $course_list = $session_data['course_list'];
4977
4978
                $html .= '<a name= "course_session_list"></a>';
4979
                $html .= Display::tag('h3', $session_data['name'].' - '.get_lang('CourseList'));
4980
4981
                $html .= '<div class="table-responsive">';
4982
                $html .= '<table class="table table-hover table-striped">';
4983
4984
                $columnHeaders = [
4985
                    'course_title' => [
4986
                        get_lang('Course'),
4987
                        ['width'=>'300px']
4988
                    ],
4989
                    'published_exercises' => [
4990
                        get_lang('PublishedExercises')
4991
                    ],
4992
                    'new_exercises' => [
4993
                        get_lang('NewExercises'),
4994
                    ],
4995
                    'my_average' => [
4996
                        get_lang('MyAverage'),
4997
                    ],
4998
                    'average_exercise_result'  => [
4999
                        get_lang('AverageExerciseResult'),
5000
                    ],
5001
                    'time_spent'  => [
5002
                        get_lang('TimeSpentInTheCourse'),
5003
                    ],
5004
                    'lp_progress'  => [
5005
                        get_lang('LPProgress'),
5006
                    ],
5007
                    'score'  => [
5008
                        get_lang('Score').
5009
                        Display::return_icon(
5010
                            'info3.gif',
5011
                            get_lang('ScormAndLPTestTotalAverage'),
5012
                            ['align' => 'absmiddle', 'hspace' => '3px']
5013
                        ),
5014
                    ],
5015
                    'best_score'  => [
5016
                        get_lang('BestScore'),
5017
                    ],
5018
                    'last_connection'  => [
5019
                        get_lang('LastConnexion'),
5020
                    ],
5021
                    'details'  => [
5022
                        get_lang('Details'),
5023
                    ],
5024
                ];
5025
5026
                $html .= '<thead><tr>';
5027
                foreach ($columnHeaders as $key => $columnSetting) {
5028
                    if (isset($trackingColumns['course_session']) &&
5029
                        in_array($key, $trackingColumns['course_session']) &&
5030
                        $trackingColumns['course_session'][$key]
5031
                    ) {
5032
                        $settings = isset($columnSetting[1]) ? $columnSetting[1] : [];
5033
                        $html .= Display::tag(
5034
                             'th',
5035
                             $columnSetting[0],
5036
                             $settings
5037
                         );
5038
                    }
5039
                }
5040
5041
                $html .= '</tr>
5042
                    </thead>
5043
                    <tbody>';
5044
5045
                foreach ($course_list as $course_data) {
5046
                    $course_code = $course_data['code'];
5047
                    $course_title = $course_data['title'];
5048
                    $courseId = $course_data['real_id'];
5049
5050
                    // All exercises in the course @todo change for a real count
5051
                    $exercises = ExerciseLib::get_all_exercises(
5052
                        $course_data,
5053
                        $session_id_from_get
5054
                    );
5055
                    $count_exercises = 0;
5056
                    if (!empty($exercises)) {
5057
                        $count_exercises = count($exercises);
5058
                    }
5059
                    $answered_exercises = 0;
5060
                    foreach ($exercises as $exercise_item) {
5061
                        $attempts = Event::count_exercise_attempts_by_user(
5062
                            api_get_user_id(),
5063
                            $exercise_item['id'],
5064
                            $courseId,
5065
                            $session_id_from_get
5066
                        );
5067
                        if ($attempts > 1) {
5068
                            $answered_exercises++;
5069
                        }
5070
                    }
5071
5072
                    $unanswered_exercises = $count_exercises - $answered_exercises;
5073
5074
                    // Average
5075
                    $average = ExerciseLib::get_average_score_by_course(
5076
                        $courseId,
5077
                        $session_id_from_get
5078
                    );
5079
                    $my_average = ExerciseLib::get_average_score_by_course_by_user(
5080
                        api_get_user_id(),
5081
                        $courseId,
5082
                        $session_id_from_get
5083
                    );
5084
5085
                    $bestScore = self::get_avg_student_score(
5086
                        $user_id,
5087
                        $course_code,
5088
                        [],
5089
                        $session_id_from_get,
5090
                        false,
5091
                        false,
5092
                        true
5093
                    );
5094
5095
                    $stats_array[$course_code] = [
5096
                        'exercises' => $count_exercises,
5097
                        'unanswered_exercises_by_user' => $unanswered_exercises,
5098
                        '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...
5099
                        'average' => $average,
5100
                        'my_average' => $my_average,
5101
                        'best_score' => $bestScore
5102
                    ];
5103
5104
                    $last_connection = self::get_last_connection_date_on_the_course(
5105
                        $user_id,
5106
                        $course_data,
5107
                        $session_id_from_get
5108
                    );
5109
5110
                    $progress = self::get_avg_student_progress(
5111
                        $user_id,
5112
                        $course_code,
5113
                        [],
5114
                        $session_id_from_get
5115
                    );
5116
5117
                    $total_time_login = self::get_time_spent_on_the_course(
5118
                        $user_id,
5119
                        $courseId,
5120
                        $session_id_from_get
5121
                    );
5122
                    $time = api_time_to_hms($total_time_login);
5123
5124
                    $percentage_score = self::get_avg_student_score(
5125
                        $user_id,
5126
                        $course_code,
5127
                        [],
5128
                        $session_id_from_get
5129
                    );
5130
                    $courseCodeFromGet = isset($_GET['course']) ? $_GET['course'] : null;
5131
5132
                    if ($course_code == $courseCodeFromGet && $_GET['session_id'] == $session_id_from_get) {
5133
                        $html .= '<tr class="row_odd" style="background-color:#FBF09D" >';
5134
                    } else {
5135
                        $html .= '<tr class="row_even">';
5136
                    }
5137
5138
                    $url = api_get_course_url($course_code, $session_id_from_get);
5139
                    $course_url = Display::url(
5140
                        $course_title,
5141
                        $url,
5142
                        ['target' => SESSION_LINK_TARGET]
5143
                    );
5144
5145
                    if (is_numeric($progress)) {
5146
                        $progress = $progress.'%';
5147
                    } else {
5148
                        $progress = '0%';
5149
                    }
5150
                    if (is_numeric($percentage_score)) {
5151
                        $percentage_score = $percentage_score.'%';
5152
                    } else {
5153
                        $percentage_score = '0%';
5154
                    }
5155
5156
                    if (is_numeric($stats_array[$course_code]['best_score'])) {
5157
                        $bestScore = $stats_array[$course_code]['best_score'].'%';
5158
                    } else {
5159
                        $bestScore = '-';
5160
                    }
5161
5162
                    if (empty($last_connection) || is_bool($last_connection)) {
5163
                        $last_connection = '';
5164
                    }
5165
5166
                    if ($course_code == $courseCodeFromGet &&
5167
                        $_GET['session_id'] == $session_id_from_get
5168
                    ) {
5169
                        $details = Display::url(
5170
                            Display::return_icon('2rightarrow_na.png', get_lang('Details')),
5171
                        '#course_session_data'
5172
                        );
5173
                    } else {
5174
                        $url = api_get_self().'?course='.$course_code.'&session_id='.$session_id_from_get.$extra_params.'#course_session_data';
5175
                        $details = Display::url(
5176
                            Display::return_icon(
5177
                                '2rightarrow.png',
5178
                                get_lang('Details')
5179
                            ),
5180
                            $url
5181
                        );
5182
                    }
5183
                    $details .= '</a>';
5184
5185
                    $data = [
5186
                        'course_title' => $course_url,
5187
                        'published_exercises' => $stats_array[$course_code]['exercises'], // exercise available
5188
                        'new_exercises' => $stats_array[$course_code]['unanswered_exercises_by_user'],
5189
                        'my_average' => ExerciseLib::convert_to_percentage($stats_array[$course_code]['my_average']),
5190
                        'average_exercise_result' => $stats_array[$course_code]['average'] == 0 ? '-' : '('.ExerciseLib::convert_to_percentage($stats_array[$course_code]['average']).')',
5191
                        'time_spent' => $time,
5192
                        'lp_progress' => $progress,
5193
                        'score' => $percentage_score,
5194
                        'best_score' => $bestScore,
5195
                        'last_connection' => $last_connection,
5196
                        'details' => $details,
5197
                    ];
5198
5199
                    foreach ($data as $key => $value) {
5200
                        if (in_array($key, $trackingColumns['course_session'])
5201
                            && $trackingColumns['course_session'][$key]
5202
                        ) {
5203
                            $html .= Display::tag('td', $value);
5204
                        }
5205
                    }
5206
                    $html .= '</tr>';
5207
                }
5208
                $html .= '</tbody></table></div>';
5209
            }
5210
        }
5211
5212
        return $html;
5213
    }
5214
5215
    /**
5216
     * Shows the user detail progress (when clicking in the details link)
5217
     * @param   int     $user_id
5218
     * @param   string  $course_code
5219
     * @param   int     $session_id
5220
     * @return  string  html code
5221
     */
5222
    public static function show_course_detail($user_id, $course_code, $session_id)
5223
    {
5224
        $html = '';
5225
        if (isset($course_code)) {
5226
            $user_id = intval($user_id);
5227
            $session_id = intval($session_id);
5228
            $course = Database::escape_string($course_code);
5229
            $course_info = api_get_course_info($course);
5230
            if (empty($course_info)) {
5231
                return '';
5232
            }
5233
5234
            $html .= '<a name="course_session_data"></a>';
5235
            $html .= Display::page_subheader($course_info['title']);
5236
            $html .= '<div class="table-responsive">';
5237
            $html .= '<table class="table table-striped table-hover">';
5238
5239
            //Course details
5240
            $html .= '
5241
                <thead>
5242
                <tr>
5243
                <th>'.get_lang('Exercises').'</th>
5244
                <th>'.get_lang('Attempts').'</th>
5245
                <th>'.get_lang('BestAttempt').'</th>
5246
                <th>'.get_lang('Ranking').'</th>
5247
                <th>'.get_lang('BestResultInCourse').'</th>
5248
                <th>'.get_lang('Statistics').' '.Display::return_icon('info3.gif', get_lang('OnlyBestResultsPerStudent'), ['align' => 'absmiddle', 'hspace' => '3px']).'</th>
5249
                </tr>
5250
                </thead>
5251
                <tbody>';
5252
5253
            if (empty($session_id)) {
5254
                $user_list = CourseManager::get_user_list_from_course_code(
5255
                    $course,
5256
                    $session_id,
5257
                    null,
5258
                    null,
5259
                    STUDENT
5260
                );
5261
            } else {
5262
                $user_list = CourseManager::get_user_list_from_course_code(
5263
                    $course,
5264
                    $session_id,
5265
                    null,
5266
                    null,
5267
                    0
5268
                );
5269
            }
5270
5271
            // Show exercise results of invisible exercises? see BT#4091
5272
            $exercise_list = ExerciseLib::get_all_exercises(
5273
                $course_info,
5274
                $session_id,
5275
                false,
5276
                null,
5277
                false,
5278
                2
5279
            );
5280
5281
            $to_graph_exercise_result = [];
5282
            if (!empty($exercise_list)) {
5283
                $score = $weighting = $exe_id = 0;
5284
                foreach ($exercise_list as $exercices) {
5285
                    $exercise_obj = new Exercise($course_info['real_id']);
5286
                    $exercise_obj->read($exercices['id']);
5287
                    $visible_return = $exercise_obj->is_visible();
5288
                    $score = $weighting = $attempts = 0;
5289
5290
                    // Getting count of attempts by user
5291
                    $attempts = Event::count_exercise_attempts_by_user(
5292
                        api_get_user_id(),
5293
                        $exercices['id'],
5294
                        $course_info['real_id'],
5295
                        $session_id
5296
                    );
5297
5298
                    $html .= '<tr class="row_even">';
5299
                    $url = api_get_path(WEB_CODE_PATH)."exercise/overview.php?cidReq={$course_info['code']}&id_session=$session_id&exerciseId={$exercices['id']}";
5300
5301
                    if ($visible_return['value'] == true) {
5302
                        $exercices['title'] = Display::url(
5303
                            $exercices['title'],
5304
                            $url,
5305
                            ['target' => SESSION_LINK_TARGET]
5306
                        );
5307
                    } elseif ($exercices['active'] == -1) {
5308
                        $exercices['title'] = sprintf(get_lang('XParenthesisDeleted'), $exercices['title']);
5309
                    }
5310
5311
                    $html .= Display::tag('td', $exercices['title']);
5312
5313
                    // Exercise configuration show results or show only score
5314
                    if ($exercices['results_disabled'] == 0 || $exercices['results_disabled'] == 2) {
5315
                        //For graphics
5316
                        $best_exercise_stats = Event::get_best_exercise_results_by_user(
5317
                            $exercices['id'],
5318
                            $course_info['real_id'],
5319
                            $session_id
5320
                        );
5321
5322
                        $to_graph_exercise_result[$exercices['id']] = [
5323
                            'title' => $exercices['title'],
5324
                            'data' => $best_exercise_stats
5325
                        ];
5326
5327
                        $latest_attempt_url = '';
5328
                        $best_score = $position = $percentage_score_result = '-';
5329
                        $graph = $normal_graph = null;
5330
5331
                        // Getting best results
5332
                        $best_score_data = ExerciseLib::get_best_attempt_in_course(
5333
                            $exercices['id'],
5334
                            $course_info['real_id'],
5335
                            $session_id
5336
                        );
5337
5338
                        $best_score = '';
5339
                        if (!empty($best_score_data)) {
5340
                            $best_score = ExerciseLib::show_score(
5341
                                $best_score_data['exe_result'],
5342
                                $best_score_data['exe_weighting']
5343
                            );
5344
                        }
5345
5346
                        if ($attempts > 0) {
5347
                            $exercise_stat = ExerciseLib::get_best_attempt_by_user(
5348
                                api_get_user_id(),
5349
                                $exercices['id'],
5350
                                $course_info['real_id'],
5351
                                $session_id
5352
                            );
5353
                            if (!empty($exercise_stat)) {
5354
                                // Always getting the BEST attempt
5355
                                $score = $exercise_stat['exe_result'];
5356
                                $weighting = $exercise_stat['exe_weighting'];
5357
                                $exe_id = $exercise_stat['exe_id'];
5358
5359
                                $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;
5360
                                $percentage_score_result = Display::url(
5361
                                    ExerciseLib::show_score($score, $weighting),
5362
                                    $latest_attempt_url
5363
                                );
5364
                                $my_score = 0;
5365
                                if (!empty($weighting) && intval($weighting) != 0) {
5366
                                    $my_score = $score / $weighting;
5367
                                }
5368
                                //@todo this function slows the page
5369
                                if (is_int($user_list)) {
5370
                                    $user_list = [$user_list];
5371
                                }
5372
                                $position = ExerciseLib::get_exercise_result_ranking(
5373
                                    $my_score,
5374
                                    $exe_id,
5375
                                    $exercices['id'],
5376
                                    $course_info['code'],
5377
                                    $session_id,
5378
                                    $user_list
5379
                                );
5380
5381
                                $graph = self::generate_exercise_result_thumbnail_graph(
5382
                                    $to_graph_exercise_result[$exercices['id']]
5383
                                );
5384
                                $normal_graph = self::generate_exercise_result_graph(
5385
                                    $to_graph_exercise_result[$exercices['id']]
5386
                                );
5387
                            }
5388
                        }
5389
                        $html .= Display::div(
5390
                            $normal_graph,
5391
                            [
5392
                                'id' => 'main_graph_'.$exercices['id'],
5393
                                'class' => 'dialog',
5394
                                'style' => 'display:none'
5395
                            ]
5396
                        );
5397
5398
                        if (empty($graph)) {
5399
                            $graph = '-';
5400
                        } else {
5401
                            $graph = Display::url(
5402
                                '<img src="'.$graph.'" >',
5403
                                $normal_graph,
5404
                                [
5405
                                    'id' => $exercices['id'],
5406
                                    'class' => 'expand-image',
5407
                                ]
5408
                            );
5409
                        }
5410
5411
                        $html .= Display::tag('td', $attempts);
5412
                        $html .= Display::tag('td', $percentage_score_result);
5413
                        $html .= Display::tag('td', $position);
5414
                        $html .= Display::tag('td', $best_score);
5415
                        $html .= Display::tag('td', $graph);
5416
                        //$html .= Display::tag('td', $latest_attempt_url,       array('align'=>'center', 'width'=>'25'));
5417
                    } else {
5418
                        // Exercise configuration NO results
5419
                        $html .= Display::tag('td', $attempts);
5420
                        $html .= Display::tag('td', '-');
5421
                        $html .= Display::tag('td', '-');
5422
                        $html .= Display::tag('td', '-');
5423
                        $html .= Display::tag('td', '-');
5424
                    }
5425
                    $html .= '</tr>';
5426
                }
5427
            } else {
5428
                $html .= '<tr><td colspan="5">'.get_lang('NoEx').'</td></tr>';
5429
            }
5430
            $html .= '</tbody></table></div>';
5431
5432
            $columnHeaders = [
5433
                'lp' => get_lang('LearningPath'),
5434
                'time' => get_lang('LatencyTimeSpent'),
5435
                'progress' => get_lang('Progress'),
5436
                'score' => get_lang('Score'),
5437
                'best_score' => get_lang('BestScore'),
5438
                'last_connection' => get_lang('LastConnexion'),
5439
            ];
5440
5441
            $headers = '';
5442
            $trackingColumns = api_get_configuration_value('tracking_columns');
5443
            if (isset($trackingColumns['my_progress_lp'])) {
5444
                foreach ($columnHeaders as $key => $value) {
5445
                    if (!isset($trackingColumns['my_progress_lp'][$key]) ||
5446
                        $trackingColumns['my_progress_lp'][$key] == false
5447
                    ) {
5448
                        unset($columnHeaders[$key]);
5449
                    }
5450
                }
5451
            }
5452
5453
            $columnHeadersKeys = array_keys($columnHeaders);
5454
            foreach ($columnHeaders as $key => $columnName) {
5455
                $headers .= Display::tag(
5456
                    'th',
5457
                    $columnName
5458
                );
5459
            }
5460
5461
            // LP table results
5462
            $html .= '<div class="table-responsive">';
5463
            $html .= '<table class="table table-striped table-hover">';
5464
            $html .= '<thead><tr>';
5465
            $html .= $headers;
5466
            $html .= '</tr></thead><tbody>';
5467
5468
            $list = new LearnpathList(
5469
                api_get_user_id(),
5470
                $course_info['code'],
5471
                $session_id,
5472
                'lp.publicatedOn ASC',
5473
                true,
5474
                null,
5475
                true
5476
            );
5477
5478
            $lp_list = $list->get_flat_list();
5479
5480
            if (!empty($lp_list) > 0) {
5481
                foreach ($lp_list as $lp_id => $learnpath) {
5482
                    $progress = self::get_avg_student_progress(
5483
                        $user_id,
5484
                        $course,
5485
                        [$lp_id],
5486
                        $session_id
5487
                    );
5488
                    $last_connection_in_lp = self::get_last_connection_time_in_lp(
5489
                        $user_id,
5490
                        $course,
5491
                        $lp_id,
5492
                        $session_id
5493
                    );
5494
5495
                    $time_spent_in_lp = self::get_time_spent_in_lp(
5496
                        $user_id,
5497
                        $course,
5498
                        [$lp_id],
5499
                        $session_id
5500
                    );
5501
                    $percentage_score = self::get_avg_student_score(
5502
                        $user_id,
5503
                        $course,
5504
                        [$lp_id],
5505
                        $session_id
5506
                    );
5507
5508
                    $bestScore = self::get_avg_student_score(
5509
                        $user_id,
5510
                        $course,
5511
                        [$lp_id],
5512
                        $session_id,
5513
                        false,
5514
                        false,
5515
                        true
5516
                    );
5517
5518
                    if (is_numeric($progress)) {
5519
                        $progress = $progress.'%';
5520
                    }
5521
                    if (is_numeric($percentage_score)) {
5522
                        $percentage_score = $percentage_score.'%';
5523
                    } else {
5524
                        $percentage_score = '0%';
5525
                    }
5526
5527
                    if (is_numeric($bestScore)) {
5528
                        $bestScore = $bestScore.'%';
5529
                    } else {
5530
                        $bestScore = '-';
5531
                    }
5532
5533
                    $time_spent_in_lp = api_time_to_hms($time_spent_in_lp);
5534
                    $last_connection = '-';
5535
                    if (!empty($last_connection_in_lp)) {
5536
                        $last_connection = api_convert_and_format_date(
5537
                            $last_connection_in_lp,
5538
                            DATE_TIME_FORMAT_LONG
5539
                        );
5540
                    }
5541
5542
                    $url = api_get_path(WEB_CODE_PATH)."lp/lp_controller.php?cidReq={$course_code}&id_session=$session_id&lp_id=$lp_id&action=view";
5543
                    $html .= '<tr class="row_even">';
5544
5545
                    if (in_array('lp', $columnHeadersKeys)) {
5546
                        if ($learnpath['lp_visibility'] == 0) {
5547
                            $html .= Display::tag('td', $learnpath['lp_name']);
5548
                        } else {
5549
                            $html .= Display::tag(
5550
                                'td',
5551
                                Display::url(
5552
                                    $learnpath['lp_name'],
5553
                                    $url,
5554
                                    ['target' => SESSION_LINK_TARGET]
5555
                                )
5556
                            );
5557
                        }
5558
                    }
5559
5560
                    if (in_array('time', $columnHeadersKeys)) {
5561
                        $html .= Display::tag(
5562
                            'td',
5563
                            $time_spent_in_lp
5564
                        );
5565
                    }
5566
5567
                    if (in_array('progress', $columnHeadersKeys)) {
5568
                        $html .= Display::tag(
5569
                            'td',
5570
                            $progress
5571
                        );
5572
                    }
5573
5574
                    if (in_array('score', $columnHeadersKeys)) {
5575
                        $html .= Display::tag('td', $percentage_score);
5576
                    }
5577
                    if (in_array('best_score', $columnHeadersKeys)) {
5578
                        $html .= Display::tag('td', $bestScore);
5579
                    }
5580
5581
                    if (in_array('last_connection', $columnHeadersKeys)) {
5582
                        $html .= Display::tag('td', $last_connection, ['width'=>'180px']);
5583
                    }
5584
                    $html .= '</tr>';
5585
                }
5586
            } else {
5587
                $html .= '<tr>
5588
                        <td colspan="4" align="center">
5589
                            '.get_lang('NoLearnpath').'
5590
                        </td>
5591
                      </tr>';
5592
            }
5593
            $html .= '</tbody></table></div>';
5594
5595
            $html .= self::displayUserSkills($user_id, $course_info['id'], $session_id);
5596
        }
5597
5598
        return $html;
5599
    }
5600
5601
    /**
5602
     * Generates an histogram
5603
     * @param array $names list of exercise names
5604
     * @param array $my_results my results 0 to 100
5605
     * @param array $average average scores 0-100
5606
     * @return string
5607
     */
5608
    public static function generate_session_exercise_graph($names, $my_results, $average)
5609
    {
5610
        /* Create and populate the pData object */
5611
        $myData = new pData();
5612
        $myData->addPoints($names, 'Labels');
5613
        $myData->addPoints($my_results, 'Serie1');
5614
        $myData->addPoints($average, 'Serie2');
5615
        $myData->setSerieWeight('Serie1', 1);
5616
        $myData->setSerieTicks('Serie2', 4);
5617
        $myData->setSerieDescription('Labels', 'Months');
5618
        $myData->setAbscissa('Labels');
5619
        $myData->setSerieDescription('Serie1', get_lang('MyResults'));
5620
        $myData->setSerieDescription('Serie2', get_lang('AverageScore'));
5621
        $myData->setAxisUnit(0, '%');
5622
        $myData->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
5623
        // Cache definition
5624
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
5625
        $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]);
5626
        $chartHash = $myCache->getHash($myData);
5627
5628
        if ($myCache->isInCache($chartHash)) {
5629
            //if we already created the img
5630
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
5631
            $myCache->saveFromCache($chartHash, $imgPath);
5632
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
5633
        } else {
5634
            /* Define width, height and angle */
5635
            $mainWidth = 860;
5636
            $mainHeight = 500;
5637
            $angle = 50;
5638
5639
            /* Create the pChart object */
5640
            $myPicture = new pImage($mainWidth, $mainHeight, $myData);
5641
5642
            /* Turn of Antialiasing */
5643
            $myPicture->Antialias = false;
5644
5645
            /* Draw the background */
5646
            $settings = ['R' => 255, 'G' => 255, 'B' => 255];
5647
            $myPicture->drawFilledRectangle(0, 0, $mainWidth, $mainHeight, $settings);
5648
5649
            /* Add a border to the picture */
5650
            $myPicture->drawRectangle(
5651
                0,
5652
                0,
5653
                $mainWidth - 1,
5654
                $mainHeight - 1,
5655
                ['R' => 0, 'G' => 0, 'B' => 0]
5656
            );
5657
5658
            /* Set the default font */
5659
            $myPicture->setFontProperties(
5660
                [
5661
                    'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
5662
                    'FontSize' => 10]
5663
            );
5664
            /* Write the chart title */
5665
            $myPicture->drawText(
5666
                $mainWidth / 2,
5667
                30,
5668
                get_lang('ExercisesInTimeProgressChart'),
5669
                [
5670
                    'FontSize' => 12,
5671
                    'Align' => TEXT_ALIGN_BOTTOMMIDDLE
5672
                ]
5673
            );
5674
5675
            /* Set the default font */
5676
            $myPicture->setFontProperties(
5677
                [
5678
                    'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
5679
                    'FontSize' => 6
5680
                ]
5681
            );
5682
5683
            /* Define the chart area */
5684
            $myPicture->setGraphArea(60, 60, $mainWidth - 60, $mainHeight - 150);
5685
5686
            /* Draw the scale */
5687
            $scaleSettings = [
5688
                'XMargin' => 10,
5689
                'YMargin' => 10,
5690
                'Floating' => true,
5691
                'GridR' => 200,
5692
                'GridG' => 200,
5693
                'GridB' => 200,
5694
                'DrawSubTicks' => true,
5695
                'CycleBackground' => true,
5696
                'LabelRotation' => $angle,
5697
                'Mode' => SCALE_MODE_ADDALL_START0,
5698
            ];
5699
            $myPicture->drawScale($scaleSettings);
5700
5701
            /* Turn on Antialiasing */
5702
            $myPicture->Antialias = true;
5703
5704
            /* Enable shadow computing */
5705
            $myPicture->setShadow(
5706
                true,
5707
                [
5708
                    'X' => 1,
5709
                    'Y' => 1,
5710
                    'R' => 0,
5711
                    'G' => 0,
5712
                    'B' => 0,
5713
                    'Alpha' => 10
5714
                ]
5715
            );
5716
5717
            /* Draw the line chart */
5718
            $myPicture->setFontProperties(
5719
                [
5720
                    'FontName' => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
5721
                    'FontSize' => 10
5722
                ]
5723
            );
5724
            $myPicture->drawSplineChart();
5725
            $myPicture->drawPlotChart(
5726
                [
5727
                    'DisplayValues' => true,
5728
                    'PlotBorder' => true,
5729
                    'BorderSize' => 1,
5730
                    'Surrounding' => -60,
5731
                    'BorderAlpha' => 80
5732
                ]
5733
            );
5734
5735
            /* Write the chart legend */
5736
            $myPicture->drawLegend(
5737
                $mainWidth / 2 + 50,
5738
                50,
5739
                [
5740
                    'Style' => LEGEND_BOX,
5741
                    'Mode' => LEGEND_HORIZONTAL,
5742
                    'FontR' => 0,
5743
                    'FontG' => 0,
5744
                    'FontB' => 0,
5745
                    'R' => 220,
5746
                    'G' => 220,
5747
                    'B' => 220,
5748
                    'Alpha' => 100
5749
                ]
5750
            );
5751
5752
            $myCache->writeToCache($chartHash, $myPicture);
5753
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
5754
            $myCache->saveFromCache($chartHash, $imgPath);
5755
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
5756
        }
5757
5758
        $html = '<img src="'.$imgPath.'">';
5759
5760
        return $html;
5761
    }
5762
5763
    /**
5764
     * Returns a thumbnail of the function generate_exercise_result_graph
5765
     * @param  array $attempts
5766
     */
5767
    public static function generate_exercise_result_thumbnail_graph($attempts)
5768
    {
5769
        //$exercise_title = $attempts['title'];
5770
        $attempts = $attempts['data'];
5771
        $my_exercise_result_array = $exercise_result = [];
5772
        if (empty($attempts)) {
5773
            return null;
5774
        }
5775
5776
        foreach ($attempts as $attempt) {
5777
            if (api_get_user_id() == $attempt['exe_user_id']) {
5778
                if ($attempt['exe_weighting'] != 0) {
5779
                    $my_exercise_result_array[] = $attempt['exe_result'] / $attempt['exe_weighting'];
5780
                }
5781
            } else {
5782
                if ($attempt['exe_weighting'] != 0) {
5783
                    $exercise_result[] = $attempt['exe_result'] / $attempt['exe_weighting'];
5784
                }
5785
            }
5786
        }
5787
5788
        //Getting best result
5789
        rsort($my_exercise_result_array);
5790
        $my_exercise_result = 0;
5791
        if (isset($my_exercise_result_array[0])) {
5792
            $my_exercise_result = $my_exercise_result_array[0] * 100;
5793
        }
5794
5795
        $max     = 100;
5796
        $pieces  = 5;
5797
        $part    = round($max / $pieces);
5798
        $x_axis = [];
5799
        $final_array = [];
5800
        $my_final_array = [];
5801
5802
        for ($i = 1; $i <= $pieces; $i++) {
5803
            $sum = 1;
5804
            if ($i == 1) {
5805
                $sum = 0;
5806
            }
5807
            $min = ($i - 1) * $part + $sum;
5808
            $max = ($i) * $part;
5809
            $x_axis[] = $min." - ".$max;
5810
            $count = 0;
5811
            foreach ($exercise_result as $result) {
5812
                $percentage = $result * 100;
5813
                //echo $percentage.' - '.$min.' - '.$max."<br />";
5814
                if ($percentage >= $min && $percentage <= $max) {
5815
                    //echo ' is > ';
5816
                    $count++;
5817
                }
5818
            }
5819
            //echo '<br />';
5820
            $final_array[] = $count;
5821
5822
            if ($my_exercise_result >= $min && $my_exercise_result <= $max) {
5823
                $my_final_array[] = 1;
5824
            } else {
5825
                $my_final_array[] = 0;
5826
            }
5827
        }
5828
5829
        //Fix to remove the data of the user with my data
5830
        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...
5831
            if (!empty($my_final_array[$i])) {
5832
                $my_final_array[$i] = $final_array[$i] + 1; //Add my result
5833
                $final_array[$i] = 0;
5834
            }
5835
        }
5836
5837
        // Dataset definition
5838
        $dataSet = new pData();
5839
        $dataSet->addPoints($final_array, 'Serie1');
5840
        $dataSet->addPoints($my_final_array, 'Serie2');
5841
        $dataSet->normalize(100, "%");
5842
        $dataSet->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
5843
5844
        // Cache definition
5845
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
5846
        $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]);
5847
        $chartHash = $myCache->getHash($dataSet);
5848
        if ($myCache->isInCache($chartHash)) {
5849
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
5850
            $myCache->saveFromCache($chartHash, $imgPath);
5851
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
5852
        } else {
5853
            /* Create the pChart object */
5854
            $widthSize = 80;
5855
            $heightSize = 35;
5856
            $fontSize = 2;
5857
5858
            $myPicture = new pImage($widthSize, $heightSize, $dataSet);
5859
5860
            /* Turn of Antialiasing */
5861
            $myPicture->Antialias = false;
5862
5863
            /* Add a border to the picture */
5864
            $myPicture->drawRectangle(
5865
                0,
5866
                0,
5867
                $widthSize - 1,
5868
                $heightSize - 1,
5869
                ['R' => 0, 'G' => 0, 'B' => 0]
5870
            );
5871
5872
            /* Set the default font */
5873
            $myPicture->setFontProperties(
5874
                [
5875
                    'FontName' => api_get_path(
5876
                            SYS_FONTS_PATH
5877
                        ).'opensans/OpenSans-Regular.ttf',
5878
                    'FontSize' => $fontSize
5879
                ]
5880
            );
5881
5882
            /* Do not write the chart title */
5883
5884
            /* Define the chart area */
5885
            $myPicture->setGraphArea(5, 5, $widthSize - 5, $heightSize - 5);
5886
5887
            /* Draw the scale */
5888
            $scaleSettings = [
5889
                'GridR' => 200,
5890
                'GridG' => 200,
5891
                'GridB' => 200,
5892
                'DrawSubTicks' => true,
5893
                'CycleBackground' => true,
5894
                'Mode' => SCALE_MODE_MANUAL,
5895
                'ManualScale' => [
5896
                    '0' => [
5897
                        'Min' => 0,
5898
                        'Max' => 100
5899
                    ]
5900
                ]
5901
            ];
5902
            $myPicture->drawScale($scaleSettings);
5903
5904
            /* Turn on shadow computing */
5905
            $myPicture->setShadow(
5906
                true,
5907
                [
5908
                    'X' => 1,
5909
                    'Y' => 1,
5910
                    'R' => 0,
5911
                    'G' => 0,
5912
                    'B' => 0,
5913
                    'Alpha' => 10
5914
                ]
5915
            );
5916
5917
            /* Draw the chart */
5918
            $myPicture->setShadow(
5919
                true,
5920
                [
5921
                    'X' => 1,
5922
                    'Y' => 1,
5923
                    'R' => 0,
5924
                    'G' => 0,
5925
                    'B' => 0,
5926
                    'Alpha' => 10
5927
                ]
5928
            );
5929
            $settings = [
5930
                'DisplayValues' => true,
5931
                'DisplaySize' => $fontSize,
5932
                'DisplayR' => 0,
5933
                'DisplayG' => 0,
5934
                'DisplayB' => 0,
5935
                'DisplayOrientation' => ORIENTATION_HORIZONTAL,
5936
                'Gradient' => false,
5937
                'Surrounding' => 5,
5938
                'InnerSurrounding' => 5
5939
            ];
5940
            $myPicture->drawStackedBarChart($settings);
5941
5942
            /* Save and write in cache */
5943
            $myCache->writeToCache($chartHash, $myPicture);
5944
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
5945
            $myCache->saveFromCache($chartHash, $imgPath);
5946
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
5947
        }
5948
5949
        return $imgPath;
5950
    }
5951
5952
    /**
5953
     * Generates a big graph with the number of best results
5954
     * @param	array
5955
     */
5956
    public static function generate_exercise_result_graph($attempts)
5957
    {
5958
        $exercise_title = strip_tags($attempts['title']);
5959
        $attempts       = $attempts['data'];
5960
        $my_exercise_result_array = $exercise_result = [];
5961
        if (empty($attempts)) {
5962
            return null;
5963
        }
5964
        foreach ($attempts as $attempt) {
5965
            if (api_get_user_id() == $attempt['exe_user_id']) {
5966
                if ($attempt['exe_weighting'] != 0) {
5967
                    $my_exercise_result_array[] = $attempt['exe_result'] / $attempt['exe_weighting'];
5968
                }
5969
            } else {
5970
                if ($attempt['exe_weighting'] != 0) {
5971
                    $exercise_result[] = $attempt['exe_result'] / $attempt['exe_weighting'];
5972
                }
5973
            }
5974
        }
5975
5976
        //Getting best result
5977
        rsort($my_exercise_result_array);
5978
        $my_exercise_result = 0;
5979
        if (isset($my_exercise_result_array[0])) {
5980
            $my_exercise_result = $my_exercise_result_array[0] * 100;
5981
        }
5982
5983
        $max = 100;
5984
        $pieces = 5;
5985
        $part = round($max / $pieces);
5986
        $x_axis = [];
5987
        $final_array = [];
5988
        $my_final_array = [];
5989
5990
        for ($i = 1; $i <= $pieces; $i++) {
5991
            $sum = 1;
5992
            if ($i == 1) {
5993
                $sum = 0;
5994
            }
5995
            $min = ($i - 1) * $part + $sum;
5996
            $max = ($i) * $part;
5997
            $x_axis[] = $min." - ".$max;
5998
            $count = 0;
5999
            foreach ($exercise_result as $result) {
6000
                $percentage = $result * 100;
6001
                if ($percentage >= $min && $percentage <= $max) {
6002
                    $count++;
6003
                }
6004
            }
6005
            $final_array[] = $count;
6006
6007
            if ($my_exercise_result >= $min && $my_exercise_result <= $max) {
6008
                $my_final_array[] = 1;
6009
            } else {
6010
                $my_final_array[] = 0;
6011
            }
6012
        }
6013
6014
        //Fix to remove the data of the user with my data
6015
6016
        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...
6017
            if (!empty($my_final_array[$i])) {
6018
                $my_final_array[$i] = $final_array[$i] + 1; //Add my result
6019
                $final_array[$i] = 0;
6020
            }
6021
        }
6022
6023
        // Dataset definition
6024
        $dataSet = new pData();
6025
        $dataSet->addPoints($final_array, 'Serie1');
6026
        $dataSet->addPoints($my_final_array, 'Serie2');
6027
        $dataSet->addPoints($x_axis, 'Serie3');
6028
6029
        $dataSet->setSerieDescription('Serie1', get_lang('Score'));
6030
        $dataSet->setSerieDescription('Serie2', get_lang('MyResults'));
6031
        $dataSet->setAbscissa('Serie3');
6032
6033
        $dataSet->setXAxisName(get_lang('Score'));
6034
        $dataSet->normalize(100, "%");
6035
6036
        $dataSet->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
6037
6038
        // Cache definition
6039
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
6040
        $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]);
6041
        $chartHash = $myCache->getHash($dataSet);
6042
6043
        if ($myCache->isInCache($chartHash)) {
6044
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
6045
            $myCache->saveFromCache($chartHash, $imgPath);
6046
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
6047
        } else {
6048
            /* Create the pChart object */
6049
            $widthSize = 480;
6050
            $heightSize = 250;
6051
            $fontSize = 8;
6052
            $myPicture = new pImage($widthSize, $heightSize, $dataSet);
6053
6054
            /* Turn of Antialiasing */
6055
            $myPicture->Antialias = false;
6056
6057
            /* Add a border to the picture */
6058
            $myPicture->drawRectangle(0, 0, $widthSize - 1, $heightSize - 1, ['R' => 0, 'G' => 0, 'B' => 0]);
6059
6060
            /* Set the default font */
6061
            $myPicture->setFontProperties(
6062
                [
6063
                    'FontName' => api_get_path(
6064
                            SYS_FONTS_PATH
6065
                        ).'opensans/OpenSans-Regular.ttf',
6066
                    'FontSize' => 10
6067
                ]
6068
            );
6069
6070
            /* Write the chart title */
6071
            $myPicture->drawText(
6072
                250,
6073
                20,
6074
                $exercise_title,
6075
                [
6076
                    'FontSize' => 12,
6077
                    'Align' => TEXT_ALIGN_BOTTOMMIDDLE
6078
                ]
6079
            );
6080
6081
            /* Define the chart area */
6082
            $myPicture->setGraphArea(50, 50, $widthSize - 20, $heightSize - 30);
6083
6084
            /* Draw the scale */
6085
            $scaleSettings = [
6086
                'GridR' => 200,
6087
                'GridG' => 200,
6088
                'GridB' => 200,
6089
                'DrawSubTicks' => true,
6090
                'CycleBackground' => true,
6091
                'Mode' => SCALE_MODE_MANUAL,
6092
                'ManualScale' => [
6093
                    '0' => [
6094
                        'Min' => 0,
6095
                        'Max' => 100
6096
                    ]
6097
                ]
6098
            ];
6099
            $myPicture->drawScale($scaleSettings);
6100
6101
            /* Turn on shadow computing */
6102
            $myPicture->setShadow(true, ['X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10]);
6103
6104
            /* Draw the chart */
6105
            $myPicture->setShadow(true, ['X' => 1, 'Y' => 1, 'R' => 0, 'G' => 0, 'B' => 0, 'Alpha' => 10]);
6106
            $settings = [
6107
                'DisplayValues' => true,
6108
                'DisplaySize' => $fontSize,
6109
                'DisplayR' => 0,
6110
                'DisplayG' => 0,
6111
                'DisplayB' => 0,
6112
                'DisplayOrientation' => ORIENTATION_HORIZONTAL,
6113
                'Gradient' => false,
6114
                'Surrounding' => 30,
6115
                'InnerSurrounding' => 25
6116
            ];
6117
            $myPicture->drawStackedBarChart($settings);
6118
6119
            $legendSettings = [
6120
                'Mode' => LEGEND_HORIZONTAL,
6121
                'Style' => LEGEND_NOBORDER,
6122
            ];
6123
            $myPicture->drawLegend($widthSize / 2, 30, $legendSettings);
6124
6125
            /* Write and save into cache */
6126
            $myCache->writeToCache($chartHash, $myPicture);
6127
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
6128
            $myCache->saveFromCache($chartHash, $imgPath);
6129
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
6130
        }
6131
6132
        return $imgPath;
6133
    }
6134
6135
    /**
6136
    * @param FormValidator $form
6137
    * @return mixed
6138
    */
6139
    public static function setUserSearchForm($form)
6140
    {
6141
        global $_configuration;
6142
        $form->addElement('text', 'keyword', get_lang('Keyword'));
6143
        $form->addElement(
6144
            'select',
6145
            'active',
6146
            get_lang('Status'),
6147
            [1 => get_lang('Active'), 0 => get_lang('Inactive')]
6148
        );
6149
6150
        $form->addElement(
6151
            'select',
6152
            'sleeping_days',
6153
            get_lang('InactiveDays'),
6154
            [
6155
                '',
6156
                1 => 1,
6157
                5 => 5,
6158
                15 => 15,
6159
                30 => 30,
6160
                60 => 60,
6161
                90 => 90,
6162
                120 => 120,
6163
            ]
6164
        );
6165
6166
        $form->addButtonSearch(get_lang('Search'));
6167
6168
        return $form;
6169
    }
6170
6171
    /**
6172
     * Get the progress of a exercise
6173
     * @param   int $sessionId  The session ID (session.id)
6174
     * @param   int $courseId   The course ID (course.id)
6175
     * @param   int $exerciseId The quiz ID (c_quiz.id)
6176
     * @param   string $date_from
6177
     * @param   string $date_to
6178
     * @param   array   $options    An array of options you can pass to the query (limit, where and order)
6179
     * @return array An array with the data of exercise(s) progress
6180
     */
6181
    public static function get_exercise_progress(
6182
        $sessionId = 0,
6183
        $courseId = 0,
6184
        $exerciseId = 0,
6185
        $date_from = null,
6186
        $date_to = null,
6187
        $options = []
6188
    ) {
6189
        $sessionId  = intval($sessionId);
6190
        $courseId   = intval($courseId);
6191
        $exerciseId = intval($exerciseId);
6192
        $date_from  = Database::escape_string($date_from);
6193
        $date_to    = Database::escape_string($date_to);
6194
        /*
6195
         * This method gets the data by blocks, as previous attempts at one single
6196
         * query made it take ages. The logic of query division is described below
6197
         */
6198
        // Get tables names
6199
        $tuser = Database::get_main_table(TABLE_MAIN_USER);
6200
        $tquiz = Database::get_course_table(TABLE_QUIZ_TEST);
6201
        $tquiz_answer = Database::get_course_table(TABLE_QUIZ_ANSWER);
6202
        $tquiz_question = Database::get_course_table(TABLE_QUIZ_QUESTION);
6203
        $tquiz_rel_question = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
6204
        $ttrack_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
6205
        $ttrack_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
6206
6207
        $sessions = [];
6208
        $courses = [];
6209
        // if session ID is defined but course ID is empty, get all the courses
6210
        // from that session
6211
        if (!empty($sessionId) && empty($courseId)) {
6212
            // $courses is an array of course int id as index and course details hash as value
6213
            $courses = SessionManager::get_course_list_by_session_id($sessionId);
6214
            $sessions[$sessionId] = api_get_session_info($sessionId);
6215
        } elseif (empty($sessionId) && !empty($courseId)) {
6216
            // if, to the contrary, course is defined but not sessions, get the sessions that include this course
6217
            // $sessions is an array like: [0] => ('id' => 3, 'name' => 'Session 35'), [1] => () etc;
6218
            $course = api_get_course_info_by_id($courseId);
6219
            $sessionsTemp = SessionManager::get_session_by_course($courseId);
6220
            $courses[$courseId] = $course;
6221
            foreach ($sessionsTemp as $sessionItem) {
6222
                $sessions[$sessionItem['id']] = $sessionItem;
6223
            }
6224
        } elseif (!empty($courseId) && !empty($sessionId)) {
6225
            //none is empty
6226
            $course = api_get_course_info_by_id($courseId);
6227
            $courses[$courseId] = [$course['code']];
6228
            $courses[$courseId]['code'] = $course['code'];
6229
            $sessions[$sessionId] = api_get_session_info($sessionId);
6230
        } else {
6231
            //both are empty, not enough data, return an empty array
6232
            return [];
6233
        }
6234
        // Now we have two arrays of courses and sessions with enough data to proceed
6235
        // If no course could be found, we shouldn't return anything.
6236
        // Sessions can be empty (then we only return the pure-course-context results)
6237
        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

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

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