MySpace::getDataAccessTrackingFilters()   C
last analyzed

Complexity

Conditions 13
Paths 40

Size

Total Lines 33
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 20
c 0
b 0
f 0
nc 40
nop 1
dl 0
loc 33
rs 6.6166

How to fix   Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
5
use Chamilo\CoreBundle\Entity\User;
6
use Chamilo\CoreBundle\Framework\Container;
7
use ChamiloSession as Session;
8
use CpChart\Cache as pCache;
9
use CpChart\Data as pData;
10
use CpChart\Image as pImage;
11
12
/**
13
 * Class MySpace.
14
 */
15
class MySpace
16
{
17
    /**
18
     * Generate the list of admin actions to be shown
19
     * @return array
20
     */
21
    public static function generateAdminActionLinks(): array
22
    {
23
        $actions = [
24
            [
25
                'url' => api_get_path(WEB_CODE_PATH).'my_space/admin_view.php?display=coaches',
26
                'content' => get_lang('Trainers Overview'),
27
            ],
28
            [
29
                'url' => api_get_path(WEB_CODE_PATH).'my_space/admin_view.php?display=user',
30
                'content' => get_lang('User overview'),
31
            ],
32
            [
33
                'url' => api_get_path(WEB_CODE_PATH).'my_space/admin_view.php?display=session',
34
                'content' => get_lang('Sessions overview'),
35
            ],
36
            [
37
                'url' => api_get_path(WEB_CODE_PATH).'my_space/admin_view.php?display=course',
38
                'content' => get_lang('Courses overview'),
39
            ],
40
            [
41
                'url' => api_get_path(WEB_CODE_PATH).'tracking/question_course_report.php?view=admin',
42
                'content' => get_lang('Learning paths exercises results list'),
43
            ],
44
            [
45
                'url' => api_get_path(WEB_CODE_PATH).'tracking/course_session_report.php?view=admin',
46
                'content' => get_lang('Results of learning paths exercises by session'),
47
            ],
48
            [
49
                'url' => api_get_path(WEB_CODE_PATH).'my_space/admin_view.php?display=accessoverview',
50
                'content' => get_lang('Accesses by user overview').' ('.get_lang('Beta').')',
51
            ],
52
            [
53
                'url' => api_get_path(WEB_CODE_PATH).'my_space/exercise_category_report.php',
54
                'content' => get_lang('Exercise report by category for all sessions'),
55
            ],
56
            [
57
                'url' => api_get_path(WEB_CODE_PATH).'my_space/survey_report.php',
58
                'content' => get_lang('Surveys report'),
59
            ],
60
            [
61
                'url' => api_get_path(WEB_CODE_PATH).'my_space/tc_report.php',
62
                'content' => get_lang("Student's superior follow up"),
63
            ],
64
            [
65
                'url' => api_get_path(WEB_CODE_PATH).'my_space/ti_report.php',
66
                'content' => get_lang('General Coaches planning'),
67
            ],
68
            [
69
                'url' => api_get_path(WEB_CODE_PATH).'my_space/question_stats_global.php',
70
                'content' => get_lang('Question stats'),
71
            ],
72
            [
73
                'url' => api_get_path(WEB_CODE_PATH).'my_space/question_stats_global_detail.php',
74
                'content' => get_lang('Detailed questions stats'),
75
            ],
76
        ];
77
78
        $field = new ExtraField('user');
79
        $companyField = $field->get_handler_field_info_by_field_variable('company');
80
        if (!empty($companyField)) {
81
            $actions[] =
82
                [
83
                    'url' => api_get_path(WEB_CODE_PATH).'my_space/admin_view.php?display=company',
84
                    'content' => get_lang('User by organization'),
85
                ];
86
        }
87
        $field = new ExtraField('lp');
88
        $authorsField = $field->get_handler_field_info_by_field_variable('authors');
89
        if (!empty($authorsField)) {
90
            $actions[] =
91
                [
92
                    'url' => api_get_path(WEB_CODE_PATH).'my_space/admin_view.php?display=learningPath',
93
                    'content' => get_lang('Learning path by author'),
94
                ];
95
        }
96
        $field = new ExtraField('lp_item');
97
        $authorsItemField = $field->get_handler_field_info_by_field_variable('authorlpitem');
98
        if (!empty($authorsItemField)) {
99
            $actions[] =
100
                [
101
                    'url' => api_get_path(WEB_CODE_PATH).'my_space/admin_view.php?display=learningPathByItem',
102
                    'content' => get_lang('LP item by author'),
103
                ];
104
        }
105
        return $actions;
106
    }
107
108
    /**
109
     * @return string
110
     */
111
    public static function getTopMenu()
112
    {
113
        $menuItems = [];
114
115
        // Always available: student's own progress
116
        $menuItems[] = Display::url(
117
            Display::getMdiIcon('chart-box', 'ch-tool-icon', null, 32, get_lang('View my progress')),
118
            api_get_path(WEB_CODE_PATH).'auth/my_progress.php'
119
        );
120
121
        // Trainer view: only for course teachers / coaches
122
        if (api_is_allowed_to_edit(null, true)) {
123
            $menuItems[] = Display::url(
124
                Display::getMdiIcon('human-male-board', 'ch-tool-icon', null, 32, get_lang('Trainer View')),
125
                api_get_path(WEB_CODE_PATH).'my_space/index.php?view=teacher'
126
            );
127
        }
128
129
        // Admin view: only for platform admins and DRH
130
        if (api_is_platform_admin() || api_is_drh()) {
131
            $menuItems[] = Display::url(
132
                Display::getMdiIcon('star', 'ch-tool-icon', null, 32, get_lang('Admin view')),
133
                api_get_path(WEB_CODE_PATH).'my_space/index.php?view=admin'
134
            );
135
        }
136
137
        // Exam tracking
138
        if (api_is_platform_admin() || api_is_drh() || api_is_allowed_to_edit(null, true)) {
139
            $menuItems[] = Display::url(
140
                Display::getMdiIcon('order-bool-ascending-variant', 'ch-tool-icon', null, 32, get_lang('Exam tracking')),
141
                api_get_path(WEB_CODE_PATH).'tracking/exams.php'
142
            );
143
        }
144
145
        return Display::toolbarAction('myspace', $menuItems);
146
    }
147
148
    /**
149
     * This function serves exporting data in CSV format.
150
     *
151
     * @param array  $header    the header labels
152
     * @param array  $data      the data array
153
     * @param string $file_name the name of the file which contains exported data
154
     *
155
     * @return string mixed             Returns a message (string) if an error occurred
156
     */
157
    public function export_csv($header, $data, $file_name = 'export.csv')
158
    {
159
        $archive_path = api_get_path(SYS_ARCHIVE_PATH);
160
        $archive_url = api_get_path(WEB_CODE_PATH).'course_info/download.php?archive_path=&archive=';
161
        $message = '';
162
        if (!$open = fopen($archive_path.$file_name, 'w+')) {
163
            $message = get_lang('Could not open');
164
        } else {
165
            $info = '';
166
167
            foreach ($header as $value) {
168
                $info .= $value.';';
169
            }
170
            $info .= "\r\n";
171
172
            foreach ($data as $row) {
173
                foreach ($row as $value) {
174
                    $info .= $value.';';
175
                }
176
                $info .= "\r\n";
177
            }
178
179
            fwrite($open, $info);
180
            fclose($open);
181
            @chmod($file_name, api_get_permissions_for_new_files());
182
183
            header("Location:".$archive_url.$file_name);
184
            exit;
185
        }
186
187
        return $message;
188
    }
189
190
    /**
191
     * Gets the connections to a course as an array of login and logout time.
192
     *
193
     * @param int   $userId     User id
194
     * @param array $courseInfo
195
     * @param int   $sessionId  Session id (optional, default = 0)
196
     *
197
     * @return array Connections
198
     */
199
    public static function get_connections_to_course(
200
        $userId,
201
        $courseInfo,
202
        $sessionId = 0
203
    ) {
204
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
205
206
        // protect data
207
        $userId = (int) $userId;
208
        $courseId = (int) $courseInfo['real_id'];
209
        $sessionId = (int) $sessionId;
210
        $sessionCondition = api_get_session_condition($sessionId);
211
212
        $sql = 'SELECT login_course_date, logout_course_date
213
                FROM '.$table.'
214
                WHERE
215
                    user_id = '.$userId.' AND
216
                    c_id = '.$courseId.'
217
                    '.$sessionCondition.'
218
                ORDER BY login_course_date ASC';
219
        $rs = Database::query($sql);
220
        $connections = [];
221
222
        while ($row = Database::fetch_array($rs)) {
223
            $connections[] = [
224
                'login' => $row['login_course_date'],
225
                'logout' => $row['logout_course_date'],
226
            ];
227
        }
228
229
        return $connections;
230
    }
231
232
    /**
233
     * @param $user_id
234
     * @param $course_list
235
     * @param int $session_id
236
     *
237
     * @return array|bool
238
     */
239
    public static function get_connections_from_course_list(
240
        $user_id,
241
        $course_list,
242
        $session_id = 0
243
    ) {
244
        // Database table definitions
245
        $tbl_track_course = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
246
        if (empty($course_list)) {
247
            return false;
248
        }
249
250
        // protect data
251
        $user_id = (int) $user_id;
252
        $session_id = (int) $session_id;
253
        $new_course_list = [];
254
        foreach ($course_list as $course_item) {
255
            $courseInfo = api_get_course_info($course_item['code']);
256
            if ($courseInfo) {
257
                $courseId = $courseInfo['real_id'];
258
                $new_course_list[] = '"'.$courseId.'"';
259
            }
260
        }
261
        $course_list = implode(', ', $new_course_list);
262
263
        if (empty($course_list)) {
264
            return false;
265
        }
266
        $sql = 'SELECT login_course_date, logout_course_date, c_id
267
                FROM '.$tbl_track_course.'
268
                WHERE
269
                    user_id = '.$user_id.' AND
270
                    c_id IN ('.$course_list.') AND
271
                    session_id = '.$session_id.'
272
                ORDER BY login_course_date ASC';
273
        $rs = Database::query($sql);
274
        $connections = [];
275
276
        while ($row = Database::fetch_array($rs)) {
277
            $timestamp_login_date = api_strtotime($row['login_course_date'], 'UTC');
278
            $timestamp_logout_date = api_strtotime($row['logout_course_date'], 'UTC');
279
            $connections[] = [
280
                'login' => $timestamp_login_date,
281
                'logout' => $timestamp_logout_date,
282
                'c_id' => $row['c_id'],
283
            ];
284
        }
285
286
        return $connections;
287
    }
288
289
    /**
290
     * Creates a small table in the last column of the table with the user overview.
291
     *
292
     * @return array List course
293
     */
294
    public static function returnCourseTracking(User $user)
295
    {
296
        $userId = $user->getId();
297
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
298
        // getting all the courses of the user
299
        $sql = "SELECT * FROM $tbl_course_user
300
                WHERE
301
                    user_id = $userId AND
302
                    relation_type <> ".COURSE_RELATION_TYPE_RRHH;
303
        $result = Database::query($sql);
304
305
        $list = [];
306
307
        while ($row = Database::fetch_array($result)) {
308
            $course = api_get_course_entity($row['c_id']);
309
310
            if (null === $course) {
311
                continue;
312
            }
313
314
            $courseId = $course->getId();
315
            $courseCode = $course->getCode();
316
317
            $avg_score = Tracking::get_avg_student_score($userId, $course);
318
            if (is_numeric($avg_score)) {
319
                $avg_score = round($avg_score, 2);
320
            } else {
321
                $avg_score = '-';
322
            }
323
324
            // Student exercises results (obtained score, maximum score, number of exercises answered, score percentage)
325
            $exercisesResults = self::exercises_results($userId, $courseCode);
326
327
            $resultToString = '';
328
            if (!is_null($exercisesResults['percentage'])) {
329
                $resultToString =
330
                    $exercisesResults['score_obtained'].'/'.$exercisesResults['score_possible'].
331
                    ' ( '.$exercisesResults['percentage'].'% )';
332
            }
333
334
            $item = [
335
                'code' => $courseCode,
336
                'real_id' => $courseId,
337
                'title' => $course->getTitle(),
338
                'category' => '',
339
                //'category' => $courseInfo['categoryName'], // @todo show categories instead of 1 category
340
                //'image_small' => $courseInfo['course_image'],
341
                //'image_large' => $courseInfo['course_image_large'],
342
                'time_spent' => api_time_to_hms(Tracking::get_time_spent_on_the_course($userId, $courseId)),
343
                'student_progress' => round(Tracking::get_avg_student_progress($userId, $course)),
344
                'student_score' => $avg_score,
345
                'student_message' => Container::getForumPostRepository()->countUserForumPosts($user, $course),
346
                'student_assignments' => Container::getStudentPublicationRepository()->countUserPublications($user, $course),
347
                'student_exercises' => $resultToString,
348
                'questions_answered' => $exercisesResults['questions_answered'],
349
                'last_connection' => Tracking::get_last_connection_date_on_the_course(
350
                    $userId,
351
                    ['real_id' => $courseId]
352
                ),
353
            ];
354
            $list[] = $item;
355
        }
356
357
        return $list;
358
    }
359
360
    /**
361
     * Display a sortable table that contains an overview off all the
362
     * reporting progress of all users and all courses the user is subscribed to.
363
     *
364
     * @author Patrick Cool <[email protected]>, Ghent University, Belgium
365
     *          Alex Aragon <[email protected]>, BeezNest, Perú
366
     *
367
     * @version Chamilo 1.11.8
368
     *
369
     * @since April 2019
370
     */
371
    public static function returnTrackingUserOverviewFilter($userId)
372
    {
373
        $tpl = new Template('', false, false, false, false, false, false);
374
        $user = api_get_user_entity($userId);
375
        $url = Container::getIllustrationRepository()->getIllustrationUrl($user);
376
377
        $item = [
378
            'id' => $user->getId(),
379
            'code_user' => $user->getOfficialCode(),
380
            'complete_name' => UserManager::formatUserFullName($user),
381
            'username' => $user->getUsername(),
382
            'course' => self::returnCourseTracking($user),
383
            'avatar' => $url,
384
        ];
385
386
        $tpl->assign('item', $item);
387
        $templateName = $tpl->get_template('my_space/partials/tracking_user_overview.tpl');
388
389
        return $tpl->fetch($templateName);
390
    }
391
392
    /**
393
     * Display a sortable table that contains an overview off all the
394
     * reporting progress of all users and all courses the user is subscribed to.
395
     *
396
     * @author Patrick Cool <[email protected]>, Ghent University, Belgium
397
     *         Alex Aragon <[email protected]>, BeezNest, Perú
398
     *
399
     * @version Chamilo 1.11.8
400
     *
401
     * @since October 2008, Update April 2019
402
     */
403
    public static function display_tracking_user_overview()
404
    {
405
        self::display_user_overview_export_options();
406
407
        $params = ['view' => 'admin', 'display' => 'user'];
408
        $table = new SortableTable(
409
            'tracking_user_overview',
410
            ['MySpace', 'get_number_of_users_tracking_overview'],
411
            ['MySpace', 'get_user_data_tracking_overview'],
412
            0,
413
            20,
414
            'ASC',
415
            null, [
416
                'class' => 'table table-transparent',
417
            ]
418
        );
419
        $table->additional_parameters = $params;
420
421
        $table->set_column_filter(0, ['MySpace', 'returnTrackingUserOverviewFilter']);
422
        $tableContent = $table->return_table();
423
        $tpl = new Template('', false, false, false, false, false, false);
424
        $tpl->assign('table', $tableContent);
425
        $templateName = $tpl->get_template('my_space/user_summary.tpl');
426
        echo $tpl->fetch($templateName);
427
    }
428
429
    /**
430
     * @param $export_csv
431
     */
432
    public static function display_tracking_coach_overview($export_csv)
433
    {
434
        if ($export_csv) {
435
            $is_western_name_order = api_is_western_name_order(PERSON_NAME_DATA_EXPORT);
436
        } else {
437
            $is_western_name_order = api_is_western_name_order();
438
        }
439
        $sort_by_first_name = api_sort_by_first_name();
440
441
        if (isset($_GET['tracking_list_coaches_column'])) {
442
            $tracking_column = (int) $_GET['tracking_list_coaches_column'];
443
        } else {
444
            $tracking_column = ($is_western_name_order xor $sort_by_first_name) ? 1 : 0;
445
        }
446
447
        $tracking_direction = (isset($_GET['tracking_list_coaches_direction']) && in_array(strtoupper($_GET['tracking_list_coaches_direction']), ['ASC', 'DESC', 'ASCENDING', 'DESCENDING', '0', '1'])) ? $_GET['tracking_list_coaches_direction'] : 'DESC';
448
        // Prepare array for column order - when impossible, use some of user names.
449
        if ($is_western_name_order) {
450
            $order = [
451
                0 => 'firstname',
452
                1 => 'lastname',
453
                2 => $sort_by_first_name ? 'firstname' : 'lastname',
454
                3 => 'login_date',
455
                4 => $sort_by_first_name ? 'firstname' : 'lastname',
456
                5 => $sort_by_first_name ? 'firstname' : 'lastname',
457
            ];
458
        } else {
459
            $order = [
460
                0 => 'lastname',
461
                1 => 'firstname',
462
                2 => $sort_by_first_name ? 'firstname' : 'lastname',
463
                3 => 'login_date',
464
                4 => $sort_by_first_name ? 'firstname' : 'lastname',
465
                5 => $sort_by_first_name ? 'firstname' : 'lastname',
466
            ];
467
        }
468
        $table = new SortableTable(
469
            'tracking_list_coaches_myspace',
470
            null,
471
            null,
472
            ($is_western_name_order xor $sort_by_first_name) ? 1 : 0
473
        );
474
        $parameters['view'] = 'admin';
475
        $table->set_additional_parameters($parameters);
476
        if ($is_western_name_order) {
477
            $table->set_header(0, get_lang('First name'), true);
478
            $table->set_header(1, get_lang('Last name'), true);
479
        } else {
480
            $table->set_header(0, get_lang('Last name'), true);
481
            $table->set_header(1, get_lang('First name'), true);
482
        }
483
        $table->set_header(2, get_lang('Time spent in portal'), false);
484
        $table->set_header(3, get_lang('Latest login'), false);
485
        $table->set_header(4, get_lang('Learners'), false);
486
        $table->set_header(5, get_lang('Courses'), false);
487
        $table->set_header(6, get_lang('Number of sessions'), false);
488
        $table->set_header(7, get_lang('Course sessions'), false);
489
490
        if ($is_western_name_order) {
491
            $csv_header[] = [
492
                get_lang('First name'),
493
                get_lang('Last name'),
494
                get_lang('Time spent in portal'),
495
                get_lang('Latest login'),
496
                get_lang('Learners'),
497
                get_lang('Courses'),
498
                get_lang('Number of sessions'),
499
            ];
500
        } else {
501
            $csv_header[] = [
502
                get_lang('Last name'),
503
                get_lang('First name'),
504
                get_lang('Time spent in portal'),
505
                get_lang('Latest login'),
506
                get_lang('Learners'),
507
                get_lang('Courses'),
508
                get_lang('Number of sessions'),
509
            ];
510
        }
511
512
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
513
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
514
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
515
        $tblSessionRelUser = Database::get_main_table(TABLE_MAIN_SESSION_USER);
516
517
        $sqlCoachs = "SELECT DISTINCT
518
                        scu.user_id as id_coach,
519
                        u.id as user_id,
520
                        lastname,
521
                        firstname,
522
                        MAX(login_date) as login_date
523
                        FROM $tbl_user u, $tbl_session_course_user scu, $tbl_track_login
524
                        WHERE
525
                            u.active <> ".USER_SOFT_DELETED." AND scu.user_id = u.id AND scu.status=".SessionEntity::COURSE_COACH." AND login_user_id=u.id
526
                        GROUP BY user_id ";
527
528
        if (api_is_multiple_url_enabled()) {
529
            $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
530
            $access_url_id = api_get_current_access_url_id();
531
            if (-1 != $access_url_id) {
532
                $sqlCoachs = "SELECT DISTINCT
533
                                    scu.user_id as id_coach,
534
                                    u.id as user_id,
535
                                    lastname,
536
                                    firstname,
537
                                    MAX(login_date) as login_date
538
                                FROM $tbl_user u,
539
                                $tbl_session_course_user scu,
540
                                $tbl_track_login ,
541
                                $tbl_session_rel_access_url session_rel_url
542
                                WHERE
543
                                    scu.user_id = u.id AND
544
                                    scu.status = ".SessionEntity::COURSE_COACH." AND
545
                                    login_user_id = u.id AND
546
                                    access_url_id = $access_url_id AND
547
                                    session_rel_url.session_id = scu.session_id
548
                                GROUP BY u.id";
549
            }
550
        }
551
        if (!empty($order[$tracking_column])) {
552
            $sqlCoachs .= " ORDER BY `".$order[$tracking_column]."` ".$tracking_direction;
553
        }
554
555
        $result_coaches = Database::query($sqlCoachs);
556
        $global_coaches = [];
557
        while ($coach = Database::fetch_array($result_coaches)) {
558
            $global_coaches[$coach['user_id']] = $coach;
559
        }
560
561
        $sql_session_coach = "SELECT u.id AS user_id, u.lastname, u.firstname, MAX(tel.login_date) AS login_date
562
                                FROM $tbl_user u
563
                                INNER JOIN $tbl_track_login tel
564
                                ON tel.login_user_id = u.id
565
                                INNER JOIN $tblSessionRelUser sru
566
                                ON (u.id = sru.user_id AND sru.relation_type = ".SessionEntity::GENERAL_COACH.")
567
                                GROUP BY u.id
568
                                ORDER BY login_date $tracking_direction";
569
570
        if (api_is_multiple_url_enabled()) {
571
            $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
572
            $access_url_id = api_get_current_access_url_id();
573
            if (-1 != $access_url_id) {
574
                $sql_session_coach = "SELECT u.id AS user_id, u.lastname, u.firstname, MAX(tel.login_date) AS login_date
575
                    FROM $tbl_user u
576
                    INNER JOIN $tbl_track_login  tel
577
                    ON tel.login_user_id = u.id
578
                    INNER JOIN $tblSessionRelUser sru
579
                    ON (u.id = sru.user_id AND sru.relation_type = ".SessionEntity::GENERAL_COACH.")
580
                    INNER JOIN $tbl_session_rel_access_url aurs
581
                    ON sru.session_id = aurs.session_id
582
                    WHERE aurs.access_url_id = $access_url_id
583
                    GROUP BY u.id
584
					ORDER BY login_date $tracking_direction";
585
            }
586
        }
587
588
        $result_sessions_coach = Database::query($sql_session_coach);
589
        //$total_no_coaches += Database::num_rows($result_sessions_coach);
590
        while ($coach = Database::fetch_array($result_sessions_coach)) {
591
            $global_coaches[$coach['user_id']] = $coach;
592
        }
593
594
        $all_datas = [];
595
        foreach ($global_coaches as $id_coach => $coaches) {
596
            $time_on_platform = api_time_to_hms(
597
                Tracking::get_time_spent_on_the_platform($coaches['user_id'])
598
            );
599
            $last_connection = Tracking::get_last_connection_date(
600
                $coaches['user_id']
601
            );
602
            $nb_students = count(
603
                Tracking::get_student_followed_by_coach($coaches['user_id'])
604
            );
605
            $nb_courses = count(
606
                Tracking::get_courses_followed_by_coach($coaches['user_id'])
607
            );
608
            $nb_sessions = count(
609
                Tracking::get_sessions_coached_by_user($coaches['user_id'])
610
            );
611
612
            $table_row = [];
613
            if ($is_western_name_order) {
614
                $table_row[] = $coaches['firstname'];
615
                $table_row[] = $coaches['lastname'];
616
            } else {
617
                $table_row[] = $coaches['lastname'];
618
                $table_row[] = $coaches['firstname'];
619
            }
620
            $table_row[] = $time_on_platform;
621
            $table_row[] = $last_connection;
622
            $table_row[] = $nb_students;
623
            $table_row[] = $nb_courses;
624
            $table_row[] = $nb_sessions;
625
            $table_row[] = '<a href="session.php?id_coach='.$coaches['user_id'].'">
626
                '.Display::getMdiIcon('arrow-left-bold-box', 'ch-tool-icon', null, 22, get_lang('Details')).'
627
            </a>';
628
            $all_datas[] = $table_row;
629
630
            if ($is_western_name_order) {
631
                $csv_content[] = [
632
                    api_html_entity_decode($coaches['firstname'], ENT_QUOTES),
633
                    api_html_entity_decode($coaches['lastname'], ENT_QUOTES),
634
                    $time_on_platform,
635
                    $last_connection,
636
                    $nb_students,
637
                    $nb_courses,
638
                    $nb_sessions,
639
                ];
640
            } else {
641
                $csv_content[] = [
642
                    api_html_entity_decode($coaches['lastname'], ENT_QUOTES),
643
                    api_html_entity_decode($coaches['firstname'], ENT_QUOTES),
644
                    $time_on_platform,
645
                    $last_connection,
646
                    $nb_students,
647
                    $nb_courses,
648
                    $nb_sessions,
649
                ];
650
            }
651
        }
652
653
        if (3 != $tracking_column) {
654
            if ('DESC' === $tracking_direction) {
655
                usort($all_datas, ['MySpace', 'rsort_users']);
656
            } else {
657
                usort($all_datas, ['MySpace', 'sort_users']);
658
            }
659
        }
660
661
        if ($export_csv && 3 != $tracking_column) {
662
            usort($csv_content, 'sort_users');
663
        }
664
        if ($export_csv) {
665
            $csv_content = array_merge($csv_header, $csv_content);
666
        }
667
668
        foreach ($all_datas as $row) {
669
            $table->addRow($row, 'align="right"');
670
        }
671
        $table->display();
672
    }
673
674
    public static function sort_users($a, $b)
675
    {
676
        $tracking = Session::read('tracking_column', 0);
677
678
        return api_strcmp(
679
            trim(api_strtolower($a[$tracking])),
680
            trim(api_strtolower($b[$tracking]))
681
        );
682
    }
683
684
    public static function rsort_users($a, $b)
685
    {
686
        $tracking = Session::read('tracking_column', 0);
687
688
        return api_strcmp(
689
            trim(api_strtolower($b[$tracking])),
690
            trim(api_strtolower($a[$tracking]))
691
        );
692
    }
693
694
    /**
695
     * Displays a form with all the additionally defined user fields of the profile
696
     * and give you the opportunity to include these in the CSV export.
697
     *
698
     * @author Patrick Cool <[email protected]>, Ghent University, Belgium
699
     *
700
     * @version 1.8.6
701
     *
702
     * @since November 2008
703
     */
704
    public static function display_user_overview_export_options()
705
    {
706
        $message = '';
707
        $defaults = [];
708
        // include the user manager and formvalidator library
709
        if (isset($_GET['export']) && 'options' == $_GET['export']) {
710
            // get all the defined extra fields
711
            $extrafields = UserManager::get_extra_fields(
712
                0,
713
                50,
714
                5,
715
                'ASC',
716
                false,
717
                1
718
            );
719
720
            // creating the form with all the defined extra fields
721
            $form = new FormValidator(
722
                'exportextrafields',
723
                'post',
724
                api_get_self()."?view=".Security::remove_XSS($_GET['view']).'&display='.Security::remove_XSS($_GET['display']).'&export='.Security::remove_XSS($_GET['export'])
725
            );
726
727
            if (is_array($extrafields) && count($extrafields) > 0) {
728
                foreach ($extrafields as $key => $extra) {
729
                    $form->addElement('checkbox', 'extra_export_field'.$extra[0], '', $extra[3]);
730
                }
731
                $form->addButtonSave(get_lang('Validate'), 'submit');
732
733
                // setting the default values for the form that contains all the extra fields
734
                $exportFields = Session::read('additional_export_fields');
735
                if (is_array($exportFields)) {
736
                    foreach ($exportFields as $key => $value) {
737
                        $defaults['extra_export_field'.$value] = 1;
738
                    }
739
                }
740
                $form->setDefaults($defaults);
741
            } else {
742
                $form->addElement('html', Display::return_message(get_lang('There are not extra fields available'), 'warning'));
743
            }
744
745
            if ($form->validate()) {
746
                // exporting the form values
747
                $values = $form->exportValues();
748
749
                // re-initialising the session that contains the additional fields that need to be exported
750
                Session::write('additional_export_fields', []);
751
752
                // adding the fields that are checked to the session
753
                $message = '';
754
                $additionalExportFields = [];
755
                foreach ($values as $field_ids => $value) {
756
                    if (1 == $value && strstr($field_ids, 'extra_export_field')) {
757
                        $additionalExportFields[] = str_replace('extra_export_field', '', $field_ids);
758
                    }
759
                }
760
                Session::write('additional_export_fields', $additionalExportFields);
761
762
                // adding the fields that will be also exported to a message string
763
                $additionalExportFields = Session::read('additional_export_fields');
764
                if (is_array($additionalExportFields)) {
765
                    foreach ($additionalExportFields as $key => $extra_field_export) {
766
                        $message .= '<li>'.$extrafields[$extra_field_export][3].'</li>';
767
                    }
768
                }
769
770
                // Displaying a feedback message
771
                if (!empty($additionalExportFields)) {
772
                    echo Display::return_message(
773
                        get_lang('The following fields will also be exported').': <br /><ul>'.$message.'</ul>',
774
                        'confirm',
775
                        false
776
                    );
777
                } else {
778
                    echo Display::return_message(
779
                        get_lang('No additional fields will be exported'),
780
                        'confirm',
781
                        false
782
                    );
783
                }
784
            } else {
785
                $form->display();
786
            }
787
        } else {
788
            $additionalExportFields = Session::read('additional_export_fields');
789
            if (!empty($additionalExportFields)) {
790
                // get all the defined extra fields
791
                $extrafields = UserManager::get_extra_fields(0, 50, 5, 'ASC');
792
793
                foreach ($additionalExportFields as $key => $extra_field_export) {
794
                    $message .= '<li>'.$extrafields[$extra_field_export][3].'</li>';
795
                }
796
797
                echo Display::return_message(
798
                    get_lang('The following fields will also be exported').': <br /><ul>'.$message.'</ul>',
799
                    'normal',
800
                    false
801
                );
802
            }
803
        }
804
    }
805
806
    /**
807
     * Export to cvs a list of users who were enrolled in the lessons.
808
     * It is necessary that in the extra field, a company is defined.
809
     *
810
     * @param string|null $startDate
811
     * @param string|null $endDate
812
     *
813
     * @return array
814
     */
815
    public static function exportCompanyResumeCsv($startDate, $endDate)
816
    {
817
        $companys = self::getCompanyLearnpathSubscription($startDate, $endDate);
818
        $csv_content = [];
819
        // Printing table
820
        $total = 0;
821
        $displayText = get_lang('Company');
822
        // the first line of the csv file with the column headers
823
        $csv_row = [];
824
        $csv_row[] = $displayText;
825
826
        $csv_row[] = get_lang('Subscribed users count');
827
        $csv_content[] = $csv_row;
828
829
        foreach ($companys as $entity => $student) {
830
            $csv_row = [];
831
            // user official code
832
            $csv_row[] = $entity;
833
            $csv_row[] = count($student);
834
            $total += count($student);
835
            $csv_content[] = $csv_row;
836
        }
837
838
        $csv_row = [];
839
        // user official code
840
        $csv_row[] = get_lang('General total');
841
        $csv_row[] = $total;
842
        $csv_content[] = $csv_row;
843
        Export::arrayToCsv($csv_content, 'reporting_company_resume');
844
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
845
    }
846
847
    /**
848
     * Displays a list as a table of users who were enrolled in the lessons.
849
     * It is necessary that in the extra field, a company is defined.
850
     *
851
     * @param string|null $startDate
852
     * @param string|null $endDate
853
     */
854
    public static function displayResumeCompany(
855
        $startDate = null,
856
        $endDate = null
857
    ) {
858
        $companys = self::getCompanyLearnpathSubscription($startDate, $endDate);
859
        $tableHtml = '';
860
        // Printing table
861
        $total = 0;
862
        $table = '<div class="table-responsive"><table class="table table-hover table-striped table-bordered data_table">';
863
864
        $displayText = get_lang('Company');
865
        $table .= "<thead><tr><th class=\"th-header\">$displayText</th><th class=\"th-header\"> ".get_lang('Subscribed users count')." </th></tr></thead><tbody>";
866
867
        foreach ($companys as $entity => $student) {
868
            $table .= "<tr><td>$entity</td><td>".count($student)."</td></tr>";
869
            $total += count($student);
870
        }
871
        $table .= "<tr><td>".get_lang('General total')."</td><td>$total</td></tr>";
872
        $table .= '</tbody></table></div>';
873
874
        if (!empty($startDate) or !empty($endDate)) {
875
            $tableHtml = $table;
876
        }
877
878
        $form = new FormValidator('searchDate', 'get');
879
        $form->addHidden('display', 'company');
880
        $today = new DateTime();
881
        if (empty($startDate)) {
882
            $startDate = api_get_local_time($today->modify('first day of this month')->format('Y-m-d'));
883
        }
884
        if (empty($endDate)) {
885
            $endDate = api_get_local_time($today->modify('last day of this month')->format('Y-m-d'));
886
        }
887
        $form->addDatePicker(
888
            'startDate',
889
            get_lang('Start date'),
890
            [
891
                'value' => $startDate,
892
            ]);
893
        $form->addDatePicker(
894
            'endDate',
895
            get_lang('End date'),
896
            [
897
                'value' => $endDate,
898
            ]);
899
        $form->addButtonSearch(get_lang('Search'));
900
        if (0 != count($companys)) {
901
            $form
902
                ->addButton(
903
                    'export_csv',
904
                    get_lang('CSV export'),
905
                    'check',
906
                    'primary',
907
                    null,
908
                    null,
909
                    [
910
                    ]
911
                );
912
        }
913
914
        $tableContent = $form->returnForm();
915
        $tableContent .= $tableHtml;
916
        // $tableContent .= $table->return_table();
917
918
        $tpl = new Template('', false, false, false, false, false, false);
919
        $tpl->assign('table', $tableContent);
920
        $templateName = $tpl->get_template('my_space/course_summary.tpl');
921
        $tpl->display($templateName);
922
    }
923
924
    /**
925
     *  Displays a list as a table of teachers who are set authors by a extra_field authors.
926
     *
927
     * @param string|null $startDate
928
     * @param string|null $endDate
929
     * @param bool        $csv
930
     */
931
    public static function displayResumeLP(
932
        $startDate = null,
933
        $endDate = null,
934
        $csv = false
935
    ) {
936
        $tableHtml = '';
937
        $tblExtraField = Database::get_main_table(TABLE_EXTRA_FIELD);
938
        $tblExtraFieldValue = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
939
        $tblCourse = Database::get_main_table(TABLE_MAIN_COURSE);
940
        $query = "
941
        SELECT
942
            item_id AS lp_id,
943
            REPLACE (s.value, ';', ',') AS users_id
944
        FROM
945
            $tblExtraFieldValue s
946
        INNER JOIN $tblExtraField sf ON (s.field_id = sf.id)
947
        WHERE
948
            field_id IN (
949
                SELECT
950
                    id
951
                FROM
952
                    $tblExtraField
953
                WHERE
954
                    variable = 'authors'
955
            )
956
        AND sf.item_type = ".ExtraField::FIELD_TYPE_DATE."
957
        AND (s.value != '' OR s.value IS NOT NULL)
958
";
959
        $queryResult = Database::query($query);
960
        $data = [];
961
        while ($row = Database::fetch_assoc($queryResult)) {
962
            $lp_id = (int) $row['lp_id'];
963
            $registeredUsers = self::getCompanyLearnpathSubscription($startDate, $endDate, $lp_id);
964
            if (!empty($registeredUsers)) {
965
                $lpInfo = [];
966
                $teacherList = [];
967
                $teachersId = explode(',', trim($row['users_id'], ","));
968
                $lp_table = Database::get_course_table(TABLE_LP_MAIN);
969
                $query = "
970
            SELECT $lp_table.*,
971
                   $tblCourse.title as courseTitle,
972
                   $tblCourse.code as courseCode
973
            FROM
974
                $lp_table
975
            INNER JOIN $tblCourse ON $tblCourse.id = $lp_table.c_id
976
            WHERE
977
                $lp_table.iid = $lp_id
978
                ";
979
                $res = Database::query($query);
980
                if (Database::num_rows($res)) {
981
                    $lpInfo = Database::fetch_array($res);
982
                }
983
                $studentUsers = [];
984
                for ($i = 0; $i < count($registeredUsers); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

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

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

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
985
                    $studentUsers[] = api_get_user_info($registeredUsers[$i]);
986
                }
987
                $teacherList = [];
988
                for ($i = 0; $i < count($teachersId); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

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

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

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
989
                    $teacherId = $teachersId[$i];
990
                    $teacher = api_get_user_info($teacherId);
991
                    $data[$teacher['complete_name']][$lpInfo['name']] = [
992
                        'students' => count($studentUsers),
993
                        'studentList' => $studentUsers,
994
                        'lpInfo' => $lpInfo,
995
                    ];
996
                    $teacherList[] = $teacher;
997
                }
998
            }
999
        }
1000
        if (false == $csv) {
1001
            $table = "<div class='table-responsive'>".
1002
                "<table class='table table-hover table-striped table-bordered data_table'>".
1003
                "<thead>".
1004
                "<tr>".
1005
                "<th class=\"th-header\">".get_lang('Author')."</th>".
1006
                "<th class=\"th-header\">".get_lang('Learning path list')."</th>".
1007
                "<th class=\"th-header\">".get_lang('Subscribed users count')."</th>".
1008
                "<th class=\"th-header\">".get_lang('Learner list')."</th>".
1009
                "</tr>".
1010
                "</thead>".
1011
                "<tbody>";
1012
            $index = 0;
1013
            //icons for show and hode
1014
            $iconAdd = Display::getMdiIcon('plus', 'ch-tool-icon', null, 22, get_lang('Show/Hide'));
1015
            $iconRemove = Display::getMdiIcon('delete', 'ch-tool-icon', null, 22, get_lang('Show/Hide'));
1016
            $teacherNameTemp = '';
1017
            foreach ($data as $teacherName => $reportData) {
1018
                $lpCount = 0;
1019
                $totalStudent = 0;
1020
                foreach ($reportData as $lpName => $row) {
1021
                    $hiddenField = 'student_show_'.$index;
1022
                    $hiddenFieldLink = 'student_show_'.$index.'_';
1023
                    $printTeacherName = ($teacherName == $teacherNameTemp) ? '' : $teacherName;
1024
                    $lpInfo = $row['lpInfo'];
1025
                    $teacherNameTemp = $teacherName;
1026
                    $table .=
1027
                        "<tr>".
1028
                        "<td>$printTeacherName</td>".
1029
                        "<td>$lpName</td>".
1030
                        "<td>".$row['students']."</td>".
1031
                        "<td>".
1032
                        "<a href='#!' id='$hiddenFieldLink' onclick='showHideStudent(\"$hiddenField\")'>".
1033
                        "<div class='icon_add'>$iconAdd</div>".
1034
                        "<div class='icon_remove hidden'>$iconRemove</div>".
1035
                        "</a>".
1036
                        "<div id='$hiddenField' class='hidden'>";
1037
                    foreach ($row['studentList'] as $student) {
1038
                        $reportLink = Display::url(
1039
                            Display::getMdiIcon('chart-box', 'ch-tool-icon', null, 22, get_lang('Statistics')),
1040
                            api_get_path(WEB_CODE_PATH).'my_space/myStudents.php?details=true&student='.
1041
                            $student['id']
1042
                            .'&id_session='.$lpInfo['session_id']
1043
                            .'&course='.$lpInfo['courseCode']
1044
                        );
1045
                        $table .= "$reportLink ".$student['complete_name']."<br>";
1046
                        $totalStudent++;
1047
                    }
1048
                    $index++;
1049
                    $lpCount++;
1050
                    $table .= "</div>".
1051
                        "</td>".
1052
                        "</tr>";
1053
                }
1054
                $table .=
1055
                    "<tr>".
1056
                    "<td></td>".
1057
                    "<td><strong>".get_lang('Total learning paths')." $lpCount</strong></td>".
1058
                    "<td><strong>$totalStudent</strong></td>".
1059
                    "<td></td>".
1060
                    "</tr>";
1061
            }
1062
            $table .= "</tbody>".
1063
                "</table>".
1064
                "</div>";
1065
            if (!empty($startDate) or !empty($endDate)) {
1066
                $tableHtml = $table;
1067
            }
1068
1069
            $form = new FormValidator('searchDate', 'get');
1070
            $form->addHidden('display', 'learningPath');
1071
            $today = new DateTime();
1072
            if (empty($startDate)) {
1073
                $startDate = $today->modify('first day of this month')->format('Y-m-d');
1074
            }
1075
            if (empty($endDate)) {
1076
                $endDate = $today->modify('last day of this month')->format('Y-m-d');
1077
            }
1078
            $form->addDatePicker(
1079
                'startDate',
1080
                get_lang('Start date'),
1081
                [
1082
                    'value' => $startDate,
1083
                ]);
1084
            $form->addDatePicker(
1085
                'endDate',
1086
                get_lang('End date'),
1087
                [
1088
                    'value' => $endDate,
1089
                ]);
1090
            $form->addButtonSearch(get_lang('Search'));
1091
            if (0 != count($data)) {
1092
                $form
1093
                    ->addButton(
1094
                        'export_csv',
1095
                        get_lang('CSV export'),
1096
                        'check',
1097
                        'primary',
1098
                        null,
1099
                        null,
1100
                        [
1101
                        ]
1102
                    );
1103
            }
1104
            $tableContent = $form->returnForm();
1105
            $tableContent .= $tableHtml;
1106
            $tpl = new Template('', false, false, false, false, false, false);
1107
            $tpl->assign('table', $tableContent);
1108
            $templateName = $tpl->get_template('my_space/course_summary.tpl');
1109
            $tpl->display($templateName);
1110
        } else {
1111
            $csv_content = [];
1112
            $csv_row = [];
1113
            $csv_row[] = get_lang('Author');
1114
            $csv_row[] = get_lang('Learning path list');
1115
            $csv_row[] = get_lang('Subscribed users count');
1116
            $csv_row[] = get_lang('Learner list');
1117
            $csv_content[] = $csv_row;
1118
            foreach ($data as $teacherName => $reportData) {
1119
                foreach ($reportData as $lpName => $row) {
1120
                    $csv_row = [];
1121
                    $csv_row[] = $teacherName;
1122
                    $csv_row[] = $lpName;
1123
                    $csv_row[] = $row['students'];
1124
                    $studentsName = '';
1125
                    foreach ($row['studentList'] as $student) {
1126
                        $studentsName .= $student['complete_name']." / ";
1127
                    }
1128
                    $csv_row[] = trim($studentsName, " / ");
1129
                    $csv_content[] = $csv_row;
1130
                }
1131
            }
1132
            Export::arrayToCsv($csv_content, 'reporting_lp_by_authors');
1133
        }
1134
    }
1135
1136
    /**
1137
     *  Displays a list as a table of teachers who are set authors of lp's item by a extra_field authors.
1138
     *
1139
     * @param string|null $startDate
1140
     * @param string|null $endDate
1141
     * @param bool        $csv
1142
     */
1143
    public static function displayResumeLpByItem(
1144
        $startDate = null,
1145
        $endDate = null,
1146
        $csv = false
1147
    ) {
1148
        $tableHtml = '';
1149
        $table = '';
1150
        $tblExtraField = Database::get_main_table(TABLE_EXTRA_FIELD);
1151
        $tblExtraFieldValue = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1152
        $extraFieldLpByAutorName = 'authorlpitem';
1153
        $extraFieldLpPrice = 'price';
1154
1155
        $queryExtraFieldPrice = "SELECT id  ".
1156
            " FROM $tblExtraField ".
1157
            " WHERE variable = '$extraFieldLpPrice'";
1158
        $queryExtraFieldValue = "SELECT id ".
1159
            " FROM $tblExtraField ".
1160
            " WHERE variable = '$extraFieldLpByAutorName'";
1161
1162
        // search items of lp
1163
        $cLpItemsQuery = "select item_id as lp_item_id ".
1164
            " from $tblExtraFieldValue ".
1165
            " where field_id IN ( $queryExtraFieldValue ) ".
1166
            " group by lp_item_id";
1167
        $queryResult = Database::query($cLpItemsQuery);
1168
        $cLpItems = [];
1169
        while ($row = Database::fetch_assoc($queryResult)) {
1170
            $cLpItems[] = (int) $row['lp_item_id'];
1171
        }
1172
        if (0 == count($cLpItems)) {
1173
            $tableContent = "<div class='table-responsive'>".
1174
                "<table class='table table-hover table-striped table-bordered data_table'>".
1175
                "<thead>".
1176
                "<tr>".
1177
                "<th class=\"th-header\">".get_lang('No data available')."</th>".
1178
                "</tr>".
1179
                "</thead>".
1180
                "</tbody>".
1181
                "</tbody>".
1182
                "</table>".
1183
                "</div>";
1184
            $tableHtml = $tableContent;
1185
        } else {
1186
            $cLpItems = implode(',', $cLpItems);
1187
            // search by price
1188
            $cLpItemsPriceQuery = "select value as price, item_id as lp_item_id ".
1189
                " from $tblExtraFieldValue ".
1190
                " where field_id IN ( $queryExtraFieldPrice ) and item_id in ($cLpItems)";
1191
            $queryResult = Database::query($cLpItemsPriceQuery);
1192
            $lpItemPrice = [];
1193
            while ($row = Database::fetch_assoc($queryResult)) {
1194
                $lpItemPrice[$row['lp_item_id']] = $row['price'];
1195
            }
1196
            // search authors of lp
1197
            $autorsStr = '';
1198
            $autorsQuery = "select value as users_id ".
1199
                " from $tblExtraFieldValue ".
1200
                " where field_id IN ( $queryExtraFieldValue ) ".
1201
                " group by users_id ";
1202
            $queryResult = Database::query($autorsQuery);
1203
            while ($row = Database::fetch_assoc($queryResult)) {
1204
                $autorsStr .= " ".str_replace(';', ' ', $row['users_id']);
1205
                $autorsStr = trim($autorsStr);
1206
            }
1207
            $autorsStr = str_replace(' ', ',', $autorsStr);
1208
1209
            //search autors detailed
1210
            $authors = [];
1211
            if (!empty($autorsStr)) {
1212
                $autorsStr = explode(',', $autorsStr);
1213
                foreach ($autorsStr as $item) {
1214
                    $authors[$item] = api_get_user_info($item);
1215
                }
1216
            }
1217
            unset($autorsStr);
1218
1219
            //search info of lp's items
1220
            $cLpItemsData = [];
1221
            if (!empty($cLpItems)) {
1222
                $query = "select * ".
1223
                    " from c_lp_item ".
1224
                    " where iid in ($cLpItems)";
1225
                $queryResult = Database::query($query);
1226
                while ($row = Database::fetch_assoc($queryResult)) {
1227
                    $row['price'] = isset($lpItemPrice[$row['iid']]) ? $lpItemPrice[$row['iid']] : 0;
1228
                    $cLpItemsData[$row['iid']] = $row;
1229
                }
1230
            }
1231
1232
            $query = "select item_id as lp_item_id ,value as users_id ".
1233
                " from $tblExtraFieldValue ".
1234
                " where field_id IN ( $queryExtraFieldValue )";
1235
            $queryResult = Database::query($query);
1236
            $printData = [];
1237
            while ($row = Database::fetch_assoc($queryResult)) {
1238
                $cLpItem = (int) $row['lp_item_id'];
1239
                // get full lp data
1240
                $cLpItemData = isset($cLpItemsData[$cLpItem]) ? $cLpItemsData[$cLpItem] : [];
1241
                $authorData = $row['users_id'];
1242
                if (!empty($authorData)) {
1243
                    if (false === strpos($authorData, ";")) {
1244
                        $printData[(int) $authorData][$cLpItem] = $cLpItemData;
1245
                    } else {
1246
                        foreach (explode(';', $authorData) as $item) {
1247
                            $printData[$item][$cLpItem] = $cLpItemData;
1248
                        }
1249
                    }
1250
                }
1251
            }
1252
            $index = 0;
1253
        }
1254
        if (false == $csv) {
1255
            if (empty($tableHtml)) {
1256
                $table .= "<div class='table-responsive'>".
1257
                    "<table class='table table-hover table-striped table-bordered data_table'>".
1258
                    "<thead>".
1259
                    "<tr>".
1260
                    "<th class=\"th-header\">".get_lang('Author')."</th>".
1261
                    "<th class=\"th-header\">".get_lang('Content list')."</th>".
1262
                    "<th class=\"th-header\">".get_lang('Tariff')."</th>".
1263
                    "<th class=\"th-header\">".get_lang('Subscribed users count')."</th>".
1264
                    "<th class=\"th-header\">".get_lang('To invoice')."</th>".
1265
                    "<th class=\"th-header\">".get_lang('Learner list')."</th>".
1266
                    "</tr>".
1267
                    "</thead>".
1268
                    "<tbody>";
1269
                //Icon Constant
1270
                $iconAdd = Display::getMdiIcon('plus', 'ch-tool-icon', null, 22, get_lang('Show/Hide'));
1271
                $iconRemove = Display::getMdiIcon('delete', 'ch-tool-icon', null, 22, get_lang('Show/Hide'));
1272
1273
                $lastAuthor = '';
1274
                $total = 0;
1275
                foreach ($printData as $authorId => $lpItemData) {
1276
                    $autor = $authors[$authorId];
1277
                    $totalSudent = 0;
1278
                    foreach ($lpItemData as $lpItemId => $lpitem) {
1279
                        $title = $lpitem['title'];
1280
                        $price = $lpitem['price'];
1281
                        $hide = "class='author_$authorId hidden' ";
1282
                        if ($lastAuthor != $autor) {
1283
                            $table .= "<tr>";
1284
                            $table .= "<td>".$autor['complete_name'].
1285
                                "</td>";
1286
                        } else {
1287
                            $table .= "<tr $hide >";
1288
                            $table .= "<td></td>";
1289
                        }
1290
1291
                        $hiddenField = 'student_show_'.$index;
1292
                        $hiddenFieldLink = 'student_show_'.$index.'_';
1293
                        if ($lastAuthor != $autor) {
1294
                            $table .= "<td>$title".
1295
                                "</td>";
1296
                        } else {
1297
                            $table .= "<td>$title</td>";
1298
                        }
1299
                        $table .= "<td>$price</td>";
1300
                        $registeredUsers = self::getCompanyLearnpathSubscription($startDate, $endDate, $lpitem['lp_id'], true);
1301
                        $studenRegister = count($registeredUsers);
1302
                        $table .= "<td>$studenRegister</td>";
1303
                        $facturar = ($studenRegister * $price);
1304
                        $table .= "<td>$facturar</td>";
1305
                        $total += $facturar;
1306
                        $totalSudent += $studenRegister;
1307
                        if (0 != $studenRegister) {
1308
                            $table .= "<td>".
1309
                                "<a href='#!' id='$hiddenFieldLink' onclick='showHideStudent(\"$hiddenField\")'>".
1310
                                "<div class='icon_add'>$iconAdd</div>".
1311
                                "<div class='icon_remove hidden'>$iconRemove</div>".
1312
                                "</a>".
1313
                                "<div id='$hiddenField' class='hidden'>";
1314
                            for ($i = 0; $i < $studenRegister; $i++) {
1315
                                $tempStudent = api_get_user_info($registeredUsers[$i]['id']);
1316
                                $table .= $tempStudent['complete_name']." (".$registeredUsers[$i]['company'].")<br>";
1317
                            }
1318
                            $index++;
1319
                            $table .= "</div>".
1320
                                "</td>";
1321
                        } else {
1322
                            $table .= "<td></td>";
1323
                        }
1324
                        $table .= "</tr>";
1325
                        $lastAuthor = $autor;
1326
                    }
1327
                    //footer
1328
                    $table .= "<tr><th class=\"th-header\"></th>".
1329
                        "<th class=\"th-header\">".
1330
                        "<a href='#!' id='$hiddenFieldLink' onclick='ShowMoreAuthor(\"$authorId\")'>".
1331
                        "<div class='icon_add_author_$authorId'>$iconAdd</div>".
1332
                        "<div class='icon_remove_author_$authorId hidden'>$iconRemove</div>".
1333
                        "</a>"."</th>".
1334
                        "<th class=\"th-header\"></th>".
1335
                        "<th class=\"th-header\">$totalSudent</th>".
1336
                        "<th class=\"th-header\">$total</th>".
1337
                        "<th class=\"th-header\"></tr>";
1338
                    $total = 0;
1339
                }
1340
                $table .= "</tbody>".
1341
                    "</table>".
1342
                    "</div>";
1343
                $tableHtml = $table;
1344
            }
1345
1346
            $form = new FormValidator('searchDate', 'get');
1347
            $form->addHidden('display', 'learningPathByItem');
1348
            $today = new DateTime();
1349
            if (empty($startDate)) {
1350
                $startDate = $today->modify('first day of this month')->format('Y-m-d');
1351
            }
1352
            if (empty($endDate)) {
1353
                $endDate = $today->modify('last day of this month')->format('Y-m-d');
1354
            }
1355
            $form->addDatePicker(
1356
                'startDate',
1357
                get_lang('Start date'),
1358
                [
1359
                    'value' => $startDate,
1360
                ]);
1361
            $form->addDatePicker(
1362
                'endDate',
1363
                get_lang('End date'),
1364
                [
1365
                    'value' => $endDate,
1366
                ]);
1367
            $form->addButtonSearch(get_lang('Search'));
1368
1369
            if (0 != count($printData)) {
1370
                $form
1371
                    ->addButton(
1372
                        'export_csv',
1373
                        get_lang('CSV export'),
1374
                        'check',
1375
                        'primary',
1376
                        null,
1377
                        null,
1378
                        [
1379
                        ]
1380
                    );
1381
            }
1382
            $tableContent = $form->returnForm();
1383
            $tableContent .= $tableHtml;
1384
            $tpl = new Template('', false, false, false, false, false, false);
1385
            $tpl->assign('table', $tableContent);
1386
            $templateName = $tpl->get_template('my_space/course_summary.tpl');
1387
            $tpl->display($templateName);
1388
        } else {
1389
            $csv_content = [];
1390
            $csv_row = [];
1391
1392
            $csv_row[] = get_lang('Author');
1393
            $csv_row[] = get_lang('Content list');
1394
            $csv_row[] = get_lang('Tariff');
1395
            $csv_row[] = get_lang('Subscribed users count');
1396
            $csv_row[] = get_lang('To invoice');
1397
            $csv_row[] = get_lang('Learner list');
1398
            $csv_content[] = $csv_row;
1399
            foreach ($printData as $authorId => $lpItemData) {
1400
                $autor = $authors[$authorId];
1401
                foreach ($lpItemData as $lpItemId => $lpitem) {
1402
                    $title = $lpitem['title'];
1403
                    $price = $lpitem['price'];
1404
1405
                    $csv_row = [];
1406
                    $csv_row[] = $autor['complete_name'];
1407
                    $csv_row[] = $title;
1408
                    $csv_row[] = $price;
1409
                    $registeredUsers = self::getCompanyLearnpathSubscription($startDate, $endDate, $lpitem['lp_id'], true);
1410
                    $studenRegister = count($registeredUsers);
1411
                    $csv_row[] = $studenRegister;
1412
                    $facturar = ($studenRegister * $price);
1413
                    $csv_row[] = $facturar;
1414
                    $totalStudent += $studenRegister;
1415
                    if (0 != $studenRegister) {
1416
                        $studentsName = '';
1417
                        for ($i = 0; $i < $studenRegister; $i++) {
1418
                            $tempStudent = api_get_user_info($registeredUsers[$i]['id']);
1419
                            $studentsName .= $tempStudent['complete_name']." (".$registeredUsers[$i]['company'].") / ";
1420
1421
                            $totalStudent++;
1422
                        }
1423
                        $csv_row[] = trim($studentsName, " / ");
1424
                        $csv_content[] = $csv_row;
1425
                        $index++;
1426
                        $lpCount++;
1427
                    }
1428
                }
1429
            }
1430
            Export::arrayToCsv($csv_content, 'reporting_lp_by_authors');
1431
        }
1432
    }
1433
1434
    /**
1435
     * Display a sortable table that contains an overview of all the reporting progress of all courses.
1436
     */
1437
    public static function display_tracking_course_overview()
1438
    {
1439
        $params = ['view' => 'admin', 'display' => 'course'];
1440
1441
        $table = new SortableTable(
1442
            'tracking_course_overview',
1443
            ['MySpace', 'get_total_number_courses'],
1444
            ['MySpace', 'get_course_data_tracking_overview'],
1445
            1,
1446
            20,
1447
            'ASC',
1448
            null,
1449
            [
1450
                'class' => 'table table-transparent',
1451
            ]
1452
        );
1453
1454
        $table->additional_parameters = $params;
1455
        $table->set_column_filter(0, ['MySpace', 'course_tracking_filter']);
1456
        echo '<div class="summary-legend">';
1457
        echo $table->return_table();
1458
        echo '</div>';
1459
    }
1460
1461
    /**
1462
     * Get the total number of courses.
1463
     *
1464
     * @return int Total number of courses
1465
     */
1466
    public static function get_total_number_courses()
1467
    {
1468
        return CourseManager::count_courses(api_get_current_access_url_id());
1469
    }
1470
1471
    /**
1472
     * Get data for the courses.
1473
     *
1474
     * @param int    $from        Inferior limit
1475
     * @param int    $numberItems Number of items to select
1476
     * @param string $column      Column to order on
1477
     * @param string $direction   Order direction
1478
     *
1479
     * @return array Results
1480
     */
1481
    public static function get_course_data_tracking_overview(
1482
        $from,
1483
        $numberItems,
1484
        $column,
1485
        $direction
1486
    ) {
1487
        switch ($column) {
1488
            default:
1489
            case 1:
1490
                $column = 'title';
1491
                break;
1492
        }
1493
        $courses = CourseManager::get_courses_list(
1494
            $from,
1495
            $numberItems,
1496
            $column,
1497
            $direction,
1498
             -1,
1499
            '',
1500
            api_get_current_access_url_id()
1501
        );
1502
1503
        $list = [];
1504
        foreach ($courses as $course) {
1505
            $list[] = [
1506
                '0' => $course['real_id'],
1507
                'col0' => $course['real_id'],
1508
            ];
1509
        }
1510
1511
        return $list;
1512
    }
1513
1514
    /**
1515
     * Fills in course reporting data.
1516
     *
1517
     * @param int course code
1518
     * @param array $url_params additional url parameters
1519
     * @param array $row        the row information (the other columns)
1520
     *
1521
     * @return string html code
1522
     */
1523
    public static function course_tracking_filter($courseCode, $urlParams, $row)
1524
    {
1525
        $course = api_get_course_entity($courseCode);
1526
1527
        if (null === $course) {
1528
            return '';
1529
        }
1530
1531
        $courseId = (int) $course->getId();
1532
1533
        $tpl = new Template('', false, false, false, false, false, false);
1534
1535
        $timeSpent              = 0;
1536
        $progressSum            = 0;
1537
        $progressCount          = 0;
1538
        $scoreSum               = 0;
1539
        $scoreCount             = 0;
1540
        $messagesCount          = 0;
1541
        $assignmentsCount       = 0;
1542
        $lastLoginRaw           = null;
1543
        $totalScoreObtained     = 0;
1544
        $totalScorePossible     = 0;
1545
        $totalQuestionsAnswered = 0;
1546
1547
        $courseRelUsers = $course->getUsers();
1548
1549
        foreach ($courseRelUsers as $courseRelUser) {
1550
            $user   = $courseRelUser->getUser();
1551
            $userId = (int) $user->getId();
1552
1553
            $timeSpent += Tracking::get_time_spent_on_the_course(
1554
                $userId,
1555
                $courseId
1556
            );
1557
1558
            $progressTmp = Tracking::get_avg_student_progress(
1559
                $userId,
1560
                $course,
1561
                [],
1562
                null,
1563
                true
1564
            );
1565
1566
            if (!empty($progressTmp)) {
1567
                $progressSum   += $progressTmp[0];
1568
                $progressCount += $progressTmp[1];
1569
            }
1570
1571
            $scoreTmp = Tracking::get_avg_student_score(
1572
                $userId,
1573
                $course,
1574
                [],
1575
                null,
1576
                true
1577
            );
1578
1579
            if (is_array($scoreTmp) && !empty($scoreTmp)) {
1580
                $scoreSum   += $scoreTmp[0];
1581
                $scoreCount += $scoreTmp[1];
1582
            }
1583
1584
            $lastLoginTmp = Tracking::get_last_connection_date_on_the_course(
1585
                $userId,
1586
                ['real_id' => $courseId],
1587
                null,
1588
                false
1589
            );
1590
1591
            if (!empty($lastLoginTmp)) {
1592
                if (null === $lastLoginRaw ||
1593
                    strtotime((string) $lastLoginTmp) > strtotime((string) $lastLoginRaw)
1594
                ) {
1595
                    $lastLoginRaw = $lastLoginTmp;
1596
                }
1597
            }
1598
1599
            $exerciseResults = self::exercises_results($userId, $courseCode);
1600
1601
            $totalScoreObtained     += $exerciseResults['score_obtained'] ?? 0;
1602
            $totalScorePossible     += $exerciseResults['score_possible'] ?? 0;
1603
            $totalQuestionsAnswered += $exerciseResults['questions_answered'] ?? 0;
1604
        }
1605
1606
        $avgProgress = $progressCount > 0
1607
            ? round($progressSum / $progressCount, 2)
1608
            : 0;
1609
1610
        $avgScore = $scoreCount > 0
1611
            ? round($scoreSum / $scoreCount, 2)
1612
            : '-';
1613
1614
        if (!empty($lastLoginRaw)) {
1615
            $lastLogin = api_convert_and_format_date(
1616
                $lastLoginRaw,
1617
                DATE_FORMAT_SHORT,
1618
                date_default_timezone_get()
1619
            );
1620
        } else {
1621
            $lastLogin = '-';
1622
        }
1623
1624
        if ($totalScorePossible > 0) {
1625
            $totalScorePercentage = round(
1626
                ($totalScoreObtained / $totalScorePossible) * 100,
1627
                2
1628
            );
1629
1630
            $totalScore = sprintf(
1631
                '%d/%d (%s %%)',
1632
                $totalScoreObtained,
1633
                $totalScorePossible,
1634
                $totalScorePercentage
1635
            );
1636
        } else {
1637
            $totalScore = '-';
1638
        }
1639
1640
        $data = [
1641
            'time_spent'         => api_time_to_hms($timeSpent),
1642
            'avg_progress'       => $avgProgress,
1643
            'avg_score'          => $avgScore,
1644
            'number_message'     => $messagesCount,
1645
            'number_assignments' => $assignmentsCount,
1646
            'total_score'        => $totalScore,
1647
            'questions_answered' => $totalQuestionsAnswered,
1648
            'last_login'         => $lastLogin,
1649
        ];
1650
1651
        $tpl->assign('data', $data);
1652
        $tpl->assign('course', $course);
1653
1654
        $layout = $tpl->get_template('my_space/partials/tracking_course_overview.html.twig');
1655
1656
        return $tpl->fetch($layout);
1657
    }
1658
1659
1660
    /**
1661
     * This function exports the table that we see in display_tracking_course_overview().
1662
     */
1663
    public static function export_tracking_course_overview()
1664
    {
1665
        // database table definition
1666
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1667
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1668
1669
        // the values of the sortable table
1670
        if ($_GET['tracking_course_overview_page_nr']) {
1671
            $from = $_GET['tracking_course_overview_page_nr'];
1672
        } else {
1673
            $from = 0;
1674
        }
1675
        if ($_GET['tracking_course_overview_column']) {
1676
            $orderby = $_GET['tracking_course_overview_column'];
1677
        } else {
1678
            $orderby = 0;
1679
        }
1680
1681
        if ($_GET['tracking_course_overview_direction']) {
1682
            $direction = $_GET['tracking_course_overview_direction'];
1683
        } else {
1684
            $direction = 'ASC';
1685
        }
1686
1687
        $course_data = self::get_course_data_tracking_overview(
1688
            $from,
1689
            1000,
1690
            $orderby,
1691
            $direction
1692
        );
1693
1694
        $csv_content = [];
1695
1696
        // the first line of the csv file with the column headers
1697
        $csv_row = [];
1698
        $csv_row[] = get_lang('Course');
1699
        $csv_row[] = get_lang('Time');
1700
        $csv_row[] = get_lang('Progress');
1701
        $csv_row[] = get_lang('Average score in learning paths');
1702
        $csv_row[] = get_lang('Total number of messages');
1703
        $csv_row[] = get_lang('Total number of assignments');
1704
        $csv_row[] = get_lang('Total score obtained for tests');
1705
        $csv_row[] = get_lang('Total possible score for tests');
1706
        $csv_row[] = get_lang('Number of tests answered');
1707
        $csv_row[] = get_lang('Total score percentage for tests');
1708
        $csv_row[] = get_lang('Latest login');
1709
        $csv_content[] = $csv_row;
1710
1711
        // the other lines (the data)
1712
        foreach ($course_data as $key => $course) {
1713
            $courseId = $course[0];
1714
            $course = api_get_course_entity($courseId);
1715
            $courseCode = $course->getCode();
1716
            $course_title = $course->getTitle();
1717
1718
            $csv_row = [];
1719
            $csv_row[] = $course_title;
1720
1721
            $time_spent = 0;
1722
            $progress = 0;
1723
            $nb_progress_lp = 0;
1724
            $score = 0;
1725
            $nb_score_lp = 0;
1726
            $nb_messages = 0;
1727
            $nb_assignments = 0;
1728
            $last_login_date = false;
1729
            $total_score_obtained = 0;
1730
            $total_score_possible = 0;
1731
            $total_questions_answered = 0;
1732
1733
            $courseRelUsers = $course->getUsers();
1734
            foreach ($courseRelUsers as $courseRelUser) {
1735
                $user = $courseRelUser->getUser();
1736
                $userId = $user->getId();
1737
1738
                // get time spent in the course and session
1739
                $time_spent += Tracking::get_time_spent_on_the_course(
1740
                    $userId,
1741
                    $courseId
1742
                );
1743
                $progress_tmp = Tracking::get_avg_student_progress(
1744
                    $userId,
1745
                    $course,
1746
                    [],
1747
                    null,
1748
                    true
1749
                );
1750
                $progress += $progress_tmp[0];
1751
                $nb_progress_lp += $progress_tmp[1];
1752
                $score_tmp = Tracking::get_avg_student_score(
1753
                    $userId,
1754
                    $course,
1755
                    [],
1756
                    null,
1757
                    true
1758
                );
1759
                if (is_array($score_tmp)) {
1760
                    $score += $score_tmp[0];
1761
                    $nb_score_lp += $score_tmp[1];
1762
                }
1763
                $nb_messages += Container::getForumPostRepository()->countUserForumPosts($user, $course);
1764
                $nb_assignments += Container::getStudentPublicationRepository()->countUserPublications($user, $course);
1765
1766
                $last_login_date_tmp = Tracking::get_last_connection_date_on_the_course(
1767
                    $userId,
1768
                    ['real_id' => $courseId],
1769
                    null,
1770
                    false
1771
                );
1772
1773
                if (false != $last_login_date_tmp && false == $last_login_date) {
1774
                    $last_login_date = $last_login_date_tmp;
1775
                    // TODO: Repeated previous condition. To be cleaned.
1776
                    // Find the max and assign it to first_login_date
1777
                    if (strtotime($last_login_date_tmp) > strtotime($last_login_date)) {
1778
                        $last_login_date = $last_login_date_tmp;
1779
                    }
1780
                }
1781
1782
                $exercise_results_tmp = self::exercises_results($userId, $courseCode);
1783
                $total_score_obtained += $exercise_results_tmp['score_obtained'];
1784
                $total_score_possible += $exercise_results_tmp['score_possible'];
1785
                $total_questions_answered += $exercise_results_tmp['questions_answered'];
1786
            }
1787
            if ($nb_progress_lp > 0) {
1788
                $avg_progress = round($progress / $nb_progress_lp, 2);
1789
            } else {
1790
                $avg_progress = 0;
1791
            }
1792
            if ($nb_score_lp > 0) {
1793
                $avg_score = round($score / $nb_score_lp, 2);
1794
            } else {
1795
                $avg_score = '-';
1796
            }
1797
            if ($last_login_date) {
1798
                $last_login_date = api_convert_and_format_date(
1799
                    $last_login_date,
1800
                    DATE_FORMAT_SHORT,
1801
                    date_default_timezone_get()
1802
                );
1803
            } else {
1804
                $last_login_date = '-';
1805
            }
1806
            if ($total_score_possible > 0) {
1807
                $total_score_percentage = round($total_score_obtained / $total_score_possible * 100, 2);
1808
            } else {
1809
                $total_score_percentage = 0;
1810
            }
1811
            // time spent in the course
1812
            $csv_row[] = api_time_to_hms($time_spent);
1813
            // student progress in course
1814
            $csv_row[] = $avg_progress;
1815
            // student score
1816
            $csv_row[] = $avg_score;
1817
            // student messages
1818
            $csv_row[] = $nb_messages;
1819
            // student assignments
1820
            $csv_row[] = $nb_assignments;
1821
            // student exercises results (obtained score, maximum score, number of exercises answered, score percentage)
1822
            $csv_row[] = $total_score_obtained;
1823
            $csv_row[] = $total_score_possible;
1824
            $csv_row[] = $total_questions_answered;
1825
            $csv_row[] = $total_score_percentage;
1826
            // last connection
1827
            $csv_row[] = $last_login_date;
1828
            $csv_content[] = $csv_row;
1829
        }
1830
        Export::arrayToCsv($csv_content, 'reporting_course_overview');
1831
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
1832
    }
1833
1834
    /**
1835
     * Display a sortable table that contains an overview of all the reporting
1836
     * progress of all sessions and all courses the user is subscribed to.
1837
     *
1838
     * @author Guillaume Viguier <[email protected]>
1839
     */
1840
    public static function display_tracking_session_overview()
1841
    {
1842
        // Build header for the "metrics" column (course + stats).
1843
        // We keep the inner table because session_tracking_filter expects it,
1844
        // but we use a specific class to style it cleanly with CSS.
1845
        $head  = '<table class="session-metrics-header" '
1846
            .'style="width:100%;border:0;padding:0;border-collapse:collapse;">';
1847
        $head .= '<tr>';
1848
        // Course (left aligned).
1849
        $head .= '<th style="border-left:0;border-bottom:0;">'
1850
            .'<span>'.get_lang('Course').'</span></th>';
1851
        // Time spent.
1852
        $head .= '<th style="padding:0;border-bottom:0;">'
1853
            .'<span>'.get_lang('Time').'</span></th>';
1854
        // Progress.
1855
        $head .= '<th style="padding:0;border-bottom:0;">'
1856
            .'<span>'.get_lang('Progress').'</span></th>';
1857
        // Average score in learning paths.
1858
        $head .= '<th style="padding:0;border-bottom:0;">'
1859
            .'<span>'.get_lang('Average score in learning paths').'</span></th>';
1860
        // Total number of messages.
1861
        $head .= '<th style="padding:0;border-bottom:0;">'
1862
            .'<span>'.get_lang('Total number of messages').'</span></th>';
1863
        // Total number of assignments.
1864
        $head .= '<th style="padding:0;border-bottom:0;">'
1865
            .'<span>'.get_lang('Total number of assignments').'</span></th>';
1866
        // Total score obtained for tests.
1867
        $head .= '<th style="padding:0;border-bottom:0;">'
1868
            .'<span>'.get_lang('Total score obtained for tests').'</span></th>';
1869
        // Number of tests answered.
1870
        $head .= '<th style="padding:0;border-bottom:0;">'
1871
            .'<span>'.get_lang('Number of tests answered').'</span></th>';
1872
        // Latest login.
1873
        $head .= '<th style="padding:0;border-bottom:0;border-right:0;">'
1874
            .'<span>'.get_lang('Latest login').'</span></th>';
1875
        $head .= '</tr>';
1876
        $head .= '</table>';
1877
1878
        // Keep display=session so paging keeps the same view.
1879
        $params = [
1880
            'view'    => 'admin',
1881
            'display' => 'session',
1882
        ];
1883
1884
        $table = new SortableTable(
1885
            'tracking_session_overview',
1886
            ['MySpace', 'get_total_number_sessions'],
1887
            ['MySpace', 'get_session_data_tracking_overview'],
1888
            1
1889
        );
1890
        $table->additional_parameters = $params;
1891
1892
        // Hidden internal id column.
1893
        $table->set_header(
1894
            0,
1895
            '',
1896
            false,
1897
            ['style' => 'display:none'],
1898
            ['style' => 'display:none']
1899
        );
1900
1901
        // Session name column.
1902
        $table->set_header(
1903
            1,
1904
            get_lang('Session'),
1905
            true,
1906
            ['style' => 'font-size:0.875rem;font-weight:600;'],
1907
            ['style' => 'font-size:0.875rem;']
1908
        );
1909
1910
        // Metrics block column (course + stats table).
1911
        $table->set_header(
1912
            2,
1913
            $head,
1914
            false,
1915
            ['style' => 'width:90%;border:0;padding:0;'],
1916
            ['style' => 'width:90%;padding:0;']
1917
        );
1918
1919
        // Use existing filter to render metrics table per session.
1920
        $table->set_column_filter(2, ['MySpace', 'session_tracking_filter']);
1921
1922
        $table->display();
1923
    }
1924
1925
1926
    /**
1927
     * Get the total number of sessions.
1928
     *
1929
     * @return int Total number of sessions
1930
     */
1931
    public static function get_total_number_sessions()
1932
    {
1933
        return SessionManager::count_sessions(api_get_current_access_url_id());
1934
    }
1935
1936
    /**
1937
     * Get data for the sessions.
1938
     *
1939
     * @param int    $from        Inferior limit
1940
     * @param int    $numberItems Number of items to select
1941
     * @param string $column      Column to order on
1942
     * @param string $direction   Order direction
1943
     *
1944
     * @return array Results
1945
     */
1946
    public static function get_session_data_tracking_overview(
1947
        $from,
1948
        $numberItems,
1949
        $column,
1950
        $direction
1951
    ) {
1952
        $from = (int) $from;
1953
        $numberItems = (int) $numberItems;
1954
        $direction = Database::escape_string($direction);
1955
        $columnName = 'name';
1956
        if (1 === $column) {
1957
            $columnName = 'id';
1958
        }
1959
1960
        $options = [
1961
            'order' => " $columnName $direction",
1962
            'limit' => " $from,$numberItems",
1963
        ];
1964
        $sessions = SessionManager::formatSessionsAdminForGrid($options);
1965
        $list = [];
1966
        foreach ($sessions as $session) {
1967
            $list[] = [
1968
                '0' => $session['id'],
1969
                'col0' => $session['id'],
1970
                '1' => strip_tags($session['title']),
1971
                'col1' => strip_tags($session['title']),
1972
            ];
1973
        }
1974
1975
        return $list;
1976
    }
1977
1978
    /**
1979
     * Fills in session reporting data.
1980
     *
1981
     * @param int   $session_id the id of the user
1982
     * @param array $url_params additonal url parameters
1983
     * @param array $row        the row information (the other columns)
1984
     *
1985
     * @return string html code
1986
     */
1987
    public static function session_tracking_filter($session_id, $url_params, $row)
1988
    {
1989
        $sessionId = $row[0];
1990
        $session = api_get_session_entity($sessionId);
1991
        // the table header
1992
        $return = '<table
1993
            class="data_table"
1994
            style="width: 100%;border:0;padding:0;border-collapse:collapse;table-layout: fixed">';
1995
1996
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1997
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1998
        $sessionRelCourses = $session->getCourses();
1999
        foreach ($sessionRelCourses as $sessionRelCourse) {
2000
            $course = $sessionRelCourse->getCourse();
2001
            $courseId = $course->getId();
2002
            $courseCode = $course->getCode();
2003
            $return .= '<tr>';
2004
            $return .= '<td>'.$course->getTitle().'</td>';
2005
            //$users = Container::getSessionRepository()->getUsersByCourse($session, $course, $url);
2006
2007
            // get the users in the course
2008
            $sql = "SELECT u.id as user_id
2009
                    FROM $tbl_user AS u
2010
                    INNER JOIN $tbl_session_rel_course_rel_user AS scu
2011
                    ON u.id = scu.user_id
2012
                    WHERE u.active <> ".USER_SOFT_DELETED." AND scu.session_id = '".$session_id."' AND scu.c_id = '".$courseId."'";
2013
            $result_users = Database::query($sql);
2014
            $time_spent = 0;
2015
            $progress = 0;
2016
            $nb_progress_lp = 0;
2017
            $score = 0;
2018
            $nb_score_lp = 0;
2019
            $nb_messages = 0;
2020
            $nb_assignments = 0;
2021
            $last_login_date = false;
2022
            $total_score_obtained = 0;
2023
            $total_score_possible = 0;
2024
            $total_questions_answered = 0;
2025
            while ($row_user = Database::fetch_object($result_users)) {
2026
                $user = api_get_user_entity($row_user->user_id);
2027
                // get time spent in the course and session
2028
                $time_spent += Tracking::get_time_spent_on_the_course($row_user->user_id, $courseId, $session_id);
2029
                $progress_tmp = Tracking::get_avg_student_progress(
2030
                    $row_user->user_id,
2031
                    $course,
2032
                    [],
2033
                    $session_id,
2034
                    true
2035
                );
2036
                $progress += $progress_tmp[0];
2037
                $nb_progress_lp += $progress_tmp[1];
2038
                $score_tmp = Tracking::get_avg_student_score($row_user->user_id, $course, [], $session_id, true);
2039
                if (is_array($score_tmp)) {
2040
                    $score += $score_tmp[0];
2041
                    $nb_score_lp += $score_tmp[1];
2042
                }
2043
                $nb_messages += Container::getForumPostRepository()->countUserForumPosts($user, $course, $session);
2044
                $nb_assignments += Container::getStudentPublicationRepository()->countUserPublications(
2045
                    $user,
2046
                    $course,
2047
                    $session
2048
                );
2049
                $last_login_date_tmp = Tracking::get_last_connection_date_on_the_course(
2050
                    $row_user->user_id,
2051
                    ['real_id' => $courseId],
2052
                    $session_id,
2053
                    false
2054
                );
2055
                if (false != $last_login_date_tmp && false == $last_login_date) {
2056
                    // TODO: To be cleaned.
2057
                    $last_login_date = $last_login_date_tmp;
2058
                } elseif (false != $last_login_date_tmp && false != $last_login_date) {
2059
                    // TODO: Repeated previous condition! To be cleaned.
2060
                    // Find the max and assign it to first_login_date
2061
                    if (strtotime($last_login_date_tmp) > strtotime($last_login_date)) {
2062
                        $last_login_date = $last_login_date_tmp;
2063
                    }
2064
                }
2065
2066
                $exercise_results_tmp = self::exercises_results($row_user->user_id, $courseCode, $session_id);
2067
                $total_score_obtained += $exercise_results_tmp['score_obtained'];
2068
                $total_score_possible += $exercise_results_tmp['score_possible'];
2069
                $total_questions_answered += $exercise_results_tmp['questions_answered'];
2070
            }
2071
            if ($nb_progress_lp > 0) {
2072
                $avg_progress = round($progress / $nb_progress_lp, 2);
2073
            } else {
2074
                $avg_progress = 0;
2075
            }
2076
            if ($nb_score_lp > 0) {
2077
                $avg_score = round($score / $nb_score_lp, 2);
2078
            } else {
2079
                $avg_score = '-';
2080
            }
2081
            if ($last_login_date) {
2082
                $last_login_date = api_convert_and_format_date(
2083
                    $last_login_date,
2084
                    DATE_FORMAT_SHORT,
2085
                    date_default_timezone_get()
2086
                );
2087
            } else {
2088
                $last_login_date = '-';
2089
            }
2090
            if ($total_score_possible > 0) {
2091
                $total_score_percentage = round($total_score_obtained / $total_score_possible * 100, 2);
2092
            } else {
2093
                $total_score_percentage = 0;
2094
            }
2095
            if ($total_score_percentage > 0) {
2096
                $total_score = $total_score_obtained.'/'.$total_score_possible.' ('.$total_score_percentage.' %)';
2097
            } else {
2098
                $total_score = '-';
2099
            }
2100
            // time spent in the course
2101
            $return .= '    <td><div>'.api_time_to_hms($time_spent).'</div></td>';
2102
            // student progress in course
2103
            $return .= '    <td><div>'.$avg_progress.'</div></td>';
2104
            // student score
2105
            $return .= '    <td><div>'.$avg_score.'</div></td>';
2106
            // student messages
2107
            $return .= '    <td><div>'.$nb_messages.'</div></td>';
2108
            // student assignments
2109
            $return .= '    <td><div>'.$nb_assignments.'</div></td>';
2110
            // student exercises results (obtained score, maximum score, number of exercises answered, score percentage)
2111
            $return .= '<td width="105px;">'.$total_score.'</td>';
2112
            $return .= '<td>'.$total_questions_answered.'</td>';
2113
            // last connection
2114
            $return .= '    <td><div>'.$last_login_date.'</div></td>';
2115
            $return .= '<tr>';
2116
        }
2117
        $return .= '</table>';
2118
2119
        return $return;
2120
    }
2121
2122
    /**
2123
     * This function exports the table that we see in display_tracking_session_overview().
2124
     */
2125
    public static function export_tracking_session_overview()
2126
    {
2127
        // database table definition
2128
        $tbl_session_rel_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
2129
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2130
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2131
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
2132
2133
        // the values of the sortable table
2134
        $from = 0;
2135
        if ($_GET['tracking_session_overview_page_nr']) {
2136
            $from = $_GET['tracking_session_overview_page_nr'];
2137
        }
2138
2139
        $orderby = 0;
2140
        if ($_GET['tracking_session_overview_column']) {
2141
            $orderby = $_GET['tracking_session_overview_column'];
2142
        }
2143
2144
        $direction = 'ASC';
2145
        if ($_GET['tracking_session_overview_direction']) {
2146
            $direction = $_GET['tracking_session_overview_direction'];
2147
        }
2148
2149
        $session_data = self::get_session_data_tracking_overview($from, 1000, $orderby, $direction);
2150
2151
        $csv_content = [];
2152
2153
        // the first line of the csv file with the column headers
2154
        $csv_row = [];
2155
        $csv_row[] = get_lang('Session');
2156
        $csv_row[] = get_lang('Course');
2157
        $csv_row[] = get_lang('Time');
2158
        $csv_row[] = get_lang('Progress');
2159
        $csv_row[] = get_lang('Average score in learning paths');
2160
        $csv_row[] = get_lang('Total number of messages');
2161
        $csv_row[] = get_lang('Total number of assignments');
2162
        $csv_row[] = get_lang('Total score obtained for tests');
2163
        $csv_row[] = get_lang('Total possible score for tests');
2164
        $csv_row[] = get_lang('Number of tests answered');
2165
        $csv_row[] = get_lang('Total score percentage for tests');
2166
        $csv_row[] = get_lang('Latest login');
2167
        $csv_content[] = $csv_row;
2168
2169
        // the other lines (the data)
2170
        foreach ($session_data as $session) {
2171
            $session_id = $session[0];
2172
            $session_title = $session[1];
2173
2174
            // getting all the courses of the session
2175
            $sql = "SELECT * FROM $tbl_course AS c
2176
                    INNER JOIN $tbl_session_rel_course AS sc
2177
                    ON sc.c_id = c.id
2178
                    WHERE sc.session_id = '".$session_id."';";
2179
            $result = Database::query($sql);
2180
            while ($row = Database::fetch_object($result)) {
2181
                $courseId = $row->c_id;
2182
                $courseInfo = ['real_id' => $courseId];
2183
                $course = api_get_course_entity($courseId);
2184
                $csv_row = [];
2185
                $csv_row[] = $session_title;
2186
                $csv_row[] = $row->title;
2187
                // get the users in the course
2188
                $sql = "SELECT scu.user_id
2189
                        FROM $tbl_user AS u
2190
                        INNER JOIN $tbl_session_rel_course_rel_user AS scu
2191
                        ON u.id = scu.user_id
2192
                        WHERE u.active <> ".USER_SOFT_DELETED." AND scu.session_id = '".$session_id."' AND scu.c_id = '".$courseId."'";
2193
                $result_users = Database::query($sql);
2194
                $time_spent = 0;
2195
                $progress = 0;
2196
                $nb_progress_lp = 0;
2197
                $score = 0;
2198
                $nb_score_lp = 0;
2199
                $nb_messages = 0;
2200
                $nb_assignments = 0;
2201
                $last_login_date = false;
2202
                $total_score_obtained = 0;
2203
                $total_score_possible = 0;
2204
                $total_questions_answered = 0;
2205
                while ($row_user = Database::fetch_object($result_users)) {
2206
                    // get time spent in the course and session
2207
                    $time_spent += Tracking::get_time_spent_on_the_course($row_user->user_id, $courseId, $session_id);
2208
                    $progress_tmp = Tracking::get_avg_student_progress(
2209
                        $row_user->user_id,
2210
                        $row->code,
2211
                        [],
2212
                        $session_id,
2213
                        true
2214
                    );
2215
                    $progress += $progress_tmp[0];
2216
                    $nb_progress_lp += $progress_tmp[1];
2217
                    $score_tmp = Tracking::get_avg_student_score(
2218
                        $row_user->user_id,
2219
                        $course,
2220
                        [],
2221
                        $session_id,
2222
                        true
2223
                    );
2224
                    if (is_array($score_tmp)) {
2225
                        $score += $score_tmp[0];
2226
                        $nb_score_lp += $score_tmp[1];
2227
                    }
2228
                    $nb_messages += Tracking::count_student_messages(
2229
                        $row_user->user_id,
2230
                        $row->code,
2231
                        $session_id
2232
                    );
2233
2234
                    $nb_assignments += Tracking::count_student_assignments(
2235
                        $row_user->user_id,
2236
                        $row->code,
2237
                        $session_id
2238
                    );
2239
2240
                    $last_login_date_tmp = Tracking:: get_last_connection_date_on_the_course(
2241
                        $row_user->user_id,
2242
                        $courseInfo,
2243
                        $session_id,
2244
                        false
2245
                    );
2246
                    if (false != $last_login_date_tmp && false == $last_login_date) {
2247
                        // TODO: To be cleaned.
2248
                        $last_login_date = $last_login_date_tmp;
2249
                    } elseif (false != $last_login_date_tmp && false == $last_login_date) {
2250
                        // TODO: Repeated previous condition. To be cleaned.
2251
                        // Find the max and assign it to first_login_date
2252
                        if (strtotime($last_login_date_tmp) > strtotime($last_login_date)) {
2253
                            $last_login_date = $last_login_date_tmp;
2254
                        }
2255
                    }
2256
2257
                    $exercise_results_tmp = self::exercises_results($row_user->user_id, $row->code, $session_id);
2258
                    $total_score_obtained += $exercise_results_tmp['score_obtained'];
2259
                    $total_score_possible += $exercise_results_tmp['score_possible'];
2260
                    $total_questions_answered += $exercise_results_tmp['questions_answered'];
2261
                }
2262
                if ($nb_progress_lp > 0) {
2263
                    $avg_progress = round($progress / $nb_progress_lp, 2);
2264
                } else {
2265
                    $avg_progress = 0;
2266
                }
2267
                if ($nb_score_lp > 0) {
2268
                    $avg_score = round($score / $nb_score_lp, 2);
2269
                } else {
2270
                    $avg_score = '-';
2271
                }
2272
                if ($last_login_date) {
2273
                    $last_login_date = api_convert_and_format_date(
2274
                        $last_login_date,
2275
                        DATE_FORMAT_SHORT,
2276
                        date_default_timezone_get()
2277
                    );
2278
                } else {
2279
                    $last_login_date = '-';
2280
                }
2281
                if ($total_score_possible > 0) {
2282
                    $total_score_percentage = round($total_score_obtained / $total_score_possible * 100, 2);
2283
                } else {
2284
                    $total_score_percentage = 0;
2285
                }
2286
                if ($total_score_percentage > 0) {
2287
                    $total_score = $total_score_obtained.'/'.$total_score_possible.' ('.$total_score_percentage.' %)';
2288
                } else {
2289
                    $total_score = '-';
2290
                }
2291
                // time spent in the course
2292
                $csv_row[] = api_time_to_hms($time_spent);
2293
                // student progress in course
2294
                $csv_row[] = $avg_progress;
2295
                // student score
2296
                $csv_row[] = $avg_score;
2297
                // student messages
2298
                $csv_row[] = $nb_messages;
2299
                // student assignments
2300
                $csv_row[] = $nb_assignments;
2301
                // student exercises results (obtained score, maximum score, number of exercises answered, score percentage)
2302
                $csv_row[] = $total_score_obtained;
2303
                $csv_row[] = $total_score_possible;
2304
                $csv_row[] = $total_questions_answered;
2305
                $csv_row[] = $total_score_percentage;
2306
                // last connection
2307
                $csv_row[] = $last_login_date;
2308
                $csv_content[] = $csv_row;
2309
            }
2310
        }
2311
        Export::arrayToCsv($csv_content, 'reporting_session_overview');
2312
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
2313
    }
2314
2315
    /**
2316
     * Get general information about the exercise performance of the user
2317
     * the total obtained score (all the score on all the questions)
2318
     * the maximum score that could be obtained
2319
     * the number of questions answered
2320
     * the success percentage.
2321
     *
2322
     * @param int    $user_id     the id of the user
2323
     * @param string $course_code the course code
2324
     * @param int    $session_id
2325
     *
2326
     * @return array
2327
     *
2328
     * @author Patrick Cool <[email protected]>, Ghent University, Belgium
2329
     *
2330
     * @version Dokeos 1.8.6
2331
     *
2332
     * @since November 2008
2333
     */
2334
    public static function exercises_results($user_id, $course_code, $session_id = 0)
2335
    {
2336
        $user_id = (int) $user_id;
2337
        $courseId = api_get_course_int_id($course_code);
2338
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2339
        $sessionCondition = api_get_session_condition($session_id);
2340
        $sql = "SELECT score, max_score
2341
                FROM $table
2342
                WHERE
2343
                    c_id = $courseId AND
2344
                    exe_user_id = $user_id
2345
                    $sessionCondition
2346
                    ";
2347
2348
        $result = Database::query($sql);
2349
        $score_obtained = 0;
2350
        $score_possible = 0;
2351
        $questions_answered = 0;
2352
        while ($row = Database::fetch_array($result)) {
2353
            $score_obtained += $row['score'];
2354
            $score_possible += $row['max_score'];
2355
            $questions_answered++;
2356
        }
2357
2358
        $percentage = null;
2359
        if (0 != $score_possible) {
2360
            $percentage = round(($score_obtained / $score_possible * 100), 2);
2361
        }
2362
2363
        return [
2364
            'score_obtained' => $score_obtained,
2365
            'score_possible' => $score_possible,
2366
            'questions_answered' => $questions_answered,
2367
            'percentage' => $percentage,
2368
        ];
2369
    }
2370
2371
    /**
2372
     * This function exports the table that we see in display_tracking_user_overview().
2373
     *
2374
     * @author Patrick Cool <[email protected]>, Ghent University, Belgium
2375
     *
2376
     * @version Dokeos 1.8.6
2377
     *
2378
     * @since October 2008
2379
     */
2380
    public static function export_tracking_user_overview()
2381
    {
2382
        // database table definitions
2383
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2384
        $is_western_name_order = api_is_western_name_order(PERSON_NAME_DATA_EXPORT);
2385
2386
        // the values of the sortable table
2387
        if ($_GET['tracking_user_overview_page_nr']) {
2388
            $from = $_GET['tracking_user_overview_page_nr'];
2389
        } else {
2390
            $from = 0;
2391
        }
2392
        if ($_GET['tracking_user_overview_column']) {
2393
            $orderby = $_GET['tracking_user_overview_column'];
2394
        } else {
2395
            $orderby = 0;
2396
        }
2397
        if ($is_western_name_order != api_is_western_name_order() && (1 == $orderby || 2 == $orderby)) {
2398
            // Swapping the sorting column if name order for export is different than the common name order.
2399
            $orderby = 3 - $orderby;
2400
        }
2401
        if ($_GET['tracking_user_overview_direction']) {
2402
            $direction = $_GET['tracking_user_overview_direction'];
2403
        } else {
2404
            $direction = 'ASC';
2405
        }
2406
2407
        $user_data = self::get_user_data_tracking_overview(
2408
            $from,
2409
            1000,
2410
            $orderby,
2411
            $direction
2412
        );
2413
2414
        // the first line of the csv file with the column headers
2415
        $csv_row = [];
2416
        $csv_row[] = get_lang('Code');
2417
        if ($is_western_name_order) {
2418
            $csv_row[] = get_lang('First name');
2419
            $csv_row[] = get_lang('Last name');
2420
        } else {
2421
            $csv_row[] = get_lang('Last name');
2422
            $csv_row[] = get_lang('First name');
2423
        }
2424
        $csv_row[] = get_lang('Login');
2425
        $csv_row[] = get_lang('Code');
2426
2427
        // the additional user defined fields (only those that were selected to be exported)
2428
        $fields = UserManager::get_extra_fields(0, 50, 5, 'ASC');
2429
2430
        $additionalExportFields = Session::read('additional_export_fields');
2431
2432
        if (is_array($additionalExportFields)) {
2433
            foreach ($additionalExportFields as $key => $extra_field_export) {
2434
                $csv_row[] = $fields[$extra_field_export][3];
2435
                $field_names_to_be_exported[] = 'extra_'.$fields[$extra_field_export][1];
2436
            }
2437
        }
2438
        $csv_row[] = get_lang('Time');
2439
        $csv_row[] = get_lang('Progress');
2440
        $csv_row[] = get_lang('Average score in learning paths');
2441
        $csv_row[] = get_lang('Tests score');
2442
        $csv_row[] = get_lang('Messages per learner');
2443
        $csv_row[] = get_lang('Assignments');
2444
        $csv_row[] = get_lang('Total score obtained for tests');
2445
        $csv_row[] = get_lang('Total possible score for tests');
2446
        $csv_row[] = get_lang('Number of tests answered');
2447
        $csv_row[] = get_lang('Total score percentage for tests');
2448
        $csv_row[] = get_lang('First connection');
2449
        $csv_row[] = get_lang('Latest login');
2450
        $csv_content[] = $csv_row;
2451
2452
        // the other lines (the data)
2453
        foreach ($user_data as $user) {
2454
            // getting all the courses of the user
2455
            $sql = "SELECT * FROM $tbl_course_user
2456
                    WHERE user_id = '".intval($user[4])."' AND relation_type<>".COURSE_RELATION_TYPE_RRHH." ";
2457
            $result = Database::query($sql);
2458
            while ($row = Database::fetch_row($result)) {
2459
                $course = api_get_course_entity($row['c_id']);
2460
                $courseId = $course->getId();
2461
                $courseCode = $course->getCode();
2462
2463
                $csv_row = [];
2464
                // user official code
2465
                $csv_row[] = $user[0];
2466
                // user first|last name
2467
                $csv_row[] = $user[1];
2468
                // user last|first name
2469
                $csv_row[] = $user[2];
2470
                // user login name
2471
                $csv_row[] = $user[3];
2472
                // course code
2473
                $csv_row[] = $row[0];
2474
                // the additional defined user fields
2475
                $extra_fields = self::get_user_overview_export_extra_fields($user[4]);
2476
2477
                if (is_array($field_names_to_be_exported)) {
2478
                    foreach ($field_names_to_be_exported as $key => $extra_field_export) {
2479
                        $csv_row[] = $extra_fields[$extra_field_export];
2480
                    }
2481
                }
2482
                // time spent in the course
2483
                $csv_row[] = api_time_to_hms(Tracking::get_time_spent_on_the_course($user[4], $courseId));
2484
                // student progress in course
2485
                $csv_row[] = round(Tracking::get_avg_student_progress($user[4], $course), 2);
2486
                // student score
2487
                $csv_row[] = round(Tracking::get_avg_student_score($user[4], $course), 2);
2488
                // student tes score
2489
                $csv_row[] = round(Tracking::get_avg_student_exercise_score($user[4], $courseCode), 2);
2490
                // student messages
2491
                //$csv_row[] = Tracking::count_student_messages($user[4], $row[0]);
2492
                // student assignments
2493
                //$csv_row[] = Tracking::count_student_assignments($user[4], $row[0]);
2494
                // student exercises results
2495
                $exercises_results = self::exercises_results($user[4], $row[0]);
2496
                $csv_row[] = $exercises_results['score_obtained'];
2497
                $csv_row[] = $exercises_results['score_possible'];
2498
                $csv_row[] = $exercises_results['questions_answered'];
2499
                $csv_row[] = $exercises_results['percentage'];
2500
                // first connection
2501
                $csv_row[] = Tracking::get_first_connection_date_on_the_course($user[4], $courseId);
2502
                // last connection
2503
                $csv_row[] = strip_tags(Tracking::get_last_connection_date_on_the_course($user[4], $courseInfo));
2504
2505
                $csv_content[] = $csv_row;
2506
            }
2507
        }
2508
        Export::arrayToCsv($csv_content, 'reporting_user_overview');
2509
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
2510
    }
2511
2512
    /**
2513
     * Get data for courses list in sortable with pagination.
2514
     *
2515
     * @return array
2516
     */
2517
    public static function get_course_data($from, $number_of_items, $column, $direction)
2518
    {
2519
        global $courses, $csv_content, $charset, $session_id;
2520
2521
        // definition database tables
2522
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2523
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2524
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2525
2526
        $course_data = [];
2527
        $courses_code = array_keys($courses);
2528
2529
        foreach ($courses_code as &$code) {
2530
            $code = "'$code'";
2531
        }
2532
2533
        // get all courses with limit
2534
        $sql = "SELECT course.code as col1, course.title as col2
2535
                FROM $tbl_course course
2536
                WHERE course.code IN (".implode(',', $courses_code).")";
2537
2538
        if (!in_array($direction, ['ASC', 'DESC'])) {
2539
            $direction = 'ASC';
2540
        }
2541
2542
        $column = (int) $column;
2543
        $from = (int) $from;
2544
        $number_of_items = (int) $number_of_items;
2545
        $sql .= " ORDER BY col$column $direction ";
2546
        $sql .= " LIMIT $from,$number_of_items";
2547
2548
        $res = Database::query($sql);
2549
        while ($row_course = Database::fetch_row($res)) {
2550
            $course_code = $row_course[0];
2551
            $courseInfo = api_get_course_info($course_code);
2552
            $courseId = $courseInfo['real_id'];
2553
            $avg_assignments_in_course = $avg_messages_in_course = $nb_students_in_course = $avg_progress_in_course = $avg_score_in_course = $avg_time_spent_in_course = $avg_score_in_exercise = 0;
2554
2555
            // students directly subscribed to the course
2556
            if (empty($session_id)) {
2557
                $sql = "SELECT user_id
2558
                        FROM $tbl_course_user as course_rel_user
2559
                        WHERE
2560
                            course_rel_user.status='5' AND
2561
                            course_rel_user.c_id = '$courseId'";
2562
            } else {
2563
                $sql = "SELECT user_id FROM $tbl_session_course_user srcu
2564
                        WHERE
2565
                            c_id = '$courseId' AND
2566
                            session_id = '$session_id' AND
2567
                            status = ".SessionEntity::STUDENT;
2568
            }
2569
            $rs = Database::query($sql);
2570
            $users = [];
2571
            while ($row = Database::fetch_array($rs)) {
2572
                $users[] = $row['user_id'];
2573
            }
2574
2575
            if (count($users) > 0) {
2576
                $nb_students_in_course = count($users);
2577
                $avg_assignments_in_course = Tracking::count_student_assignments($users, $course_code, $session_id);
2578
                $avg_messages_in_course = Tracking::count_student_messages($users, $course_code, $session_id);
2579
                $avg_progress_in_course = Tracking::get_avg_student_progress($users, $course_code, [], $session_id);
2580
                $avg_score_in_course = Tracking::get_avg_student_score($users, $course_code, [], $session_id);
2581
                $avg_score_in_exercise = Tracking::get_avg_student_exercise_score($users, $course_code, 0, $session_id);
2582
                $avg_time_spent_in_course = Tracking::get_time_spent_on_the_course(
2583
                    $users,
2584
                    $courseInfo['real_id'],
2585
                    $session_id
2586
                );
2587
2588
                $avg_progress_in_course = round($avg_progress_in_course / $nb_students_in_course, 2);
2589
                if (is_numeric($avg_score_in_course)) {
2590
                    $avg_score_in_course = round($avg_score_in_course / $nb_students_in_course, 2);
2591
                }
2592
                $avg_time_spent_in_course = api_time_to_hms($avg_time_spent_in_course / $nb_students_in_course);
2593
            } else {
2594
                $avg_time_spent_in_course = null;
2595
                $avg_progress_in_course = null;
2596
                $avg_score_in_course = null;
2597
                $avg_score_in_exercise = null;
2598
                $avg_messages_in_course = null;
2599
                $avg_assignments_in_course = null;
2600
            }
2601
            $table_row = [];
2602
            $table_row[] = $row_course[1];
2603
            $table_row[] = $nb_students_in_course;
2604
            $table_row[] = $avg_time_spent_in_course;
2605
            $table_row[] = is_null($avg_progress_in_course) ? '' : $avg_progress_in_course.'%';
2606
            $table_row[] = is_null($avg_score_in_course) ? '' : $avg_score_in_course.'%';
2607
            $table_row[] = is_null($avg_score_in_exercise) ? '' : $avg_score_in_exercise.'%';
2608
            $table_row[] = $avg_messages_in_course;
2609
            $table_row[] = $avg_assignments_in_course;
2610
2611
            //set the "from" value to know if I access the Reporting by the chamilo tab or the course link
2612
            $table_row[] = '<center><a href="../../tracking/courseLog.php?cidReq='.$course_code.'&from=myspace&id_session='.$session_id.'">
2613
                             '.Display::getMdiIcon('fast-forward-outline', 'ch-tool-icon', null, 22, get_lang('Details')).'
2614
                             </a>
2615
                            </center>';
2616
2617
            $scoreInCourse = null;
2618
            if (null !== $avg_score_in_course) {
2619
                if (is_numeric($avg_score_in_course)) {
2620
                    $scoreInCourse = $avg_score_in_course.'%';
2621
                } else {
2622
                    $scoreInCourse = $avg_score_in_course;
2623
                }
2624
            }
2625
2626
            $csv_content[] = [
2627
                api_html_entity_decode($row_course[1], ENT_QUOTES, $charset),
2628
                $nb_students_in_course,
2629
                $avg_time_spent_in_course,
2630
                is_null($avg_progress_in_course) ? null : $avg_progress_in_course.'%',
2631
                $scoreInCourse,
2632
                is_null($avg_score_in_exercise) ? null : $avg_score_in_exercise.'%',
2633
                $avg_messages_in_course,
2634
                $avg_assignments_in_course,
2635
            ];
2636
            $course_data[] = $table_row;
2637
        }
2638
2639
        return $course_data;
2640
    }
2641
2642
    /**
2643
     * Get the number of users of the platform.
2644
     *
2645
     * @return int
2646
     */
2647
    public static function get_number_of_users_tracking_overview()
2648
    {
2649
        return UserManager::get_number_of_users(0, api_get_current_access_url_id());
2650
    }
2651
2652
    /**
2653
     * Get all the data for the sortable table of the reporting progress of
2654
     * all users and all the courses the user is subscribed to.
2655
     *
2656
     * @param int    $from
2657
     * @param int    $numberItems
2658
     * @param int    $column
2659
     * @param string $direction
2660
     *
2661
     * @return array
2662
     */
2663
    public static function get_user_data_tracking_overview($from, $numberItems, $column, $direction)
2664
    {
2665
        $isWestern = api_is_western_name_order();
2666
2667
        switch ($column) {
2668
            case '0':
2669
                $column = $isWestern ? 'firstname' : 'lastname';
2670
                break;
2671
        }
2672
2673
        $order = [
2674
            " `$column` $direction",
2675
        ];
2676
        $userList = UserManager::get_user_list([], $order, $from, $numberItems);
2677
        $return = [];
2678
        foreach ($userList as $user) {
2679
            $return[] = [
2680
                '0' => $user['user_id'],
2681
                'col0' => $user['user_id'],
2682
            ];
2683
        }
2684
2685
        return $return;
2686
    }
2687
2688
    /**
2689
     * Get all information that the user with user_id = $user_data has
2690
     * entered in the additionally defined profile fields.
2691
     *
2692
     * @param int $user_id the id of the user
2693
     *
2694
     * @return array
2695
     *
2696
     * @author Patrick Cool <[email protected]>, Ghent University, Belgium
2697
     *
2698
     * @version Dokeos 1.8.6
2699
     *
2700
     * @since November 2008
2701
     */
2702
    public static function get_user_overview_export_extra_fields($user_id)
2703
    {
2704
        // include the user manager
2705
        $data = UserManager::get_extra_user_data($user_id, true);
2706
2707
        return $data;
2708
    }
2709
2710
    /**
2711
     * Checks if a username exist in the DB otherwise it create a "double"
2712
     * i.e. if we look into for jmontoya but the user's name already exist we create the user jmontoya2
2713
     * the return array will be array(username=>'jmontoya', sufix='2').
2714
     *
2715
     * @param string firstname
2716
     * @param string lastname
2717
     * @param string username
2718
     *
2719
     * @return array with the username, the sufix
2720
     *
2721
     * @author Julio Montoya
2722
     */
2723
    public static function make_username($firstname, $lastname, $username, $language = null, $encoding = null)
2724
    {
2725
        // if username exist
2726
        if (!Container::getUserRepository()->isUsernameAvailable($username) || empty($username)) {
2727
            $i = 0;
2728
            while (1) {
2729
                if (0 == $i) {
2730
                    $sufix = '';
2731
                } else {
2732
                    $sufix = $i;
2733
                }
2734
                $desired_username = UserManager::create_username(
2735
                    $firstname,
2736
                    $lastname
2737
                );
2738
                if (Container::getUserRepository()->isUsernameAvailable($desired_username.$sufix)) {
2739
                    break;
2740
                } else {
2741
                    $i++;
2742
                }
2743
            }
2744
            $username_array = ['username' => $desired_username, 'sufix' => $sufix];
2745
2746
            return $username_array;
2747
        } else {
2748
            $username_array = ['username' => $username, 'sufix' => ''];
2749
2750
            return $username_array;
2751
        }
2752
    }
2753
2754
    /**
2755
     * Checks if there are repeted users in a given array.
2756
     *
2757
     * @param array $usernames  list of the usernames in the uploaded file
2758
     * @param array $user_array $user_array['username'] and $user_array['sufix']
2759
     *                          where suffix is the number part in a login i.e -> jmontoya2
2760
     *
2761
     * @return array with the $usernames array and the $user_array array
2762
     *
2763
     * @author Julio Montoya
2764
     */
2765
    public static function check_user_in_array($usernames, $user_array)
2766
    {
2767
        $user_list = array_keys($usernames);
2768
        $username = $user_array['username'].$user_array['sufix'];
2769
2770
        if (in_array($username, $user_list)) {
2771
            $user_array['sufix'] += $usernames[$username];
2772
            $usernames[$username]++;
2773
        } else {
2774
            $usernames[$username] = 1;
2775
        }
2776
        $result_array = [$usernames, $user_array];
2777
2778
        return $result_array;
2779
    }
2780
2781
    /**
2782
     * Checks whether a username has been already subscribed in a session.
2783
     *
2784
     * @param string $username    a given username
2785
     * @param array  $course_list the array with the course list id
2786
     * @param int    $id_session  the session id
2787
     *
2788
     * @return int 0 if the user is not subscribed otherwise it returns the user_id of the given username
2789
     *
2790
     * @author Julio Montoya
2791
     */
2792
    public static function user_available_in_session($username, $course_list, $id_session)
2793
    {
2794
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
2795
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2796
        $id_session = (int) $id_session;
2797
        $username = Database::escape_string($username);
2798
        foreach ($course_list as $courseId) {
2799
            $courseId = (int) $courseId;
2800
            $sql = " SELECT u.id as user_id FROM $tbl_session_rel_course_rel_user rel
2801
                     INNER JOIN $table_user u
2802
                     ON (rel.user_id = u.id)
2803
                     WHERE
2804
                        rel.session_id='$id_session' AND
2805
                        u.status='5' AND
2806
                        u.username ='$username' AND
2807
                        rel.c_id='$courseId'";
2808
            $rs = Database::query($sql);
2809
            if (Database::num_rows($rs) > 0) {
2810
                return Database::result($rs, 0, 0);
2811
            }
2812
        }
2813
2814
        return 0;
2815
    }
2816
2817
    /**
2818
     * This function checks whether some users in the uploaded file
2819
     * repeated and creates unique usernames if necesary.
2820
     * A case: Within the file there is an user repeted twice (Julio Montoya / Julio Montoya)
2821
     * and the username fields are empty.
2822
     * Then, this function would create unique usernames based on the first and the last name.
2823
     * Two users wiould be created - jmontoya and jmontoya2.
2824
     * Of course, if in the database there is a user with the name jmontoya,
2825
     * the newly created two users registered would be jmontoya2 and jmontoya3.
2826
     *
2827
     * @param $users list of users
2828
     *
2829
     * @return array
2830
     *
2831
     * @author Julio Montoya Armas
2832
     */
2833
    public static function check_all_usernames($users, $course_list, $id_session)
2834
    {
2835
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
2836
        $usernames = [];
2837
        $new_users = [];
2838
        foreach ($users as $index => $user) {
2839
            $desired_username = [];
2840
            if (empty($user['UserName'])) {
2841
                $desired_username = self::make_username($user['FirstName'], $user['LastName'], '');
2842
                $pre_username = $desired_username['username'].$desired_username['sufix'];
2843
                $user['UserName'] = $pre_username;
2844
                $user['create'] = '1';
2845
            } else {
2846
                if (Container::getUserRepository()->isUsernameAvailable($user['UserName'])) {
2847
                    $desired_username = self::make_username($user['FirstName'], $user['LastName'], $user['UserName']);
2848
                    $user['UserName'] = $desired_username['username'].$desired_username['sufix'];
2849
                    $user['create'] = '1';
2850
                } else {
2851
                    $is_session_avail = self::user_available_in_session($user['UserName'], $course_list, $id_session);
2852
                    if (0 == $is_session_avail) {
2853
                        $user_name = $user['UserName'];
2854
                        $sql_select = "SELECT user_id FROM $table_user WHERE username ='$user_name' ";
2855
                        $rs = Database::query($sql_select);
2856
                        $user['create'] = Database::result($rs, 0, 0);
2857
                    } else {
2858
                        $user['create'] = $is_session_avail;
2859
                    }
2860
                }
2861
            }
2862
            // Usernames is the current list of users in the file.
2863
            $result_array = self::check_user_in_array($usernames, $desired_username);
2864
            $usernames = $result_array[0];
2865
            $desired_username = $result_array[1];
2866
            $user['UserName'] = $desired_username['username'].$desired_username['sufix'];
2867
            $new_users[] = $user;
2868
        }
2869
2870
        return $new_users;
2871
    }
2872
2873
    /**
2874
     * This functions checks whether there are users that are already
2875
     * registered in the DB by different creator than the current coach.
2876
     *
2877
     * @param array $users
2878
     *
2879
     * @return array
2880
     *
2881
     * @author Julio Montoya Armas
2882
     */
2883
    public static function get_user_creator($users)
2884
    {
2885
        $errors = [];
2886
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
2887
        foreach ($users as $index => $user) {
2888
            $username = Database::escape_string($user['UserName']);
2889
            $sql = "SELECT creator_id FROM $table_user WHERE username='$username' ";
2890
2891
            $rs = Database::query($sql);
2892
            $creator_id = Database::result($rs, 0, 0);
2893
            // check if we are the creators or not
2894
            if ('' != $creator_id) {
2895
                if ($creator_id != api_get_user_id()) {
2896
                    $user['error'] = get_lang('User already register by other coach.');
2897
                    $errors[] = $user;
2898
                }
2899
            }
2900
        }
2901
2902
        return $errors;
2903
    }
2904
2905
    /**
2906
     * Validates imported data.
2907
     *
2908
     * @param array $users list of users
2909
     */
2910
    public static function validate_data($users, $id_session = null)
2911
    {
2912
        $errors = [];
2913
        $new_users = [];
2914
        foreach ($users as $index => $user) {
2915
            // 1. Check whether mandatory fields are set.
2916
            $mandatory_fields = ['LastName', 'FirstName'];
2917
            if ('true' == api_get_setting('registration', 'email')) {
2918
                $mandatory_fields[] = 'Email';
2919
            }
2920
2921
            foreach ($mandatory_fields as $key => $field) {
2922
                if (!isset($user[$field]) || 0 == strlen($user[$field])) {
2923
                    $user['error'] = get_lang($field.'Mandatory');
2924
                    $errors[] = $user;
2925
                }
2926
            }
2927
            // 2. Check whether the username is too long.
2928
            if (UserManager::is_username_too_long($user['UserName'])) {
2929
                $user['error'] = get_lang('This login is too long');
2930
                $errors[] = $user;
2931
            }
2932
2933
            $user['UserName'] = trim($user['UserName']);
2934
2935
            if (empty($user['UserName'])) {
2936
                $user['UserName'] = UserManager::create_username($user['FirstName'], $user['LastName']);
2937
            }
2938
            $new_users[] = $user;
2939
        }
2940
        $results = ['errors' => $errors, 'users' => $new_users];
2941
2942
        return $results;
2943
    }
2944
2945
    /**
2946
     * Adds missing user-information (which isn't required, like password, etc).
2947
     */
2948
    public static function complete_missing_data($user)
2949
    {
2950
        // 1. Generate a password if it is necessary.
2951
        if (!isset($user['Password']) || 0 == strlen($user['Password'])) {
2952
            $user['Password'] = api_generate_password();
2953
        }
2954
2955
        return $user;
2956
    }
2957
2958
    /**
2959
     * Saves imported data.
2960
     */
2961
    public static function save_data($users, $course_list, $id_session)
2962
    {
2963
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2964
        $tbl_session_rel_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
2965
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2966
        $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
2967
2968
        $id_session = (int) $id_session;
2969
        $sendMail = $_POST['sendMail'] ? 1 : 0;
2970
2971
        // Adding users to the platform.
2972
        $new_users = [];
2973
        foreach ($users as $index => $user) {
2974
            $user = self::complete_missing_data($user);
2975
            // coach only will registered users
2976
            $default_status = STUDENT;
2977
            if (COURSEMANAGER == $user['create']) {
2978
                $user['id'] = UserManager:: create_user(
2979
                    $user['FirstName'],
2980
                    $user['LastName'],
2981
                    $default_status,
2982
                    $user['Email'],
2983
                    $user['UserName'],
2984
                    $user['Password'],
2985
                    $user['OfficialCode'],
2986
                    api_get_setting('PlatformLanguage'),
2987
                    $user['PhoneNumber']
2988
                );
2989
                $user['added_at_platform'] = 1;
2990
            } else {
2991
                $user['id'] = $user['create'];
2992
                $user['added_at_platform'] = 0;
2993
            }
2994
            $new_users[] = $user;
2995
        }
2996
        // Update user list.
2997
        $users = $new_users;
2998
2999
        // Inserting users.
3000
        SessionManager::insertUsersInCourses(
3001
            array_column($users, 'id'),
3002
            $course_list,
3003
            $id_session
3004
        );
3005
3006
        array_walk(
3007
            $users,
3008
            function (array &$user) {
3009
                $user['added_at_session'] = 1;
3010
            }
3011
        );
3012
3013
        $registered_users = get_lang('File imported').'<br /> Import file results : <br />';
3014
        // Sending emails.
3015
        $addedto = '';
3016
        if ($sendMail) {
3017
            foreach ($users as $index => $user) {
3018
                $emailsubject = '['.api_get_setting('siteName').'] '.get_lang('Your registration on').' '.api_get_setting('siteName');
3019
                $emailbody = get_lang('Dear').' '.
3020
                    api_get_person_name($user['First name'], $user['Last name']).",\n\n".
3021
                    get_lang('You are registered to')." ".api_get_setting('siteName')." ".get_lang('with the following settings:')."\n\n".
3022
                    get_lang('Username')." : $user[UserName]\n".
3023
                    get_lang('Pass')." : $user[Password]\n\n".
3024
                    get_lang('The address of')." ".api_get_setting('siteName')." ".get_lang('is')." : ".api_get_path(WEB_PATH)." \n\n".
3025
                    get_lang('In case of trouble, contact us.')."\n\n".
3026
                    get_lang('Sincerely').",\n\n".
3027
                    api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'))."\n".
3028
                    get_lang('Administrator')." ".api_get_setting('siteName')."\nT. ".
3029
                    api_get_setting('administratorTelephone')."\n".get_lang('E-mail')." : ".api_get_setting('emailAdministrator');
3030
3031
                api_mail_html(
3032
                    api_get_person_name($user['First name'], $user['Last name'], null, PERSON_NAME_EMAIL_ADDRESS),
3033
                    $user['e-mail'],
3034
                    $emailsubject,
3035
                    $emailbody
3036
                );
3037
                $userInfo = api_get_user_info($user['id']);
3038
3039
                if ((1 == $user['added_at_platform'] && 1 == $user['added_at_session']) || 1 == $user['added_at_session']) {
3040
                    if (1 == $user['added_at_platform']) {
3041
                        $addedto = get_lang('User created in portal');
3042
                    } else {
3043
                        $addedto = '          ';
3044
                    }
3045
3046
                    if (1 == $user['added_at_session']) {
3047
                        $addedto .= get_lang('User added into the session');
3048
                    }
3049
                } else {
3050
                    $addedto = get_lang('User not added.');
3051
                }
3052
3053
                $registered_users .= UserManager::getUserProfileLink($userInfo).' - '.$addedto.'<br />';
3054
            }
3055
        } else {
3056
            foreach ($users as $index => $user) {
3057
                $userInfo = api_get_user_info($user['id']);
3058
                if ((1 == $user['added_at_platform'] && 1 == $user['added_at_session']) || 1 == $user['added_at_session']) {
3059
                    if (1 == $user['added_at_platform']) {
3060
                        $addedto = get_lang('User created in portal');
3061
                    } else {
3062
                        $addedto = '          ';
3063
                    }
3064
3065
                    if (1 == $user['added_at_session']) {
3066
                        $addedto .= ' '.get_lang('User added into the session');
3067
                    }
3068
                } else {
3069
                    $addedto = get_lang('User not added.');
3070
                }
3071
                $registered_users .= "<a href=\"../user/userInfo.php?uInfo=".$user['id']."\">".
3072
                    Security::remove_XSS($userInfo['complete_user_name'])."</a> - ".$addedto.'<br />';
3073
            }
3074
        }
3075
        Display::addFlash(Display::return_message($registered_users, 'normal', false));
3076
        header('Location: course.php?id_session='.$id_session);
3077
        exit;
3078
    }
3079
3080
    /**
3081
     * Reads CSV-file.
3082
     *
3083
     * @param string $file Path to the CSV-file
3084
     *
3085
     * @return array All userinformation read from the file
3086
     */
3087
    public static function parse_csv_data($file)
3088
    {
3089
        $users = Import::csvToArray($file);
3090
        foreach ($users as $index => $user) {
3091
            if (isset($user['Courses'])) {
3092
                $user['Courses'] = explode('|', trim($user['Courses']));
3093
            }
3094
            $users[$index] = $user;
3095
        }
3096
3097
        return $users;
3098
    }
3099
3100
    /**
3101
     * Reads XML-file.
3102
     *
3103
     * @param string $file Path to the XML-file
3104
     *
3105
     * @return array All userinformation read from the file
3106
     */
3107
    public static function parse_xml_data($file)
3108
    {
3109
        $crawler = new \Symfony\Component\DomCrawler\Crawler();
3110
        $crawler->addXmlContent(file_get_contents($file));
3111
        $crawler = $crawler->filter('Contacts > Contact ');
3112
        $array = [];
3113
        foreach ($crawler as $domElement) {
3114
            $row = [];
3115
            foreach ($domElement->childNodes as $node) {
3116
                if ('#text' != $node->nodeName) {
3117
                    $row[$node->nodeName] = $node->nodeValue;
3118
                }
3119
            }
3120
            if (!empty($row)) {
3121
                $array[] = $row;
3122
            }
3123
        }
3124
3125
        return $array;
3126
    }
3127
3128
    /**
3129
     * @param int $courseId
3130
     * @param int $sessionId
3131
     * @param int $studentId
3132
     */
3133
    public static function displayTrackingAccessOverView(
3134
        $courseId,
3135
        $sessionId,
3136
        $studentId,
3137
        $perPage = 20,
3138
        $dates = null
3139
    ) {
3140
        $courseId = (int) $courseId;
3141
        $sessionId = (int) $sessionId;
3142
        $studentId = (int) $studentId;
3143
3144
        $courseList = [];
3145
        $sessionList = [];
3146
        $studentList = [];
3147
3148
        if (!empty($courseId)) {
3149
            $course = api_get_course_entity($courseId);
3150
            if ($course) {
3151
                $courseList[$course->getId()] = $course->getTitle();
3152
            }
3153
        }
3154
3155
        if (!empty($sessionId)) {
3156
            $session = api_get_session_entity($sessionId);
3157
            if ($session) {
3158
                $sessionList[$session->getId()] = $session->getTitle();
3159
            }
3160
        }
3161
3162
        if (!empty($studentId)) {
3163
            $student = api_get_user_entity($studentId);
3164
            if ($student) {
3165
                $studentList[$student->getId()] = UserManager::formatUserFullName($student);
3166
            }
3167
        }
3168
3169
        $form = new FormValidator('access_overview', 'GET');
3170
        $form->addElement(
3171
            'select_ajax',
3172
            'course_id',
3173
            get_lang('Search courses'),
3174
            $courseList,
3175
            [
3176
                'url' => api_get_path(WEB_AJAX_PATH).'course.ajax.php?'.http_build_query([
3177
                    'a' => 'search_course_by_session_all',
3178
                    'session_id' => $sessionId,
3179
                    'course_id' => $courseId,
3180
                ]),
3181
            ]
3182
        );
3183
3184
        $form->addElement(
3185
            'select_ajax',
3186
            'session_id',
3187
            get_lang('Search sessions'),
3188
            $sessionList,
3189
            [
3190
                'url_function' => "
3191
                    function () {
3192
                        var params = $.param({
3193
                            a: 'search_session_by_course',
3194
                            course_id: $('#access_overview_course_id').val() || 0
3195
                        });
3196
3197
                        return '".api_get_path(WEB_AJAX_PATH)."session.ajax.php?' + params;
3198
                    }
3199
                ",
3200
            ]
3201
        );
3202
3203
        $form->addSelect(
3204
            'profile',
3205
            get_lang('Profile'),
3206
            [
3207
                '' => get_lang('Select'),
3208
                STUDENT => get_lang('Learner'),
3209
                COURSEMANAGER => get_lang('Teacher'),
3210
                DRH => get_lang('Human Resources Manager'),
3211
            ],
3212
            ['id' => 'profile']
3213
        );
3214
3215
        $form->addElement(
3216
            'select_ajax',
3217
            'student_id',
3218
            get_lang('Search users'),
3219
            $studentList,
3220
            [
3221
                'placeholder' => get_lang('All'),
3222
                'url_function' => "
3223
                    function () {
3224
                        var params = $.param({
3225
                            a: 'search_user_by_course',
3226
                            session_id: $('#access_overview_session_id').val(),
3227
                            course_id: $('#access_overview_course_id').val()
3228
                        });
3229
3230
                        return '".api_get_path(WEB_AJAX_PATH)."course.ajax.php?' + params;
3231
                    }
3232
                ",
3233
            ]
3234
        );
3235
        $form->addDateRangePicker(
3236
            'date',
3237
            get_lang('Date range'),
3238
            true,
3239
            [
3240
                'id' => 'date_range',
3241
                'format' => 'YYYY-MM-DD HH:mm',
3242
                'timePicker' => 'true',
3243
            ]
3244
        );
3245
        $form->addHidden('display', 'accessoverview');
3246
        $form->addRule('course_id', get_lang('Required'), 'required');
3247
        $form->addRule('profile', get_lang('Required'), 'required');
3248
        $form->addButton('submit', get_lang('Generate'), 'gear', 'primary');
3249
3250
        $table = null;
3251
        if (!empty($dates)) {
3252
            $table = new SortableTable(
3253
                'tracking_access_overview',
3254
                ['MySpace', 'getNumberOfTrackAccessOverview'],
3255
                ['MySpace', 'getUserDataAccessTrackingOverview'],
3256
                0,
3257
                $perPage
3258
            );
3259
            $table->set_additional_parameters(
3260
                [
3261
                    'course_id' => $courseId,
3262
                    'session_id' => $sessionId,
3263
                    'student_id' => $studentId,
3264
                    'date' => $dates,
3265
                    'tracking_access_overview_per_page' => $perPage,
3266
                    'display' => 'accessoverview',
3267
                ]
3268
            );
3269
            $table->set_header(0, get_lang('Login date'), true);
3270
            $table->set_header(1, get_lang('Username'), true);
3271
            if (api_is_western_name_order()) {
3272
                $table->set_header(2, get_lang('First name'), true);
3273
                $table->set_header(3, get_lang('Last name'), true);
3274
            } else {
3275
                $table->set_header(2, get_lang('Last name'), true);
3276
                $table->set_header(3, get_lang('First name'), true);
3277
            }
3278
            $table->set_header(4, get_lang('IP'), false);
3279
            $table->set_header(5, get_lang('Time connected (hh:mm)'), false);
3280
        }
3281
3282
        $template = new Template(
3283
            null,
3284
            false,
3285
            false,
3286
            false,
3287
            false,
3288
            false,
3289
            false
3290
        );
3291
        $template->assign('form', $form->returnForm());
3292
        $template->assign('table', $table ? $table->return_table() : null);
3293
3294
        echo $template->fetch(
3295
            $template->get_template('my_space/accessoverview.tpl')
3296
        );
3297
    }
3298
3299
    /**
3300
     * @return int
3301
     */
3302
    public static function getNumberOfTrackAccessOverview()
3303
    {
3304
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
3305
        $sql = "SELECT COUNT(course_access_id) count FROM $table";
3306
        $result = Database::query($sql);
3307
        $row = Database::fetch_assoc($result);
3308
3309
        if ($row) {
3310
            return $row['count'];
3311
        }
3312
3313
        return 0;
3314
    }
3315
3316
    /**
3317
     * @param $from
3318
     * @param $numberItems
3319
     * @param $column
3320
     * @param $orderDirection
3321
     *
3322
     * @return array
3323
     */
3324
    public static function getUserDataAccessTrackingOverview(
3325
        $from,
3326
        $numberItems,
3327
        $column,
3328
        $orderDirection
3329
    ) {
3330
        $from = (int) $from;
3331
        $numberItems = (int) $numberItems;
3332
        $column = (int) $column;
3333
        $orderDirection = Database::escape_string($orderDirection);
3334
        $orderDirection = !in_array(strtolower(trim($orderDirection)), ['asc', 'desc']) ? 'asc' : $orderDirection;
3335
3336
        $user = Database::get_main_table(TABLE_MAIN_USER);
3337
        $course = Database::get_main_table(TABLE_MAIN_COURSE);
3338
        $track_e_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
3339
        $trackCourseAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
3340
3341
        global $export_csv;
3342
        $is_western_name_order = api_is_western_name_order();
3343
        if ($export_csv) {
3344
            $is_western_name_order = api_is_western_name_order(PERSON_NAME_DATA_EXPORT);
3345
        }
3346
3347
        //TODO add course name
3348
        $sql = "SELECT
3349
                a.login_course_date as col0,
3350
                u.username as col1,
3351
                ".(
3352
                    $is_western_name_order ? "
3353
                        u.firstname AS col2,
3354
                        u.lastname AS col3,
3355
                    " : "
3356
                        u.lastname AS col2,
3357
                        u.firstname AS col3,
3358
                "
3359
        )."
3360
                a.login_course_date,
3361
                a.logout_course_date,
3362
                c.title,
3363
                c.code,
3364
                u.id as user_id,
3365
                user_ip
3366
            FROM $trackCourseAccess a
3367
            INNER JOIN $user u
3368
            ON a.user_id = u.id
3369
            INNER JOIN $course c
3370
            ON a.c_id = c.id
3371
            WHERE 1=1 ";
3372
3373
        $sql = self::getDataAccessTrackingFilters($sql);
3374
3375
        $sql .= " ORDER BY col$column $orderDirection ";
3376
        $sql .= " LIMIT $from,$numberItems";
3377
3378
        $result = Database::query($sql);
3379
3380
        $data = [];
3381
        while ($user = Database::fetch_assoc($result)) {
3382
            $data[] = $user;
3383
        }
3384
3385
        $return = [];
3386
        //TODO: Dont use numeric index
3387
        foreach ($data as $key => $info) {
3388
            $return[] = [
3389
                api_get_local_time($info['login_course_date']),
3390
                $info['col1'],
3391
                $info['col2'],
3392
                $info['col3'],
3393
                $info['user_ip'],
3394
                gmdate('H:i:s', strtotime($info['logout_course_date']) - strtotime($info['login_course_date'])),
3395
            ];
3396
        }
3397
3398
        return $return;
3399
    }
3400
3401
    /**
3402
     * Gets the connections to a course as an array of login and logout time.
3403
     *
3404
     * @param int    $user_id
3405
     * @param array  $course_info
3406
     * @param int    $sessionId
3407
     * @param string $start_date
3408
     * @param string $end_date
3409
     * @param bool   $addUserIp
3410
     *
3411
     * @author  Jorge Frisancho Jibaja
3412
     * @author  Julio Montoya <[email protected]> fixing the function
3413
     *
3414
     * @version OCT-22- 2010
3415
     *
3416
     * @return array
3417
     */
3418
    public static function get_connections_to_course_by_date(
3419
        $user_id,
3420
        $course_info,
3421
        $sessionId,
3422
        $start_date,
3423
        $end_date,
3424
        $addUserIp = false
3425
    ) {
3426
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
3427
        $user_id = (int) $user_id;
3428
        $connections = [];
3429
        if (!empty($course_info)) {
3430
            $courseId = (int) $course_info['real_id'];
3431
            $end_date = self::add_day_to($end_date);
3432
3433
            $start_date = Database::escape_string($start_date);
3434
            $end_date = Database::escape_string($end_date);
3435
            $sessionCondition = api_get_session_condition($sessionId);
3436
            $sql = "SELECT
3437
                        login_course_date,
3438
                        logout_course_date,
3439
                        TIMESTAMPDIFF(SECOND, login_course_date, logout_course_date) duration,
3440
                        user_ip
3441
                    FROM $table
3442
                    WHERE
3443
                        user_id = $user_id AND
3444
                        c_id = $courseId AND
3445
                        login_course_date BETWEEN '$start_date' AND '$end_date' AND
3446
                        logout_course_date BETWEEN '$start_date' AND '$end_date'
3447
                        $sessionCondition
3448
                    ORDER BY login_course_date ASC";
3449
            $rs = Database::query($sql);
3450
3451
            while ($row = Database::fetch_array($rs)) {
3452
                $item = [
3453
                    'login' => $row['login_course_date'],
3454
                    'logout' => $row['logout_course_date'],
3455
                    'duration' => $row['duration'],
3456
                ];
3457
                if ($addUserIp) {
3458
                    $item['user_ip'] = $row['user_ip'];
3459
                }
3460
                $connections[] = $item;
3461
            }
3462
        }
3463
3464
        return $connections;
3465
    }
3466
3467
    /**
3468
     * @param int   $user_id
3469
     * @param array $course_info
3470
     * @param int   $sessionId
3471
     * @param null  $start_date
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $start_date is correct as it would always require null to be passed?
Loading history...
3472
     * @param null  $end_date
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $end_date is correct as it would always require null to be passed?
Loading history...
3473
     *
3474
     * @return array
3475
     */
3476
    public static function getStats($user_id, $course_info, $sessionId, $start_date = null, $end_date = null)
3477
    {
3478
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
3479
        $result = [];
3480
        if (!empty($course_info)) {
3481
            $stringStartDate = '';
3482
            $stringEndDate = '';
3483
            if (null != $start_date && null != $end_date) {
3484
                $end_date = self::add_day_to($end_date);
3485
3486
                $start_date = Database::escape_string($start_date);
3487
                $end_date = Database::escape_string($end_date);
3488
3489
                $stringStartDate = "AND login_course_date BETWEEN '$start_date' AND '$end_date'";
3490
                $stringEndDate = "AND logout_course_date BETWEEN '$start_date' AND '$end_date'";
3491
            }
3492
            $user_id = (int) $user_id;
3493
            $courseId = (int) $course_info['real_id'];
3494
            $sessionCondition = api_get_session_condition($sessionId);
3495
            $sql = "SELECT
3496
                SEC_TO_TIME(AVG(time_to_sec(timediff(logout_course_date,login_course_date)))) as avrg,
3497
                SEC_TO_TIME(SUM(time_to_sec(timediff(logout_course_date,login_course_date)))) as total,
3498
                count(user_id) as times
3499
                FROM $table
3500
                WHERE
3501
                    user_id = $user_id AND
3502
                    c_id = $courseId $stringStartDate $stringEndDate
3503
                    $sessionCondition
3504
                ORDER BY login_course_date ASC";
3505
3506
            $rs = Database::query($sql);
3507
            if ($row = Database::fetch_array($rs)) {
3508
                $foo_avg = $row['avrg'];
3509
                $foo_total = $row['total'];
3510
                $foo_times = $row['times'];
3511
                $result = [
3512
                'avg' => $foo_avg,
3513
                'total' => $foo_total,
3514
                'times' => $foo_times,
3515
            ];
3516
            }
3517
        }
3518
3519
        return $result;
3520
    }
3521
3522
    public static function add_day_to($end_date)
3523
    {
3524
        $foo_date = strtotime($end_date);
3525
        $foo_date = strtotime(' +1 day', $foo_date);
3526
        $foo_date = date('Y-m-d', $foo_date);
3527
3528
        return $foo_date;
3529
    }
3530
3531
    /**
3532
     * This function draw the graphic to be displayed on the user view as an image.
3533
     *
3534
     * @param array  $sql_result
3535
     * @param string $start_date
3536
     * @param string $end_date
3537
     * @param string $type
3538
     *
3539
     * @author Jorge Frisancho Jibaja
3540
     *
3541
     * @version OCT-22- 2010
3542
     *
3543
     * @return string
3544
     */
3545
    public static function grapher($sql_result, $start_date, $end_date, $type = '')
3546
    {
3547
        if (empty($start_date)) {
3548
            $start_date = '';
3549
        }
3550
        if (empty($end_date)) {
3551
            $end_date = '';
3552
        }
3553
        if ('' == $type) {
3554
            $type = 'day';
3555
        }
3556
        $main_year = $main_month_year = $main_day = [];
3557
3558
        $period = new DatePeriod(
3559
        new DateTime($start_date),
3560
        new DateInterval('P1D'),
3561
        new DateTime($end_date)
3562
    );
3563
3564
        foreach ($period as $date) {
3565
            $main_day[$date->format('d-m-Y')] = 0;
3566
        }
3567
3568
        $period = new DatePeriod(
3569
        new DateTime($start_date),
3570
        new DateInterval('P1M'),
3571
        new DateTime($end_date)
3572
    );
3573
3574
        foreach ($period as $date) {
3575
            $main_month_year[$date->format('m-Y')] = 0;
3576
        }
3577
3578
        $i = 0;
3579
        if (is_array($sql_result) && count($sql_result) > 0) {
3580
            foreach ($sql_result as $key => $data) {
3581
                $login = api_strtotime($data['login']);
3582
                $logout = api_strtotime($data['logout']);
3583
                //creating the main array
3584
                if (isset($main_month_year[date('m-Y', $login)])) {
3585
                    $main_month_year[date('m-Y', $login)] += (float) ($logout - $login) / 60;
3586
                }
3587
                if (isset($main_day[date('d-m-Y', $login)])) {
3588
                    $main_day[date('d-m-Y', $login)] += (float) ($logout - $login) / 60;
3589
                }
3590
                if ($i > 500) {
3591
                    break;
3592
                }
3593
                $i++;
3594
            }
3595
            switch ($type) {
3596
            case 'day':
3597
                $main_date = $main_day;
3598
                break;
3599
            case 'month':
3600
                $main_date = $main_month_year;
3601
                break;
3602
            case 'year':
3603
                $main_date = $main_year;
3604
                break;
3605
        }
3606
3607
            $labels = array_keys($main_date);
3608
            if (1 == count($main_date)) {
3609
                $labels = $labels[0];
3610
                $main_date = $main_date[$labels];
3611
            }
3612
3613
            /* Create and populate the pData object */
3614
            $myData = new pData();
3615
            $myData->addPoints($main_date, 'Serie1');
3616
            if (1 != count($main_date)) {
3617
                $myData->addPoints($labels, 'Labels');
3618
                $myData->setSerieDescription('Labels', 'Months');
3619
                $myData->setAbscissa('Labels');
3620
            }
3621
            $myData->setSerieWeight('Serie1', 1);
3622
            $myData->setSerieDescription('Serie1', get_lang('My results'));
3623
            $myData->setAxisName(0, get_lang('Minutes'));
3624
            $myData->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
3625
3626
            // Cache definition
3627
            $cachePath = api_get_path(SYS_ARCHIVE_PATH);
3628
            $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]);
3629
            $chartHash = $myCache->getHash($myData);
3630
3631
            if ($myCache->isInCache($chartHash)) {
3632
                //if we already created the img
3633
                $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
3634
                $myCache->saveFromCache($chartHash, $imgPath);
3635
                $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
3636
            } else {
3637
                /* Define width, height and angle */
3638
                $mainWidth = 760;
3639
                $mainHeight = 230;
3640
                $angle = 50;
3641
3642
                /* Create the pChart object */
3643
                $myPicture = new pImage($mainWidth, $mainHeight, $myData);
3644
3645
                /* Turn of Antialiasing */
3646
                $myPicture->Antialias = false;
3647
                /* Draw the background */
3648
                $settings = ["R" => 255, "G" => 255, "B" => 255];
3649
                $myPicture->drawFilledRectangle(0, 0, $mainWidth, $mainHeight, $settings);
3650
3651
                /* Add a border to the picture */
3652
                $myPicture->drawRectangle(
3653
                0,
3654
                0,
3655
                $mainWidth - 1,
3656
                $mainHeight - 1,
3657
                ["R" => 0, "G" => 0, "B" => 0]
3658
            );
3659
3660
                /* Set the default font */
3661
                $myPicture->setFontProperties(
3662
                [
3663
                    "FontName" => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
3664
                    "FontSize" => 10, ]
3665
            );
3666
                /* Write the chart title */
3667
                $myPicture->drawText(
3668
                $mainWidth / 2,
3669
                30,
3670
                get_lang('Time spent in the course'),
3671
                [
3672
                    "FontSize" => 12,
3673
                    "Align" => TEXT_ALIGN_BOTTOMMIDDLE,
3674
                ]
3675
            );
3676
3677
                /* Set the default font */
3678
                $myPicture->setFontProperties(
3679
                [
3680
                    "FontName" => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
3681
                    "FontSize" => 8,
3682
                ]
3683
            );
3684
3685
                /* Define the chart area */
3686
                $myPicture->setGraphArea(50, 40, $mainWidth - 40, $mainHeight - 80);
3687
3688
                /* Draw the scale */
3689
                $scaleSettings = [
3690
                'XMargin' => 10,
3691
                'YMargin' => 10,
3692
                'Floating' => true,
3693
                'GridR' => 200,
3694
                'GridG' => 200,
3695
                'GridB' => 200,
3696
                'DrawSubTicks' => true,
3697
                'CycleBackground' => true,
3698
                'LabelRotation' => $angle,
3699
                'Mode' => SCALE_MODE_ADDALL_START0,
3700
            ];
3701
                $myPicture->drawScale($scaleSettings);
3702
3703
                /* Turn on Antialiasing */
3704
                $myPicture->Antialias = true;
3705
3706
                /* Enable shadow computing */
3707
                $myPicture->setShadow(
3708
                true,
3709
                [
3710
                    "X" => 1,
3711
                    "Y" => 1,
3712
                    "R" => 0,
3713
                    "G" => 0,
3714
                    "B" => 0,
3715
                    "Alpha" => 10,
3716
                ]
3717
            );
3718
3719
                /* Draw the line chart */
3720
                $myPicture->setFontProperties(
3721
                [
3722
                    "FontName" => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
3723
                    "FontSize" => 10,
3724
                ]
3725
            );
3726
                $myPicture->drawSplineChart();
3727
                $myPicture->drawPlotChart(
3728
                [
3729
                    "DisplayValues" => true,
3730
                    "PlotBorder" => true,
3731
                    "BorderSize" => 1,
3732
                    "Surrounding" => -60,
3733
                    "BorderAlpha" => 80,
3734
                ]
3735
            );
3736
3737
                /* Do NOT Write the chart legend */
3738
3739
                /* Write and save into cache */
3740
                $myCache->writeToCache($chartHash, $myPicture);
3741
                $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
3742
                $myCache->saveFromCache($chartHash, $imgPath);
3743
                $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
3744
            }
3745
3746
            return '<img src="'.$imgPath.'">';
3747
        } else {
3748
            return api_convert_encoding(
3749
                '<div id="messages" class="warning-message">'.get_lang('Graphic not available').'</div>',
3750
            'UTF-8'
3751
        );
3752
        }
3753
    }
3754
3755
    /**
3756
     * Gets a list of users who were enrolled in the lessons.
3757
     * It is necessary that in the extra field, a company is defined.
3758
     *
3759
     *  if lpId is different to 0, this search by lp id too
3760
     *
3761
     * @param string|null $startDate
3762
     * @param string|null $endDate
3763
     * @param int         $lpId
3764
     * @param bool        $whitCompany
3765
     *
3766
     * @return array
3767
     */
3768
    protected static function getCompanyLearnpathSubscription(
3769
        $startDate = null,
3770
        $endDate = null,
3771
        $lpId = 0,
3772
        $whitCompany = false
3773
    ) {
3774
        $tblItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
3775
        $tblLp = Database::get_course_table(TABLE_LP_MAIN);
3776
        $tblExtraField = Database::get_main_table(TABLE_EXTRA_FIELD);
3777
        $tblExtraFieldValue = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
3778
3779
        $whereCondition = '';
3780
3781
        //Validating dates
3782
        if (!empty($startDate)) {
3783
            $startDate = new DateTime($startDate);
3784
        }
3785
        if (!empty($endDate)) {
3786
            $endDate = new DateTime($endDate);
3787
        }
3788
        if (!empty($startDate) and !empty($endDate)) {
3789
            if ($startDate > $endDate) {
3790
                $dateTemp = $endDate;
3791
                $endDate = $startDate;
3792
                $startDate = $dateTemp;
3793
                unset($dateTemp);
3794
            }
3795
        }
3796
3797
        // Settings condition and parametter GET to right date
3798
        if (!empty($startDate)) {
3799
            $startDate = api_get_utc_datetime($startDate->setTime(0, 0, 0)->format('Y-m-d H:i:s'));
3800
            $_GET['startDate'] = $startDate;
3801
            $whereCondition .= "
3802
            AND $tblItemProperty.lastedit_date >= '$startDate' ";
3803
        }
3804
        if (!empty($endDate)) {
3805
            $endDate = api_get_utc_datetime($endDate->setTime(23, 59, 59)->format('Y-m-d H:i:s'));
3806
            $_GET['endDate'] = $endDate;
3807
            $whereCondition .= "
3808
            AND $tblItemProperty.lastedit_date <= '$endDate' ";
3809
        }
3810
        if (0 != $lpId) {
3811
            $whereCondition .= "
3812
            AND c_item_property.ref = $lpId ";
3813
        }
3814
3815
        $companys = [];
3816
        if (!empty($startDate) or !empty($endDate)) {
3817
            // get Compnay data
3818
            $selectToCompany = " (
3819
            SELECT
3820
                value
3821
            FROM
3822
                $tblExtraFieldValue
3823
            WHERE
3824
                field_id IN (
3825
                    SELECT
3826
                        id
3827
                    FROM
3828
                        $tblExtraField
3829
                    WHERE
3830
                        variable = 'company'
3831
                )
3832
            AND item_id = $tblItemProperty.to_user_id
3833
            ) ";
3834
            $query = "
3835
            SELECT
3836
                * ,
3837
                 $selectToCompany  as company,
3838
                    (
3839
                    SELECT
3840
                        name
3841
                    FROM
3842
                        $tblLp
3843
                    WHERE
3844
                    $tblLp.iid = c_item_property.ref
3845
                 ) as name_lp
3846
            FROM
3847
                $tblItemProperty
3848
            WHERE
3849
                c_id IN (
3850
                    SELECT
3851
                        c_id
3852
                    FROM
3853
                        ".TABLE_MAIN_COURSE_USER."
3854
                    WHERE
3855
                        STATUS = 5
3856
                )
3857
                AND lastedit_type = 'LearnpathSubscription'
3858
3859
                ";
3860
            // -- AND $selectToCompany IS NOT NULL
3861
            if (strlen($whereCondition) > 2) {
3862
                $query .= $whereCondition;
3863
            }
3864
            $queryResult = Database::query($query);
3865
            while ($row = Database::fetch_assoc($queryResult)) {
3866
                // $courseId = (int)$row['c_id'];
3867
                $studentId = (int) $row['to_user_id'];
3868
                $company = isset($row['company']) ? $row['company'] : '';
3869
                if ('' == $company) {
3870
                    $company = get_lang('No organization');
3871
                }
3872
                // $lpId = $row['ref'];
3873
                if (0 != $lpId && 0 != $studentId) {
3874
                    if (true == $whitCompany) {
3875
                        $companys[] = [
3876
                            'id' => $studentId,
3877
                            'company' => $company,
3878
                        ];
3879
                    } else {
3880
                        $companys[] = $studentId;
3881
                    }
3882
                } else {
3883
                    $companys[$company][] = $studentId;
3884
                    $companys[$company] = array_unique($companys[$company]);
3885
                }
3886
            }
3887
        }
3888
3889
        return $companys;
3890
    }
3891
3892
    private static function getDataAccessTrackingFilters($sql)
3893
    {
3894
        if (isset($_GET['course_id']) && !empty($_GET['course_id'])) {
3895
            $courseId = (int) $_GET['course_id'];
3896
            $sql .= " AND c.id = ".$courseId;
3897
        }
3898
3899
        if (isset($_GET['session_id']) && !empty($_GET['session_id'])) {
3900
            $sessionId = (int) $_GET['session_id'];
3901
            $sql .= " AND a.session_id = ".$sessionId;
3902
        }
3903
3904
        if (isset($_GET['student_id']) && !empty($_GET['student_id'])) {
3905
            $userId = (int) $_GET['student_id'];
3906
            $sql .= " AND u.id = ".$userId;
3907
        }
3908
3909
        $sql .= " AND u.status <> ".ANONYMOUS;
3910
3911
        if (isset($_GET['date']) && !empty($_GET['date'])) {
3912
            $dateRangePicker = new DateRangePicker('date', '', ['timePicker' => 'true']);
3913
            $dates = $dateRangePicker->parseDateRange($_GET['date']);
3914
            if (isset($dates['start']) && !empty($dates['start'])) {
3915
                $dates['start'] = Database::escape_string(api_get_utc_datetime($dates['start']));
3916
                $sql .= " AND login_course_date >= '".$dates['start']."'";
3917
            }
3918
            if (isset($dates['end']) && !empty($dates['end'])) {
3919
                $dates['end'] = Database::escape_string(api_get_utc_datetime($dates['end']));
3920
                $sql .= " AND logout_course_date <= '".$dates['end']."'";
3921
            }
3922
        }
3923
3924
        return $sql;
3925
    }
3926
3927
    /**
3928
     * Render the admin reports navigation cards (common layout for tracking pages).
3929
     *
3930
     * @param string|null $activeDisplay            Report key used in ?display=... (admin_view)
3931
     * @param string|null $currentScript            Current PHP script name (e.g. "tc_report.php")
3932
     * @param bool        $includeCurrentReportNote Append the "Current report" helper text
3933
     *
3934
     * @return string
3935
     */
3936
    public static function renderAdminReportCardsSection(
3937
        ?string $activeDisplay = null,
3938
        ?string $currentScriptName = null,
3939
        bool $includeNote = false
3940
    ): string {
3941
        $actions = self::generateAdminActionLinks();
3942
        $currentReportLabel = null;
3943
3944
        // If there is no display parameter we fall back to script-based matching.
3945
        $useScriptMatching = null === $activeDisplay;
3946
3947
        if ($useScriptMatching && empty($currentScriptName)) {
3948
            $currentScriptName = basename($_SERVER['SCRIPT_NAME'] ?? '');
3949
        } else {
3950
            // Normalize in case a full path is passed.
3951
            $currentScriptName = basename((string) $currentScriptName);
3952
        }
3953
3954
        $html = '';
3955
3956
        $html .= '<section class="bg-white rounded-xl shadow-sm border border-gray-50 reporting-admin-list w-full">';
3957
        $html .= '  <div class="p-4 md:p-5 space-y-4">';
3958
        $html .= '    <h2 class="text-base md:text-lg font-semibold text-gray-800">'.get_lang('Available reports').'</h2>';
3959
        $html .= '    <div class="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">';
3960
3961
        foreach ($actions as $action) {
3962
            $url       = $action['url'];
3963
            $labelHtml = $action['content'];
3964
            $labelText = strip_tags($labelHtml);
3965
3966
            $parsedUrl   = parse_url($url);
3967
            $queryParams = [];
3968
            if (!empty($parsedUrl['query'])) {
3969
                parse_str($parsedUrl['query'], $queryParams);
3970
            }
3971
            $reportKey = $queryParams['display'] ?? null;
3972
3973
            // -------- Active state detection --------
3974
            $isActive = false;
3975
3976
            // 1) Classic admin_view.php (?display=...)
3977
            if (null !== $activeDisplay && null !== $reportKey && $reportKey === $activeDisplay) {
3978
                $isActive = true;
3979
                // 2) Fallback: match by script name (tc_report.php, bosses report, etc.)
3980
            } elseif (
3981
                $useScriptMatching &&
3982
                !empty($parsedUrl['path']) &&
3983
                !empty($currentScriptName) &&
3984
                str_contains($parsedUrl['path'], $currentScriptName)
3985
            ) {
3986
                $isActive = true;
3987
            }
3988
3989
            if ($isActive) {
3990
                $currentReportLabel = $labelText;
3991
            }
3992
3993
            // -------- Icon selection --------
3994
            $iconName = 'file-chart';
3995
            switch ($reportKey) {
3996
                case 'coaches':
3997
                    $iconName = 'account-tie';
3998
                    break;
3999
                case 'user':
4000
                    $iconName = 'account-multiple';
4001
                    break;
4002
                case 'session':
4003
                    $iconName = 'calendar-multiple';
4004
                    break;
4005
                case 'course':
4006
                    $iconName = 'book-open-page-variant';
4007
                    break;
4008
                case 'company':
4009
                    $iconName = 'office-building';
4010
                    break;
4011
                case 'learningPath':
4012
                    $iconName = 'timeline-text';
4013
                    break;
4014
                case 'learningPathByItem':
4015
                    $iconName = 'format-list-bulleted';
4016
                    break;
4017
                case 'accessoverview':
4018
                    $iconName = 'eye';
4019
                    break;
4020
                default:
4021
                    // Special icon for the general coach report without ?display=...
4022
                    if (!empty($parsedUrl['path']) && basename($parsedUrl['path']) === 'tc_report.php') {
4023
                        $iconName = 'account-group';
4024
                    } else {
4025
                        $iconName = 'file-chart';
4026
                    }
4027
            }
4028
4029
            $cardClass = 'admin-report-card block rounded-xl border border-gray-50 bg-gray-20 '.
4030
                'hover:bg-white hover:border-sky-400 shadow-sm hover:shadow-md transition';
4031
            if ($isActive) {
4032
                $cardClass .= ' admin-report-card-active';
4033
            }
4034
4035
            $html .= '      <a href="'.$url.'" class="'.$cardClass.'">';
4036
            $html .= '        <div class="flex items-center gap-3 p-3 md:p-4">';
4037
            $html .= '          <div class="flex-shrink-0">';
4038
            $html .=                Display::getMdiIcon(
4039
                $iconName,
4040
                'ch-tool-icon',
4041
                null,
4042
                32,
4043
                $labelText
4044
            );
4045
            $html .= '          </div>';
4046
            $html .= '          <div class="text-sm md:text-base text-gray-800">';
4047
            $html .=                $labelHtml;
4048
            $html .= '          </div>';
4049
            $html .= '        </div>';
4050
            $html .= '      </a>';
4051
        }
4052
4053
        $html .= '    </div>';
4054
        $html .= '  </div>';
4055
        $html .= '</section>';
4056
4057
        if ($includeNote && !empty($currentReportLabel)) {
4058
            $html .= '<div class="mt-2">';
4059
            $html .= '  <p class="text-sm text-gray-600">'.
4060
                get_lang('Current report').': <span class="font-semibold text-gray-900">'.
4061
                $currentReportLabel.
4062
                '</span></p>';
4063
            $html .= '</div>';
4064
        }
4065
4066
        return $html;
4067
    }
4068
}
4069