Passed
Push — 1.11.x ( 0e014d...433f25 )
by Angel Fernando Quiroz
09:07 queued 13s
created

getAdditionalProfileInformationOfFieldByUser()   C

Complexity

Conditions 13
Paths 3

Size

Total Lines 78
Code Lines 49

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 49
c 1
b 0
f 0
dl 0
loc 78
rs 6.6166
cc 13
nop 2
nc 3

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
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
6
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
7
use ChamiloSession as Session;
8
9
class TrackingCourseLog
10
{
11
    public const HIDE_COURSE_REPORT_GRAPH_SHOWN = 0;
12
    public const HIDE_COURSE_REPORT_GRAPH_HIDDEN = 1;
13
    public const HIDE_COURSE_REPORT_GRAPH_CLICK_SHOW = 2;
14
15
    /**
16
     * @return mixed
17
     */
18
    public static function countItemResources()
19
    {
20
        $sessionId = api_get_session_id();
21
        $courseId = api_get_course_int_id();
22
23
        $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
24
        $tableUser = Database::get_main_table(TABLE_MAIN_USER);
25
26
        $sql = "SELECT count(tool) AS total_number_of_items
27
                FROM $tableItemProperty track_resource, $tableUser user
28
                WHERE
29
                    track_resource.c_id = $courseId AND
30
                    track_resource.insert_user_id = user.user_id AND
31
                    session_id ".(empty($sessionId) ? ' IS NULL ' : " = $sessionId ");
32
33
        if (isset($_GET['keyword'])) {
34
            $keyword = Database::escape_string(trim($_GET['keyword']));
35
            $sql .= " AND (
36
                        user.username LIKE '%".$keyword."%' OR
37
                        lastedit_type LIKE '%".$keyword."%' OR
38
                        tool LIKE '%".$keyword."%'
39
                    )";
40
        }
41
42
        $sql .= " AND tool IN (
43
                    'document',
44
                    'learnpath',
45
                    'quiz',
46
                    'glossary',
47
                    'link',
48
                    'course_description',
49
                    'announcement',
50
                    'thematic',
51
                    'thematic_advance',
52
                    'thematic_plan'
53
                )";
54
        $res = Database::query($sql);
55
        $obj = Database::fetch_object($res);
56
57
        return $obj->total_number_of_items;
58
    }
59
60
    public static function getItemResourcesData($from, $numberOfItems, $column, $direction): array
61
    {
62
        $sessionId = api_get_session_id();
63
        $courseId = api_get_course_int_id();
64
65
        $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
66
        $tableUser = Database::get_main_table(TABLE_MAIN_USER);
67
        $tableSession = Database::get_main_table(TABLE_MAIN_SESSION);
68
        $column = (int) $column;
69
        $direction = !in_array(strtolower(trim($direction)), ['asc', 'desc']) ? 'asc' : $direction;
70
71
        $sql = "SELECT
72
                    tool as col0,
73
                    lastedit_type as col1,
74
                    ref as ref,
75
                    user.username as col3,
76
                    insert_date as col6,
77
                    visibility as col7,
78
                    user.user_id as user_id
79
                FROM $tableItemProperty track_resource, $tableUser user
80
                WHERE
81
                  track_resource.c_id = $courseId AND
82
                  track_resource.insert_user_id = user.user_id AND
83
                  session_id ".(empty($sessionId) ? ' IS NULL ' : " = $sessionId ");
84
85
        if (isset($_GET['keyword'])) {
86
            $keyword = Database::escape_string(trim($_GET['keyword']));
87
            $sql .= " AND (
88
                        user.username LIKE '%".$keyword."%' OR
89
                        lastedit_type LIKE '%".$keyword."%' OR
90
                        tool LIKE '%".$keyword."%'
91
                     ) ";
92
        }
93
94
        $sql .= " AND tool IN (
95
                    'document',
96
                    'learnpath',
97
                    'quiz',
98
                    'glossary',
99
                    'link',
100
                    'course_description',
101
                    'announcement',
102
                    'thematic',
103
                    'thematic_advance',
104
                    'thematic_plan'
105
                )";
106
107
        if ($column == 0) {
108
            $column = '0';
109
        }
110
        if ($column != '' && $direction != '') {
111
            if ($column != 2 && $column != 4) {
112
                $sql .= " ORDER BY col$column $direction";
113
            }
114
        } else {
115
            $sql .= " ORDER BY col6 DESC ";
116
        }
117
118
        $from = intval($from);
119
        if ($from) {
120
            $numberOfItems = intval($numberOfItems);
121
            $sql .= " LIMIT $from, $numberOfItems ";
122
        }
123
124
        $res = Database::query($sql);
125
        $resources = [];
126
        $thematicTools = ['thematic', 'thematic_advance', 'thematic_plan'];
127
        while ($row = Database::fetch_array($res)) {
128
            $ref = $row['ref'];
129
            $tableName = self::getToolNameTable($row['col0']);
130
            $tableTool = Database::get_course_table($tableName['table_name']);
131
132
            $id = $tableName['id_tool'];
133
            $recorset = false;
134
135
            if (in_array($row['col0'], ['thematic_plan', 'thematic_advance'])) {
136
                $tblThematic = Database::get_course_table(TABLE_THEMATIC);
137
                $sql = "SELECT thematic_id FROM $tableTool
138
                        WHERE c_id = $courseId AND id = $ref";
139
                $rsThematic = Database::query($sql);
140
                if (Database::num_rows($rsThematic)) {
141
                    $rowThematic = Database::fetch_array($rsThematic);
142
                    $thematicId = $rowThematic['thematic_id'];
143
144
                    $sql = "SELECT session.id, session.name, user.username
145
                            FROM $tblThematic t, $tableSession session, $tableUser user
146
                            WHERE
147
                              t.c_id = $courseId AND
148
                              t.session_id = session.id AND
149
                              session.id_coach = user.user_id AND
150
                              t.id = $thematicId";
151
                    $recorset = Database::query($sql);
152
                }
153
            } else {
154
                $sql = "SELECT session.id, session.name, user.username
155
                          FROM $tableTool tool, $tableSession session, $tableUser user
156
                          WHERE
157
                              tool.c_id = $courseId AND
158
                              tool.session_id = session.id AND
159
                              session.id_coach = user.user_id AND
160
                              tool.$id = $ref";
161
                $recorset = Database::query($sql);
162
            }
163
164
            if (!empty($recorset)) {
165
                $obj = Database::fetch_object($recorset);
166
167
                $nameSession = '';
168
                $coachName = '';
169
                if (!empty($obj)) {
170
                    $nameSession = $obj->name;
171
                    $coachName = $obj->username;
172
                }
173
174
                $urlTool = api_get_path(WEB_CODE_PATH).$tableName['link_tool'];
175
176
                if ($row['col6'] != 2) {
177
                    if (in_array($row['col0'], $thematicTools)) {
178
                        $expThematicTool = explode('_', $row['col0']);
179
                        $thematicTooltitle = '';
180
                        if (is_array($expThematicTool)) {
181
                            foreach ($expThematicTool as $exp) {
182
                                $thematicTooltitle .= api_ucfirst($exp);
183
                            }
184
                        } else {
185
                            $thematicTooltitle = api_ucfirst($row['col0']);
186
                        }
187
188
                        $row[0] = '<a href="'.$urlTool.'?'.api_get_cidreq().'&action=thematic_details">'.get_lang(
189
                                $thematicTooltitle
190
                            ).'</a>';
191
                    } else {
192
                        $row[0] = '<a href="'.$urlTool.'?'.api_get_cidreq().'">'.get_lang(
193
                                'Tool'.api_ucfirst($row['col0'])
194
                            ).'</a>';
195
                    }
196
                } else {
197
                    $row[0] = api_ucfirst($row['col0']);
198
                }
199
                $row[1] = get_lang($row[1]);
200
                $row[6] = api_convert_and_format_date($row['col6'], null, date_default_timezone_get());
201
                $row[5] = '';
202
                //@todo Improve this code please
203
                switch ($tableName['table_name']) {
204
                    case 'document':
205
                        $sql = "SELECT tool.title as title FROM $tableTool tool
206
                                WHERE c_id = $courseId AND id = $ref";
207
                        $rsDocument = Database::query($sql);
208
                        $objDocument = Database::fetch_object($rsDocument);
209
                        if ($objDocument) {
210
                            $row[5] = $objDocument->title;
211
                        }
212
                        break;
213
                    case 'quiz':
214
                    case 'course_description':
215
                    case 'announcement':
216
                        $sql = "SELECT title FROM $tableTool
217
                                WHERE c_id = $courseId AND id = $ref";
218
                        $rsDocument = Database::query($sql);
219
                        $objDocument = Database::fetch_object($rsDocument);
220
                        if ($objDocument) {
221
                            $row[5] = $objDocument->title;
222
                        }
223
                        break;
224
                    case 'glossary':
225
                        $sql = "SELECT name FROM $tableTool
226
                                WHERE c_id = $courseId AND glossary_id = $ref";
227
                        $rsDocument = Database::query($sql);
228
                        $objDocument = Database::fetch_object($rsDocument);
229
                        if ($objDocument) {
230
                            $row[5] = $objDocument->name;
231
                        }
232
                        break;
233
                    case 'lp':
234
                        $sql = "SELECT name
235
                                FROM $tableTool WHERE c_id = $courseId AND id = $ref";
236
                        $rsDocument = Database::query($sql);
237
                        $objDocument = Database::fetch_object($rsDocument);
238
                        $row[5] = $objDocument->name;
239
                        break;
240
                    case 'thematic_plan':
241
                    case 'thematic':
242
                        $rs = Database::query("SELECT title FROM $tableTool WHERE c_id = $courseId AND id = $ref");
243
                        if (Database::num_rows($rs) > 0) {
244
                            $obj = Database::fetch_object($rs);
245
                            if ($obj) {
246
                                $row[5] = $obj->title;
247
                            }
248
                        }
249
                        break;
250
                    case 'thematic_advance':
251
                        $rs = Database::query("SELECT content FROM $tableTool WHERE c_id = $courseId AND id = $ref");
252
                        if (Database::num_rows($rs) > 0) {
253
                            $obj = Database::fetch_object($rs);
254
                            if ($obj) {
255
                                $row[5] = $obj->content;
256
                            }
257
                        }
258
                        break;
259
                    default:
260
                        break;
261
                }
262
263
                $row2 = $nameSession;
264
                if (!empty($coachName)) {
265
                    $row2 .= '<br />'.get_lang('Coach').': '.$coachName;
266
                }
267
                $row[2] = $row2;
268
                if (!empty($row['col3'])) {
269
                    $userInfo = api_get_user_info($row['user_id']);
270
                    $row['col3'] = Display::url(
271
                        $row['col3'],
272
                        $userInfo['profile_url']
273
                    );
274
                    $row[3] = $row['col3'];
275
276
                    $ip = Tracking::get_ip_from_user_event(
277
                        $row['user_id'],
278
                        $row['col6'],
279
                        true
280
                    );
281
                    if (empty($ip)) {
282
                        $ip = get_lang('Unknown');
283
                    }
284
                    $row[4] = $ip;
285
                }
286
287
                $resources[] = $row;
288
            }
289
        }
290
291
        return $resources;
292
    }
293
294
    public static function getToolNameTable(string $tool): array
295
    {
296
        $linkTool = '';
297
        $idTool = '';
298
299
        switch ($tool) {
300
            case 'document':
301
                $tableName = TABLE_DOCUMENT;
302
                $linkTool = 'document/document.php';
303
                $idTool = 'id';
304
                break;
305
            case 'learnpath':
306
                $tableName = TABLE_LP_MAIN;
307
                $linkTool = 'lp/lp_controller.php';
308
                $idTool = 'id';
309
                break;
310
            case 'quiz':
311
                $tableName = TABLE_QUIZ_TEST;
312
                $linkTool = 'exercise/exercise.php';
313
                $idTool = 'iid';
314
                break;
315
            case 'glossary':
316
                $tableName = TABLE_GLOSSARY;
317
                $linkTool = 'glossary/index.php';
318
                $idTool = 'glossary_id';
319
                break;
320
            case 'link':
321
                $tableName = TABLE_LINK;
322
                $linkTool = 'link/link.php';
323
                $idTool = 'id';
324
                break;
325
            case 'course_description':
326
                $tableName = TABLE_COURSE_DESCRIPTION;
327
                $linkTool = 'course_description/';
328
                $idTool = 'id';
329
                break;
330
            case 'announcement':
331
                $tableName = TABLE_ANNOUNCEMENT;
332
                $linkTool = 'announcements/announcements.php';
333
                $idTool = 'id';
334
                break;
335
            case 'thematic':
336
                $tableName = TABLE_THEMATIC;
337
                $linkTool = 'course_progress/index.php';
338
                $idTool = 'id';
339
                break;
340
            case 'thematic_advance':
341
                $tableName = TABLE_THEMATIC_ADVANCE;
342
                $linkTool = 'course_progress/index.php';
343
                $idTool = 'id';
344
                break;
345
            case 'thematic_plan':
346
                $tableName = TABLE_THEMATIC_PLAN;
347
                $linkTool = 'course_progress/index.php';
348
                $idTool = 'id';
349
                break;
350
            default:
351
                $tableName = $tool;
352
                break;
353
        }
354
355
        return [
356
            'table_name' => $tableName,
357
            'link_tool' => $linkTool,
358
            'id_tool' => $idTool,
359
        ];
360
    }
361
362
    public static function displayAdditionalProfileFields(array $exclude = []): string
363
    {
364
        // getting all the extra profile fields that are defined by the platform administrator
365
        $extraFields = UserManager::get_extra_fields(0, 50);
366
367
        // creating the form
368
        $return = '<form action="courseLog.php" method="get" name="additional_profile_field_form" id="additional_profile_field_form">';
369
370
        // the select field with the additional user profile fields, this is where we select the field of which we want to see
371
        // the information the users have entered or selected.
372
        $return .= '<select class="chzn-select" name="additional_profile_field[]" multiple>';
373
        $return .= '<option value="-">'.get_lang('SelectFieldToAdd').'</option>';
374
        $extraFieldsToShow = 0;
375
        foreach ($extraFields as $field) {
376
            // exclude extra profile fields by id
377
            if (in_array($field[3], $exclude)) {
378
                continue;
379
            }
380
            // show only extra fields that are visible + and can be filtered, added by J.Montoya
381
            if ($field[6] == 1 && $field[8] == 1) {
382
                if (isset($_GET['additional_profile_field']) && $field[0] == $_GET['additional_profile_field']) {
383
                    $selected = 'selected="selected"';
384
                } else {
385
                    $selected = '';
386
                }
387
                $extraFieldsToShow++;
388
                $return .= '<option value="'.$field[0].'" '.$selected.'>'.$field[3].'</option>';
389
            }
390
        }
391
        $return .= '</select>';
392
393
        // the form elements for the $_GET parameters (because the form is passed through GET
394
        foreach ($_GET as $key => $value) {
395
            if ($key != 'additional_profile_field') {
396
                $return .= '<input type="hidden" name="'.Security::remove_XSS($key).'" value="'.Security::remove_XSS(
397
                        $value
398
                    ).'" />';
399
            }
400
        }
401
        // the submit button
402
        $return .= '<button class="save" type="submit">'.get_lang('AddAdditionalProfileField').'</button>';
403
        $return .= '</form>';
404
405
        return $extraFieldsToShow > 0 ? $return : '';
406
    }
407
408
    /**
409
     * This function gets all the information of a certrain ($field_id)
410
     * additional profile field for a specific list of users is more efficent
411
     * than get_addtional_profile_information_of_field() function
412
     * It gets the information of all the users so that it can be displayed
413
     * in the sortable table or in the csv or xls export.
414
     *
415
     * @param int   field id
416
     * @param array list of user ids
417
     *
418
     * @author     Julio Montoya <[email protected]>
419
     *
420
     * @since      Nov 2009
421
     *
422
     * @version    1.8.6.2
423
     */
424
    public static function getAdditionalProfileInformationOfFieldByUser($fieldId, $users): array
425
    {
426
        // Database table definition
427
        $tableUser = Database::get_main_table(TABLE_MAIN_USER);
428
        $tableUserFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
429
        $extraField = Database::get_main_table(TABLE_EXTRA_FIELD);
430
        $resultExtraField = UserManager::get_extra_field_information($fieldId);
431
        $return = [];
432
        if (!empty($users)) {
433
            if ($resultExtraField['field_type'] == UserManager::USER_FIELD_TYPE_TAG) {
434
                foreach ($users as $user_id) {
435
                    $userResult = UserManager::get_user_tags($user_id, $fieldId);
436
                    $tagList = [];
437
                    foreach ($userResult as $item) {
438
                        $tagList[] = $item['tag'];
439
                    }
440
                    $return[$user_id][] = implode(', ', $tagList);
441
                }
442
            } else {
443
                $newUserArray = [];
444
                foreach ($users as $user_id) {
445
                    $newUserArray[] = "'".$user_id."'";
446
                }
447
                $users = implode(',', $newUserArray);
448
                $extraFieldType = EntityExtraField::USER_FIELD_TYPE;
449
                // Selecting only the necessary information NOT ALL the user list
450
                $sql = "SELECT user.user_id, v.value
451
                        FROM $tableUser user
452
                        INNER JOIN $tableUserFieldValues v
453
                        ON (user.user_id = v.item_id)
454
                        INNER JOIN $extraField f
455
                        ON (f.id = v.field_id)
456
                        WHERE
457
                            f.extra_field_type = $extraFieldType AND
458
                            v.field_id=".intval($fieldId)." AND
459
                            user.user_id IN ($users)";
460
461
                $result = Database::query($sql);
462
                while ($row = Database::fetch_array($result)) {
463
                    // get option value for field type double select by id
464
                    if (!empty($row['value'])) {
465
                        if ($resultExtraField['field_type'] ==
466
                            ExtraField::FIELD_TYPE_DOUBLE_SELECT
467
                        ) {
468
                            $idDoubleSelect = explode(';', $row['value']);
469
                            if (is_array($idDoubleSelect)) {
470
                                $value1 = $resultExtraField['options'][$idDoubleSelect[0]]['option_value'];
471
                                $value2 = $resultExtraField['options'][$idDoubleSelect[1]]['option_value'];
472
                                $row['value'] = ($value1.';'.$value2);
473
                            }
474
                        }
475
476
                        if ($resultExtraField['field_type'] == ExtraField::FIELD_TYPE_SELECT_WITH_TEXT_FIELD) {
477
                            $parsedValue = explode('::', $row['value']);
478
479
                            if ($parsedValue) {
480
                                $value1 = $resultExtraField['options'][$parsedValue[0]]['display_text'];
481
                                $value2 = $parsedValue[1];
482
483
                                $row['value'] = "$value1: $value2";
484
                            }
485
                        }
486
487
                        if ($resultExtraField['field_type'] == ExtraField::FIELD_TYPE_TRIPLE_SELECT) {
488
                            [$level1, $level2, $level3] = explode(';', $row['value']);
489
490
                            $row['value'] = $resultExtraField['options'][$level1]['display_text'].' / ';
491
                            $row['value'] .= $resultExtraField['options'][$level2]['display_text'].' / ';
492
                            $row['value'] .= $resultExtraField['options'][$level3]['display_text'];
493
                        }
494
                    }
495
                    // get other value from extra field
496
                    $return[$row['user_id']][] = $row['value'];
497
                }
498
            }
499
        }
500
501
        return $return;
502
    }
503
504
    /**
505
     * Get number of users for sortable with pagination.
506
     */
507
    public static function getNumberOfUsers(array $conditions): int
508
    {
509
        $conditions['get_count'] = true;
510
511
        return self::getUserData(0, 0, 0, '', $conditions);
512
    }
513
514
    /**
515
     * Get data for users list in sortable with pagination.
516
     */
517
    public static function getUserData(
518
        $from,
519
        $numberOfItems,
520
        $column,
521
        $direction,
522
        array $conditions = []
523
    ) {
524
        $includeInvitedUsers = $conditions['include_invited_users']; // include the invited users
525
        $getCount = $conditions['get_count'] ?? false;
526
527
        $csvContent = [];
528
        $course_code = isset($GLOBALS['course_code']) ? Database::escape_string($GLOBALS['course_code']) : api_get_course_id();
529
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
530
        $tblUrlRelUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
531
        $accessUrlId = api_get_current_access_url_id();
532
533
        // get all users data from a course for sortable with limit
534
        if (!empty($GLOBALS['user_ids']) && is_array($GLOBALS['user_ids'])) {
535
            $GLOBALS['user_ids'] = array_map('intval', $GLOBALS['user_ids']);
536
            $conditionUser = " WHERE user.id IN (".implode(',', $GLOBALS['user_ids']).") ";
537
        } else {
538
            $GLOBALS['user_ids'] = (int) $GLOBALS['user_ids'];
539
            $conditionUser = " WHERE user.id = {$GLOBALS['user_ids']} ";
540
        }
541
542
        if (!empty($_GET['user_keyword'])) {
543
            $keyword = trim(Database::escape_string($_GET['user_keyword']));
544
            $conditionUser .= " AND (
545
                user.firstname LIKE '%".$keyword."%' OR
546
                user.lastname LIKE '%".$keyword."%'  OR
547
                user.username LIKE '%".$keyword."%'  OR
548
                user.email LIKE '%".$keyword."%'
549
             ) ";
550
        }
551
552
        $urlTable = '';
553
        $urlCondition = '';
554
        if (api_is_multiple_url_enabled()) {
555
            $urlTable = " INNER JOIN $tblUrlRelUser as url_users ON (user.id = url_users.user_id)";
556
            $urlCondition = " AND access_url_id = '$accessUrlId'";
557
        }
558
559
        $invitedUsersCondition = '';
560
        if (!$includeInvitedUsers) {
561
            $invitedUsersCondition = " AND user.status != ".INVITEE;
562
        }
563
564
        $select = '
565
                SELECT user.id as user_id,
566
                    user.official_code  as col0,
567
                    user.lastname       as col1,
568
                    user.firstname      as col2,
569
                    user.username       as col3,
570
                    user.email          as col4';
571
        if ($getCount) {
572
            $select = ' SELECT COUNT(distinct(user.id)) as count ';
573
        }
574
575
        $sqlInjectJoins = '';
576
        $where = 'AND 1 = 1 ';
577
        $sqlInjectWhere = '';
578
        if (!empty($conditions)) {
579
            if (isset($conditions['inject_joins'])) {
580
                $sqlInjectJoins = $conditions['inject_joins'];
581
            }
582
            if (isset($conditions['where'])) {
583
                $where = $conditions['where'];
584
            }
585
            if (isset($conditions['inject_where'])) {
586
                $sqlInjectWhere = $conditions['inject_where'];
587
            }
588
            $injectExtraFields = !empty($conditions['inject_extra_fields']) ? $conditions['inject_extra_fields'] : 1;
589
            $injectExtraFields = rtrim($injectExtraFields, ', ');
590
            if (false === $getCount) {
591
                $select .= " , $injectExtraFields";
592
            }
593
        }
594
595
        $sql = "$select
596
                FROM $tblUser as user
597
                $urlTable
598
                $sqlInjectJoins
599
                $conditionUser
600
                $urlCondition
601
                $invitedUsersCondition
602
                $where
603
                $sqlInjectWhere
604
                ";
605
606
        if (!in_array($direction, ['ASC', 'DESC'])) {
607
            $direction = 'ASC';
608
        }
609
610
        $column = $column <= 2 ? (int) $column : 0;
611
        $from = (int) $from;
612
        $numberOfItems = (int) $numberOfItems;
613
614
        if ($getCount) {
615
            $res = Database::query($sql);
616
            $row = Database::fetch_array($res);
617
618
            return $row['count'];
619
        }
620
621
        $sortByFirstName = api_sort_by_first_name();
622
623
        if ($sortByFirstName) {
624
            if ($column == 1) {
625
                $column = 2;
626
            } elseif ($column == 2) {
627
                $column = 1;
628
            }
629
        }
630
631
        $sql .= " ORDER BY col$column $direction ";
632
        $sql .= " LIMIT $from, $numberOfItems";
633
634
        $res = Database::query($sql);
635
        $users = [];
636
637
        $courseInfo = api_get_course_info($course_code);
638
        $courseId = $courseInfo['real_id'];
639
        $courseCode = $courseInfo['code'];
640
641
        $totalSurveys = 0;
642
        $totalExercises = ExerciseLib::get_all_exercises(
643
            $courseInfo,
644
            $GLOBALS['session_id'],
645
            false,
646
            null,
647
            false,
648
            3
649
        );
650
651
        if (empty($GLOBALS['session_id'])) {
652
            $surveyUserList = [];
653
            $surveyList = SurveyManager::get_surveys($course_code, $GLOBALS['session_id']);
654
            if ($surveyList) {
655
                $totalSurveys = count($surveyList);
656
                foreach ($surveyList as $survey) {
657
                    $userList = SurveyManager::get_people_who_filled_survey(
658
                        $survey['survey_id'],
659
                        false,
660
                        $courseId
661
                    );
662
663
                    foreach ($userList as $user_id) {
664
                        isset($surveyUserList[$user_id]) ? $surveyUserList[$user_id]++ : $surveyUserList[$user_id] = 1;
665
                    }
666
                }
667
            }
668
        }
669
670
        $urlBase = api_get_path(WEB_CODE_PATH).'mySpace/myStudents.php?details=true&cidReq='.$courseCode.
671
            '&course='.$course_code.'&origin=tracking_course&id_session='.$GLOBALS['session_id'];
672
673
        Session::write('user_id_list', []);
674
        $userIdList = [];
675
676
        $addExerciseOption = api_get_configuration_value('add_exercise_best_attempt_in_report');
677
        $exerciseResultsToCheck = [];
678
        if (!empty($addExerciseOption) && isset($addExerciseOption['courses']) &&
679
            isset($addExerciseOption['courses'][$courseCode])
680
        ) {
681
            foreach ($addExerciseOption['courses'][$courseCode] as $exerciseId) {
682
                $exercise = new Exercise();
683
                $exercise->read($exerciseId);
684
                if ($exercise->iid) {
685
                    $exerciseResultsToCheck[] = $exercise;
686
                }
687
            }
688
        }
689
690
        $lpShowMaxProgress = api_get_configuration_value('lp_show_max_progress_instead_of_average');
691
        if (api_get_configuration_value('lp_show_max_progress_or_average_enable_course_level_redefinition')) {
692
            $lpShowProgressCourseSetting = api_get_course_setting('lp_show_max_or_average_progress', $courseInfo, true);
693
            if (in_array($lpShowProgressCourseSetting, ['max', 'average'])) {
694
                $lpShowMaxProgress = ('max' === $lpShowProgressCourseSetting);
695
            }
696
        }
697
698
        while ($user = Database::fetch_array($res, 'ASSOC')) {
699
            $userIdList[] = $user['user_id'];
700
            $user['official_code'] = $user['col0'];
701
            $user['username'] = $user['col3'];
702
            $user['time'] = api_time_to_hms(
703
                Tracking::get_time_spent_on_the_course(
704
                    $user['user_id'],
705
                    $courseId,
706
                    $GLOBALS['session_id']
707
                )
708
            );
709
710
            $avgStudentScore = Tracking::get_avg_student_score(
711
                $user['user_id'],
712
                $course_code,
713
                [],
714
                $GLOBALS['session_id']
715
            );
716
717
            $averageBestScore = Tracking::get_avg_student_score(
718
                $user['user_id'],
719
                $course_code,
720
                [],
721
                $GLOBALS['session_id'],
722
                false,
723
                false,
724
                true
725
            );
726
727
            $avgStudentProgress = Tracking::get_avg_student_progress(
728
                $user['user_id'],
729
                $course_code,
730
                [],
731
                $GLOBALS['session_id'],
732
                false,
733
                false,
734
                $lpShowMaxProgress
735
            );
736
737
            if (empty($avgStudentProgress)) {
738
                $avgStudentProgress = 0;
739
            }
740
            $user['average_progress'] = $avgStudentProgress.'%';
741
742
            $totalUserExercise = Tracking::get_exercise_student_progress(
743
                $totalExercises,
744
                $user['user_id'],
745
                $courseId,
746
                $GLOBALS['session_id']
747
            );
748
749
            $user['exercise_progress'] = $totalUserExercise;
750
751
            $totalUserExercise = Tracking::get_exercise_student_average_best_attempt(
752
                $totalExercises,
753
                $user['user_id'],
754
                $courseId,
755
                $GLOBALS['session_id']
756
            );
757
758
            $user['exercise_average_best_attempt'] = $totalUserExercise;
759
760
            if (is_numeric($avgStudentScore)) {
761
                $user['student_score'] = $avgStudentScore.'%';
762
            } else {
763
                $user['student_score'] = $avgStudentScore;
764
            }
765
766
            if (is_numeric($averageBestScore)) {
767
                $user['student_score_best'] = $averageBestScore.'%';
768
            } else {
769
                $user['student_score_best'] = $averageBestScore;
770
            }
771
772
            $exerciseResults = [];
773
            if (!empty($exerciseResultsToCheck)) {
774
                foreach ($exerciseResultsToCheck as $exercise) {
775
                    $bestExerciseResult = Event::get_best_attempt_exercise_results_per_user(
776
                        $user['user_id'],
777
                        $exercise->iid,
778
                        $courseId,
779
                        $GLOBALS['session_id'],
780
                        false
781
                    );
782
783
                    $best = null;
784
                    if ($bestExerciseResult) {
785
                        $best = $bestExerciseResult['exe_result'] / $bestExerciseResult['exe_weighting'];
786
                        $best = round($best, 2) * 100;
787
                        $best .= '%';
788
                    }
789
                    $exerciseResults['exercise_'.$exercise->iid] = $best;
790
                }
791
            }
792
793
            $user['count_assignments'] = Tracking::count_student_assignments(
794
                $user['user_id'],
795
                $course_code,
796
                $GLOBALS['session_id']
797
            );
798
            $user['count_messages'] = Tracking::count_student_messages(
799
                $user['user_id'],
800
                $course_code,
801
                $GLOBALS['session_id']
802
            );
803
            $user['first_connection'] = Tracking::get_first_connection_date_on_the_course(
804
                $user['user_id'],
805
                $courseId,
806
                $GLOBALS['session_id'],
807
                false === $GLOBALS['export_csv']
808
            );
809
810
            $user['last_connection'] = Tracking::get_last_connection_date_on_the_course(
811
                $user['user_id'],
812
                $courseInfo,
813
                $GLOBALS['session_id'],
814
                false === $GLOBALS['export_csv']
815
            );
816
817
            if ($GLOBALS['export_csv']) {
818
                if (!empty($user['first_connection'])) {
819
                    $user['first_connection'] = api_get_local_time($user['first_connection']);
820
                } else {
821
                    $user['first_connection'] = '-';
822
                }
823
                if (!empty($user['last_connection'])) {
824
                    $user['last_connection'] = api_get_local_time($user['last_connection']);
825
                } else {
826
                    $user['last_connection'] = '-';
827
                }
828
            }
829
830
            if (empty($GLOBALS['session_id'])) {
831
                $user['survey'] = ($surveyUserList[$user['user_id']] ?? 0).' / '.$totalSurveys;
832
            }
833
834
            $url = $urlBase.'&student='.$user['user_id'];
835
836
            $user['link'] = '<center><a href="'.$url.'">
837
                            '.Display::return_icon('2rightarrow.png', get_lang('Details')).'
838
                             </a></center>';
839
840
            // store columns in array $users
841
            $userRow = [];
842
            $userRow['official_code'] = $user['official_code']; //0
843
            if ($sortByFirstName) {
844
                $userRow['firstname'] = $user['col2'];
845
                $userRow['lastname'] = $user['col1'];
846
            } else {
847
                $userRow['lastname'] = $user['col1'];
848
                $userRow['firstname'] = $user['col2'];
849
            }
850
            $userRow['username'] = $user['username'];
851
            $userRow['time'] = $user['time'];
852
            $userRow['average_progress'] = $user['average_progress'];
853
            $userRow['exercise_progress'] = $user['exercise_progress'];
854
            $userRow['exercise_average_best_attempt'] = $user['exercise_average_best_attempt'];
855
            $userRow['student_score'] = $user['student_score'];
856
            $userRow['student_score_best'] = $user['student_score_best'];
857
            if (!empty($exerciseResults)) {
858
                foreach ($exerciseResults as $exerciseId => $bestResult) {
859
                    $userRow[$exerciseId] = $bestResult;
860
                }
861
            }
862
863
            $userRow['count_assignments'] = $user['count_assignments'];
864
            $userRow['count_messages'] = $user['count_messages'];
865
866
            $userGroupManager = new UserGroup();
867
            if ($GLOBALS['export_csv']) {
868
                $userRow['classes'] = implode(
869
                    ',',
870
                    $userGroupManager->getNameListByUser($user['user_id'], UserGroup::NORMAL_CLASS)
871
                );
872
            } else {
873
                $userRow['classes'] = $userGroupManager->getLabelsFromNameList(
874
                    $user['user_id'],
875
                    UserGroup::NORMAL_CLASS
876
                );
877
            }
878
879
            if (empty($GLOBALS['session_id'])) {
880
                $userRow['survey'] = $user['survey'];
881
            } else {
882
                $userSession = SessionManager::getUserSession($user['user_id'], $GLOBALS['session_id']);
883
                $userRow['registered_at'] = '';
884
                if ($userSession) {
885
                    $userRow['registered_at'] = api_get_local_time($userSession['registered_at']);
886
                }
887
            }
888
889
            $userRow['first_connection'] = $user['first_connection'];
890
            $userRow['last_connection'] = $user['last_connection'];
891
892
            // we need to display an additional profile field
893
            if (isset($_GET['additional_profile_field'])) {
894
                $data = Session::read('additional_user_profile_info');
895
896
                $extraFieldInfo = Session::read('extra_field_info');
897
                foreach ($_GET['additional_profile_field'] as $fieldId) {
898
                    if (isset($data[$fieldId]) && isset($data[$fieldId][$user['user_id']])) {
899
                        if (is_array($data[$fieldId][$user['user_id']])) {
900
                            $userRow[$extraFieldInfo[$fieldId]['variable']] = implode(
901
                                ', ',
902
                                $data[$fieldId][$user['user_id']]
903
                            );
904
                        } else {
905
                            $userRow[$extraFieldInfo[$fieldId]['variable']] = $data[$fieldId][$user['user_id']];
906
                        }
907
                    } else {
908
                        $userRow[$extraFieldInfo[$fieldId]['variable']] = '';
909
                    }
910
                }
911
            }
912
913
            $data = Session::read('default_additional_user_profile_info');
914
            $defaultExtraFieldInfo = Session::read('default_extra_field_info');
915
            if (isset($defaultExtraFieldInfo) && isset($data)) {
916
                foreach ($data as $key => $val) {
917
                    if (isset($val[$user['user_id']])) {
918
                        if (is_array($val[$user['user_id']])) {
919
                            $userRow[$defaultExtraFieldInfo[$key]['variable']] = implode(
920
                                ', ',
921
                                $val[$user['user_id']]
922
                            );
923
                        } else {
924
                            $userRow[$defaultExtraFieldInfo[$key]['variable']] = $val[$user['user_id']];
925
                        }
926
                    } else {
927
                        $userRow[$defaultExtraFieldInfo[$key]['variable']] = '';
928
                    }
929
                }
930
            }
931
932
            if (api_get_setting('show_email_addresses') === 'true') {
933
                $userRow['email'] = $user['col4'];
934
            }
935
936
            $userRow['link'] = $user['link'];
937
938
            if ($GLOBALS['export_csv']) {
939
                unset($userRow['link']);
940
                $csvContent[] = $userRow;
941
            }
942
            $users[] = array_values($userRow);
943
        }
944
945
        if ($GLOBALS['export_csv']) {
946
            Session::write('csv_content', $csvContent);
947
        }
948
949
        Session::erase('additional_user_profile_info');
950
        Session::erase('extra_field_info');
951
        Session::erase('default_additional_user_profile_info');
952
        Session::erase('default_extra_field_info');
953
        Session::write('user_id_list', $userIdList);
954
955
        return $users;
956
    }
957
958
    /**
959
     * Get data for users list in sortable with pagination.
960
     */
961
    public static function getTotalTimeReport(
962
        $from,
963
        $numberOfItems,
964
        $column,
965
        $direction,
966
        bool $includeInvitedUsers = false
967
    ): array {
968
        global $user_ids, $course_code, $export_csv, $session_id;
969
970
        $course_code = Database::escape_string($course_code);
971
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
972
        $tblUrlRelUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
973
        $accessUrlId = api_get_current_access_url_id();
974
975
        // get all users data from a course for sortable with limit
976
        if (is_array($user_ids)) {
977
            $user_ids = array_map('intval', $user_ids);
978
            $conditionUser = " WHERE user.user_id IN (".implode(',', $user_ids).") ";
979
        } else {
980
            $user_ids = intval($user_ids);
981
            $conditionUser = " WHERE user.user_id = $user_ids ";
982
        }
983
984
        $urlTable = null;
985
        $urlCondition = null;
986
        if (api_is_multiple_url_enabled()) {
987
            $urlTable = ", ".$tblUrlRelUser." as url_users";
988
            $urlCondition = " AND user.user_id = url_users.user_id AND access_url_id='$accessUrlId'";
989
        }
990
991
        $invitedUsersCondition = '';
992
        if (!$includeInvitedUsers) {
993
            $invitedUsersCondition = " AND user.status != ".INVITEE;
994
        }
995
996
        $sql = "SELECT  user.user_id as user_id,
997
                    user.official_code  as col0,
998
                    user.lastname       as col1,
999
                    user.firstname      as col2,
1000
                    user.username       as col3
1001
                FROM $tblUser as user $urlTable
1002
                $conditionUser $urlCondition $invitedUsersCondition";
1003
1004
        if (!in_array($direction, ['ASC', 'DESC'])) {
1005
            $direction = 'ASC';
1006
        }
1007
1008
        $column = (int) $column;
1009
        $from = (int) $from;
1010
        $numberOfItems = (int) $numberOfItems;
1011
1012
        $sql .= " ORDER BY col$column $direction ";
1013
        $sql .= " LIMIT $from,$numberOfItems";
1014
1015
        $res = Database::query($sql);
1016
        $users = [];
1017
1018
        $sortByFirstName = api_sort_by_first_name();
1019
        $courseInfo = api_get_course_info($course_code);
1020
        $courseId = $courseInfo['real_id'];
1021
1022
        while ($user = Database::fetch_array($res, 'ASSOC')) {
1023
            $user['official_code'] = $user['col0'];
1024
            $user['lastname'] = $user['col1'];
1025
            $user['firstname'] = $user['col2'];
1026
            $user['username'] = $user['col3'];
1027
1028
            $totalCourseTime = Tracking::get_time_spent_on_the_course(
1029
                $user['user_id'],
1030
                $courseId,
1031
                $session_id
1032
            );
1033
1034
            $user['time'] = api_time_to_hms($totalCourseTime);
1035
            $totalLpTime = Tracking::get_time_spent_in_lp(
1036
                $user['user_id'],
1037
                $course_code,
1038
                [],
1039
                $session_id
1040
            );
1041
1042
            $warning = '';
1043
            if ($totalLpTime > $totalCourseTime) {
1044
                $warning = '&nbsp;'.Display::label(get_lang('TimeDifference'), 'danger');
1045
            }
1046
1047
            $user['total_lp_time'] = api_time_to_hms($totalLpTime).$warning;
1048
1049
            $user['first_connection'] = Tracking::get_first_connection_date_on_the_course(
1050
                $user['user_id'],
1051
                $courseId,
1052
                $session_id
1053
            );
1054
            $user['last_connection'] = Tracking::get_last_connection_date_on_the_course(
1055
                $user['user_id'],
1056
                $courseInfo,
1057
                $session_id,
1058
                $export_csv === false
1059
            );
1060
1061
            $user['link'] = '<center>
1062
                             <a href="../mySpace/myStudents.php?student='.$user['user_id'].'&details=true&course='.$course_code.'&origin=tracking_course&id_session='.$session_id.'">
1063
                             '.Display::return_icon('2rightarrow.png', get_lang('Details')).'
1064
                             </a>
1065
                         </center>';
1066
1067
            // store columns in array $users
1068
            $userRow = [];
1069
            $userRow['official_code'] = $user['official_code']; //0
1070
            if ($sortByFirstName) {
1071
                $userRow['firstname'] = $user['firstname'];
1072
                $userRow['lastname'] = $user['lastname'];
1073
            } else {
1074
                $userRow['lastname'] = $user['lastname'];
1075
                $userRow['firstname'] = $user['firstname'];
1076
            }
1077
            $userRow['username'] = $user['username'];
1078
            $userRow['time'] = $user['time'];
1079
            $userRow['total_lp_time'] = $user['total_lp_time'];
1080
            $userRow['first_connection'] = $user['first_connection'];
1081
            $userRow['last_connection'] = $user['last_connection'];
1082
1083
            $userRow['link'] = $user['link'];
1084
            $users[] = array_values($userRow);
1085
        }
1086
1087
        return $users;
1088
    }
1089
1090
    public static function actionsLeft($current, $sessionId = 0): string
1091
    {
1092
        $usersLink = Display::url(
1093
            Display::return_icon('user.png', get_lang('StudentsTracking'), [], ICON_SIZE_MEDIUM),
1094
            'courseLog.php?'.api_get_cidreq(true, false)
1095
        );
1096
1097
        $groupsLink = Display::url(
1098
            Display::return_icon('group.png', get_lang('GroupReporting'), [], ICON_SIZE_MEDIUM),
1099
            'course_log_groups.php?'.api_get_cidreq()
1100
        );
1101
1102
        $resourcesLink = Display::url(
1103
            Display::return_icon('tools.png', get_lang('ResourcesTracking'), [], ICON_SIZE_MEDIUM),
1104
            'course_log_resources.php?'.api_get_cidreq(true, false)
1105
        );
1106
1107
        $courseLink = Display::url(
1108
            Display::return_icon('course.png', get_lang('CourseTracking'), [], ICON_SIZE_MEDIUM),
1109
            'course_log_tools.php?'.api_get_cidreq(true, false)
1110
        );
1111
1112
        $examLink = Display::url(
1113
            Display::return_icon('quiz.png', get_lang('ExamTracking'), [], ICON_SIZE_MEDIUM),
1114
            api_get_path(WEB_CODE_PATH).'tracking/exams.php?'.api_get_cidreq()
1115
        );
1116
1117
        $eventsLink = Display::url(
1118
            Display::return_icon('security.png', get_lang('EventsReport'), [], ICON_SIZE_MEDIUM),
1119
            api_get_path(WEB_CODE_PATH).'tracking/course_log_events.php?'.api_get_cidreq()
1120
        );
1121
1122
        $lpLink = Display::url(
1123
            Display::return_icon('scorms.png', get_lang('CourseLearningPathsGenericStats'), [], ICON_SIZE_MEDIUM),
1124
            api_get_path(WEB_CODE_PATH).'tracking/lp_report.php?'.api_get_cidreq()
1125
        );
1126
1127
        $attendanceLink = '';
1128
        if (!empty($sessionId)) {
1129
            $attendanceLink = Display::url(
1130
                Display::return_icon('attendance_list.png', get_lang('Logins'), '', ICON_SIZE_MEDIUM),
1131
                api_get_path(WEB_CODE_PATH).'attendance/index.php?'.api_get_cidreq().'&action=calendar_logins'
1132
            );
1133
        }
1134
1135
        switch ($current) {
1136
            case 'users':
1137
                $usersLink = Display::url(
1138
                    Display::return_icon(
1139
                        'user_na.png',
1140
                        get_lang('StudentsTracking'),
1141
                        [],
1142
                        ICON_SIZE_MEDIUM
1143
                    ),
1144
                    '#'
1145
                );
1146
                break;
1147
            case 'groups':
1148
                $groupsLink = Display::url(
1149
                    Display::return_icon('group_na.png', get_lang('GroupReporting'), [], ICON_SIZE_MEDIUM),
1150
                    '#'
1151
                );
1152
                break;
1153
            case 'courses':
1154
                $courseLink = Display::url(
1155
                    Display::return_icon('course_na.png', get_lang('CourseTracking'), [], ICON_SIZE_MEDIUM),
1156
                    '#'
1157
                );
1158
                break;
1159
            case 'resources':
1160
                $resourcesLink = Display::url(
1161
                    Display::return_icon(
1162
                        'tools_na.png',
1163
                        get_lang('ResourcesTracking'),
1164
                        [],
1165
                        ICON_SIZE_MEDIUM
1166
                    ),
1167
                    '#'
1168
                );
1169
                break;
1170
            case 'exams':
1171
                $examLink = Display::url(
1172
                    Display::return_icon('quiz_na.png', get_lang('ExamTracking'), [], ICON_SIZE_MEDIUM),
1173
                    '#'
1174
                );
1175
                break;
1176
            case 'logs':
1177
                $eventsLink = Display::url(
1178
                    Display::return_icon('security_na.png', get_lang('EventsReport'), [], ICON_SIZE_MEDIUM),
1179
                    '#'
1180
                );
1181
                break;
1182
            case 'attendance':
1183
                if (!empty($sessionId)) {
1184
                    $attendanceLink = Display::url(
1185
                        Display::return_icon('attendance_list.png', get_lang('Logins'), '', ICON_SIZE_MEDIUM),
1186
                        '#'
1187
                    );
1188
                }
1189
                break;
1190
            case 'lp':
1191
                $lpLink = Display::url(
1192
                    Display::return_icon(
1193
                        'scorms_na.png',
1194
                        get_lang('CourseLearningPathsGenericStats'),
1195
                        [],
1196
                        ICON_SIZE_MEDIUM
1197
                    ),
1198
                    '#'
1199
                );
1200
                break;
1201
        }
1202
1203
        $items = [
1204
            $usersLink,
1205
            $groupsLink,
1206
            $courseLink,
1207
            $resourcesLink,
1208
            $examLink,
1209
            $eventsLink,
1210
            $lpLink,
1211
            $attendanceLink,
1212
        ];
1213
1214
        return implode('', $items).'&nbsp;';
1215
    }
1216
1217
    public static function getTeachersOrCoachesHtmlHeader(
1218
        string $courseCode,
1219
        int $cId,
1220
        int $sessionId,
1221
        bool $addLinkToPrfile
1222
    ): string {
1223
        $html = '';
1224
1225
        $teacherList = CourseManager::getTeacherListFromCourseCodeToString(
1226
            $courseCode,
1227
            ',',
1228
            $addLinkToPrfile,
1229
            true
1230
        );
1231
1232
        if (!empty($teacherList)) {
1233
            $html .= Display::page_subheader2(get_lang('Teachers'));
1234
            $html .= $teacherList;
1235
        }
1236
1237
        if (!empty($sessionId)) {
1238
            $coaches = CourseManager::get_coachs_from_course_to_string(
1239
                $sessionId,
1240
                $cId,
1241
                ',',
1242
                $addLinkToPrfile,
1243
                true
1244
            );
1245
1246
            if (!empty($coaches)) {
1247
                $html .= Display::page_subheader2(get_lang('Coaches'));
1248
                $html .= $coaches;
1249
            }
1250
        }
1251
1252
        return $html;
1253
    }
1254
1255
    /**
1256
     * @return float|string
1257
     */
1258
    public static function calcBestScoreAverageNotInLP(
1259
        array $exerciseList,
1260
        array $usersInGroup,
1261
        int $cId,
1262
        int $sessionId = 0,
1263
        bool $returnFormatted = false
1264
    ) {
1265
        if (empty($exerciseList) || empty($usersInGroup)) {
1266
            return 0;
1267
        }
1268
1269
        $bestScoreAverageNotInLP = 0;
1270
1271
        foreach ($exerciseList as $exerciseData) {
1272
            foreach ($usersInGroup as $userId) {
1273
                $results = Event::get_best_exercise_results_by_user(
1274
                    $exerciseData['iid'],
1275
                    $cId,
1276
                    $sessionId,
1277
                    $userId
1278
                );
1279
1280
                $scores = array_map(
1281
                    function (array $result) {
1282
                        return empty($result['exe_weighting']) ? 0 : $result['exe_result'] / $result['exe_weighting'];
1283
                    },
1284
                    $results
1285
                );
1286
1287
                $bestScoreAverageNotInLP += $scores ? max($scores) : 0;
1288
            }
1289
        }
1290
1291
        $rounded = round(
1292
            $bestScoreAverageNotInLP / count($exerciseList) * 100 / count($usersInGroup),
1293
            2
1294
        );
1295
1296
        if ($returnFormatted) {
1297
            return sprintf(get_lang('XPercent'), $rounded);
1298
        }
1299
1300
        return $rounded;
1301
    }
1302
1303
    public static function protectIfNotAllowed()
1304
    {
1305
        $courseInfo = api_get_course_info();
1306
1307
        if (empty($courseInfo)) {
1308
            api_not_allowed(true);
1309
        }
1310
1311
        $sessionId = api_get_session_id();
1312
        $isAllowedToTrack = Tracking::isAllowToTrack($sessionId);
1313
1314
        if (!$isAllowedToTrack) {
1315
            api_not_allowed(true);
1316
        }
1317
1318
        $courseCode = $courseInfo['code'];
1319
1320
        // If the user is an HR director (drh)
1321
        if (!api_is_drh()) {
1322
            return;
1323
        }
1324
1325
        // Blocking course for drh
1326
        if (api_drh_can_access_all_session_content()) {
1327
            // If the drh has been configured to be allowed to see all session content, give him access to the session courses
1328
            $coursesFromSession = SessionManager::getAllCoursesFollowedByUser(api_get_user_id(), null);
1329
            $coursesFromSessionCodeList = [];
1330
1331
            if (!empty($coursesFromSession)) {
1332
                foreach ($coursesFromSession as $course) {
1333
                    $coursesFromSessionCodeList[$course['code']] = $course['code'];
1334
                }
1335
            }
1336
1337
            $coursesFollowedList = CourseManager::get_courses_followed_by_drh(api_get_user_id());
1338
1339
            if (!empty($coursesFollowedList)) {
1340
                $coursesFollowedList = array_keys($coursesFollowedList);
1341
            }
1342
1343
            if (!in_array($courseCode, $coursesFollowedList)
1344
                && !in_array($courseCode, $coursesFromSessionCodeList)
1345
            ) {
1346
                api_not_allowed(true);
1347
            }
1348
        } else {
1349
            // If the drh has *not* been configured to be allowed to see all session content,
1350
            // then check if he has also been given access to the corresponding courses
1351
            $coursesFollowedList = CourseManager::get_courses_followed_by_drh(api_get_user_id());
1352
            $coursesFollowedList = array_keys($coursesFollowedList);
1353
1354
            if (!in_array($courseCode, $coursesFollowedList)) {
1355
                api_not_allowed(true);
1356
            }
1357
        }
1358
    }
1359
1360
    public static function returnCourseGraphicalReport(
1361
        array $courseInfo,
1362
        int $sessionId = 0
1363
    ): string {
1364
        if (self::HIDE_COURSE_REPORT_GRAPH_HIDDEN == (int) api_get_configuration_value('hide_course_report_graph')) {
1365
            return '';
1366
        }
1367
1368
        $args = Session::read(
1369
            'course_log_args',
1370
            ['conditions' => [], 'parameters' => []]
1371
        );
1372
        Session::erase('course_log_args');
1373
1374
        $conditions = $args['conditions'];
1375
        $parameters = $args['parameters'];
1376
1377
        $courseCode = $courseInfo['code'];
1378
1379
        if (empty($sessionId)) {
1380
            // Registered students in a course outside session.
1381
            $studentList = CourseManager::get_student_list_from_course_code(
1382
                $courseCode,
1383
                false,
1384
                0,
1385
                null,
1386
                null,
1387
                true,
1388
                0,
1389
                false,
1390
                0,
1391
                0,
1392
                $parameters['user_active']
1393
            );
1394
        } else {
1395
            // Registered students in session.
1396
            $studentList = CourseManager::get_student_list_from_course_code(
1397
                $courseCode,
1398
                true,
1399
                $sessionId,
1400
                null,
1401
                null,
1402
                true,
1403
                0,
1404
                false,
1405
                0,
1406
                0,
1407
                $parameters['user_active']
1408
            );
1409
        }
1410
1411
        $GLOBALS['user_ids'] = array_keys($studentList);
1412
        $GLOBALS['course_code'] = $courseCode;
1413
        $GLOBALS['export_csv'] = false;
1414
        $GLOBALS['session_id'] = $sessionId;
1415
1416
        $nbStudents = count($studentList);
1417
1418
        $conditions['include_invited_users'] = false;
1419
1420
        $usersTracking = TrackingCourseLog::getUserData(
1421
            0,
1422
            $nbStudents,
1423
            0,
1424
            'ASC',
1425
            $conditions
1426
        );
1427
1428
        $numberStudentsCompletedLP = 0;
1429
        $averageStudentsTestScore = 0;
1430
        $scoresDistribution = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
1431
        $userScoreList = [];
1432
        $listStudentIds = [];
1433
        $timeStudent = [];
1434
        $certificateCount = 0;
1435
        $category = Category::load(
1436
            null,
1437
            null,
1438
            $courseCode,
1439
            null,
1440
            null,
1441
            $sessionId
1442
        );
1443
1444
        foreach ($usersTracking as $userTracking) {
1445
            $userInfo = api_get_user_info_from_username($userTracking[3]);
1446
1447
            if (empty($userInfo)) {
1448
                continue;
1449
            }
1450
1451
            $userId = $userInfo['user_id'];
1452
1453
            if ('100%' === $userTracking[5]) {
1454
                $numberStudentsCompletedLP++;
1455
            }
1456
1457
            $averageStudentTestScore = (float) $userTracking[7];
1458
            $averageStudentsTestScore += $averageStudentTestScore;
1459
1460
            $reducedAverage = $averageStudentTestScore === 100.0 ? 9 : floor($averageStudentTestScore / 10);
1461
1462
            if (isset($scoresDistribution[$reducedAverage])) {
1463
                $scoresDistribution[$reducedAverage]++;
1464
            }
1465
1466
            $scoreStudent = substr($userTracking[5], 0, -1) + substr($userTracking[7], 0, -1);
1467
            [$hours, $minutes, $seconds] = preg_split('/:/', $userTracking[4]);
1468
            $minutes = round((3600 * $hours + 60 * $minutes + $seconds) / 60);
1469
1470
            $certificate = false;
1471
1472
            if (isset($category[0]) && $category[0]->is_certificate_available($userId)) {
1473
                $certificate = true;
1474
                $certificateCount++;
1475
            }
1476
1477
            $listStudent = [
1478
                'id' => $userId,
1479
                'fullname' => $userInfo['complete_name'],
1480
                'score' => floor($scoreStudent / 2),
1481
                'total_time' => $minutes,
1482
                'avatar' => $userInfo['avatar'],
1483
                'certicate' => $certificate,
1484
            ];
1485
            $listStudentIds[] = $userId;
1486
            $userScoreList[] = $listStudent;
1487
        }
1488
1489
        uasort(
1490
            $userScoreList,
1491
            function ($a, $b) {
1492
                return $a['score'] <= $b['score'];
1493
            }
1494
        );
1495
1496
        $averageStudentsTestScore = 0;
1497
1498
        if ($nbStudents > 0) {
1499
            $averageStudentsTestScore = round($averageStudentsTestScore / $nbStudents);
1500
        }
1501
1502
        $colors = ChamiloApi::getColorPalette(true, true, 10);
1503
1504
        $tpl = new Template('', false, false, false, true, false, false);
1505
        $tpl->assign('chart_colors', json_encode($colors));
1506
        $tpl->assign('certificate_count', $certificateCount);
1507
        $tpl->assign('score_distribution', json_encode($scoresDistribution));
1508
        $tpl->assign('json_time_student', json_encode($userScoreList));
1509
        $tpl->assign('students_test_score', $averageStudentsTestScore);
1510
        $tpl->assign('students_completed_lp', $numberStudentsCompletedLP);
1511
        $tpl->assign('number_students', $nbStudents);
1512
        $tpl->assign('top_students', array_chunk($userScoreList, 3, true));
1513
1514
        return $tpl->fetch($tpl->get_template('tracking/tracking_course_log.tpl'));
1515
    }
1516
1517
    /**
1518
     * count the number of students in this course (used for SortableTable)
1519
     * Deprecated.
1520
     */
1521
    public function countStudentInCourse(): int
1522
    {
1523
        global $nbStudents;
1524
1525
        return $nbStudents;
1526
    }
1527
1528
    public function sortUsers($a, $b): int
1529
    {
1530
        $tracking = Session::read('tracking_column');
1531
1532
        return strcmp(
1533
            trim(api_strtolower($a[$tracking])),
1534
            trim(api_strtolower($b[$tracking]))
1535
        );
1536
    }
1537
1538
    public function sortUsersDesc($a, $b): int
1539
    {
1540
        $tracking = Session::read('tracking_column');
1541
1542
        return strcmp(
1543
            trim(api_strtolower($b[$tracking])),
1544
            trim(api_strtolower($a[$tracking]))
1545
        );
1546
    }
1547
}
1548