Passed
Push — dependabot/composer/symfony/se... ( 6a3ee0...ae0984 )
by
unknown
28:58 queued 18:58
created

TrackingCourseLog::getUserData()   F

Complexity

Conditions 66

Size

Total Lines 473
Code Lines 305

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 66
eloc 305
nop 11
dl 0
loc 473
rs 3.3333
c 1
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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