Passed
Pull Request — master (#7150)
by
unknown
08:54
created

MySpace::sort_users()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
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
1457
        // 👉 Nada de Template ni Twig aquí.
1458
        echo '<div class="summary-legend">';
1459
        echo $table->return_table();
1460
        echo '</div>';
1461
    }
1462
1463
    /**
1464
     * Get the total number of courses.
1465
     *
1466
     * @return int Total number of courses
1467
     */
1468
    public static function get_total_number_courses()
1469
    {
1470
        return CourseManager::count_courses(api_get_current_access_url_id());
1471
    }
1472
1473
    /**
1474
     * Get data for the courses.
1475
     *
1476
     * @param int    $from        Inferior limit
1477
     * @param int    $numberItems Number of items to select
1478
     * @param string $column      Column to order on
1479
     * @param string $direction   Order direction
1480
     *
1481
     * @return array Results
1482
     */
1483
    public static function get_course_data_tracking_overview(
1484
        $from,
1485
        $numberItems,
1486
        $column,
1487
        $direction
1488
    ) {
1489
        switch ($column) {
1490
            default:
1491
            case 1:
1492
                $column = 'title';
1493
                break;
1494
        }
1495
        $courses = CourseManager::get_courses_list(
1496
            $from,
1497
            $numberItems,
1498
            $column,
1499
            $direction,
1500
             -1,
1501
            '',
1502
            api_get_current_access_url_id()
1503
        );
1504
1505
        $list = [];
1506
        foreach ($courses as $course) {
1507
            $list[] = [
1508
                '0' => $course['real_id'],
1509
                'col0' => $course['real_id'],
1510
            ];
1511
        }
1512
1513
        return $list;
1514
    }
1515
1516
    /**
1517
     * Fills in course reporting data.
1518
     *
1519
     * @param int course code
1520
     * @param array $url_params additional url parameters
1521
     * @param array $row        the row information (the other columns)
1522
     *
1523
     * @return string html code
1524
     */
1525
    public static function course_tracking_filter($courseCode, $urlParams, $row)
1526
    {
1527
        // 1) Obtener la entidad de curso a partir del code que pasa la tabla
1528
        $course = api_get_course_entity($courseCode);
1529
1530
        if (null === $course) {
1531
            return '';
1532
        }
1533
1534
        $courseId = (int) $course->getId();
1535
1536
        $tpl = new Template('', false, false, false, false, false, false);
1537
1538
        $timeSpent              = 0;
1539
        $progressSum            = 0;
1540
        $progressCount          = 0;
1541
        $scoreSum               = 0;
1542
        $scoreCount             = 0;
1543
        $messagesCount          = 0;
1544
        $assignmentsCount       = 0;
1545
        $lastLoginRaw           = null;
1546
        $totalScoreObtained     = 0;
1547
        $totalScorePossible     = 0;
1548
        $totalQuestionsAnswered = 0;
1549
1550
        $courseRelUsers = $course->getUsers();
1551
1552
        foreach ($courseRelUsers as $courseRelUser) {
1553
            $user   = $courseRelUser->getUser();
1554
            $userId = (int) $user->getId();
1555
1556
            // 1) Tiempo en el curso
1557
            $timeSpent += Tracking::get_time_spent_on_the_course(
1558
                $userId,
1559
                $courseId
1560
            );
1561
1562
            // 2) Progreso promedio
1563
            $progressTmp = Tracking::get_avg_student_progress(
1564
                $userId,
1565
                $course,
1566
                [],
1567
                null,
1568
                true
1569
            );
1570
1571
            if (!empty($progressTmp)) {
1572
                $progressSum   += $progressTmp[0];
1573
                $progressCount += $progressTmp[1];
1574
            }
1575
1576
            // 3) Nota promedio
1577
            $scoreTmp = Tracking::get_avg_student_score(
1578
                $userId,
1579
                $course,
1580
                [],
1581
                null,
1582
                true
1583
            );
1584
1585
            if (is_array($scoreTmp) && !empty($scoreTmp)) {
1586
                $scoreSum   += $scoreTmp[0];
1587
                $scoreCount += $scoreTmp[1];
1588
            }
1589
1590
            // 4) Último acceso
1591
            $lastLoginTmp = Tracking::get_last_connection_date_on_the_course(
1592
                $userId,
1593
                ['real_id' => $courseId],
1594
                null,
1595
                false
1596
            );
1597
1598
            if (!empty($lastLoginTmp)) {
1599
                if (null === $lastLoginRaw ||
1600
                    strtotime((string) $lastLoginTmp) > strtotime((string) $lastLoginRaw)
1601
                ) {
1602
                    $lastLoginRaw = $lastLoginTmp;
1603
                }
1604
            }
1605
1606
            // 5) Resultados de ejercicios
1607
            $exerciseResults = self::exercises_results($userId, $courseCode);
1608
1609
            $totalScoreObtained     += $exerciseResults['score_obtained'] ?? 0;
1610
            $totalScorePossible     += $exerciseResults['score_possible'] ?? 0;
1611
            $totalQuestionsAnswered += $exerciseResults['questions_answered'] ?? 0;
1612
1613
            // 6) Si luego quieres contar mensajes / assignments, descomentas y adaptas:
1614
            // $messagesCount    += Container::getForumPostRepository()->countByUserAndCourse($user, $course);
1615
            // $assignmentsCount += Container::getStudentPublicationRepository()->countByUserAndCourse($user, $course);
1616
        }
1617
1618
        // --- Agregados finales ---
1619
1620
        $avgProgress = $progressCount > 0
1621
            ? round($progressSum / $progressCount, 2)
1622
            : 0;
1623
1624
        $avgScore = $scoreCount > 0
1625
            ? round($scoreSum / $scoreCount, 2)
1626
            : '-';
1627
1628
        if (!empty($lastLoginRaw)) {
1629
            $lastLogin = api_convert_and_format_date(
1630
                $lastLoginRaw,
1631
                DATE_FORMAT_SHORT,
1632
                date_default_timezone_get()
1633
            );
1634
        } else {
1635
            $lastLogin = '-';
1636
        }
1637
1638
        if ($totalScorePossible > 0) {
1639
            $totalScorePercentage = round(
1640
                ($totalScoreObtained / $totalScorePossible) * 100,
1641
                2
1642
            );
1643
1644
            $totalScore = sprintf(
1645
                '%d/%d (%s %%)',
1646
                $totalScoreObtained,
1647
                $totalScorePossible,
1648
                $totalScorePercentage
1649
            );
1650
        } else {
1651
            $totalScore = '-';
1652
        }
1653
1654
        $data = [
1655
            'time_spent'         => api_time_to_hms($timeSpent),
1656
            'avg_progress'       => $avgProgress,
1657
            'avg_score'          => $avgScore,
1658
            'number_message'     => $messagesCount,
1659
            'number_assignments' => $assignmentsCount,
1660
            'total_score'        => $totalScore,
1661
            'questions_answered' => $totalQuestionsAnswered,
1662
            'last_login'         => $lastLogin,
1663
        ];
1664
1665
        $tpl->assign('data', $data);
1666
        $tpl->assign('course', $course);
1667
1668
        $layout = $tpl->get_template('my_space/partials/tracking_course_overview.html.twig');
1669
1670
        return $tpl->fetch($layout);
1671
    }
1672
1673
1674
    /**
1675
     * This function exports the table that we see in display_tracking_course_overview().
1676
     */
1677
    public static function export_tracking_course_overview()
1678
    {
1679
        // database table definition
1680
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1681
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1682
1683
        // the values of the sortable table
1684
        if ($_GET['tracking_course_overview_page_nr']) {
1685
            $from = $_GET['tracking_course_overview_page_nr'];
1686
        } else {
1687
            $from = 0;
1688
        }
1689
        if ($_GET['tracking_course_overview_column']) {
1690
            $orderby = $_GET['tracking_course_overview_column'];
1691
        } else {
1692
            $orderby = 0;
1693
        }
1694
1695
        if ($_GET['tracking_course_overview_direction']) {
1696
            $direction = $_GET['tracking_course_overview_direction'];
1697
        } else {
1698
            $direction = 'ASC';
1699
        }
1700
1701
        $course_data = self::get_course_data_tracking_overview(
1702
            $from,
1703
            1000,
1704
            $orderby,
1705
            $direction
1706
        );
1707
1708
        $csv_content = [];
1709
1710
        // the first line of the csv file with the column headers
1711
        $csv_row = [];
1712
        $csv_row[] = get_lang('Course');
1713
        $csv_row[] = get_lang('Time');
1714
        $csv_row[] = get_lang('Progress');
1715
        $csv_row[] = get_lang('Average score in learning paths');
1716
        $csv_row[] = get_lang('Total number of messages');
1717
        $csv_row[] = get_lang('Total number of assignments');
1718
        $csv_row[] = get_lang('Total score obtained for tests');
1719
        $csv_row[] = get_lang('Total possible score for tests');
1720
        $csv_row[] = get_lang('Number of tests answered');
1721
        $csv_row[] = get_lang('Total score percentage for tests');
1722
        $csv_row[] = get_lang('Latest login');
1723
        $csv_content[] = $csv_row;
1724
1725
        // the other lines (the data)
1726
        foreach ($course_data as $key => $course) {
1727
            $courseId = $course[0];
1728
            $course = api_get_course_entity($courseId);
1729
            $courseCode = $course->getCode();
1730
            $course_title = $course->getTitle();
1731
1732
            $csv_row = [];
1733
            $csv_row[] = $course_title;
1734
1735
            $time_spent = 0;
1736
            $progress = 0;
1737
            $nb_progress_lp = 0;
1738
            $score = 0;
1739
            $nb_score_lp = 0;
1740
            $nb_messages = 0;
1741
            $nb_assignments = 0;
1742
            $last_login_date = false;
1743
            $total_score_obtained = 0;
1744
            $total_score_possible = 0;
1745
            $total_questions_answered = 0;
1746
1747
            $courseRelUsers = $course->getUsers();
1748
            foreach ($courseRelUsers as $courseRelUser) {
1749
                $user = $courseRelUser->getUser();
1750
                $userId = $user->getId();
1751
1752
                // get time spent in the course and session
1753
                $time_spent += Tracking::get_time_spent_on_the_course(
1754
                    $userId,
1755
                    $courseId
1756
                );
1757
                $progress_tmp = Tracking::get_avg_student_progress(
1758
                    $userId,
1759
                    $course,
1760
                    [],
1761
                    null,
1762
                    true
1763
                );
1764
                $progress += $progress_tmp[0];
1765
                $nb_progress_lp += $progress_tmp[1];
1766
                $score_tmp = Tracking::get_avg_student_score(
1767
                    $userId,
1768
                    $course,
1769
                    [],
1770
                    null,
1771
                    true
1772
                );
1773
                if (is_array($score_tmp)) {
1774
                    $score += $score_tmp[0];
1775
                    $nb_score_lp += $score_tmp[1];
1776
                }
1777
                $nb_messages += Container::getForumPostRepository()->countUserForumPosts($user, $course);
1778
                $nb_assignments += Container::getStudentPublicationRepository()->countUserPublications($user, $course);
1779
1780
                $last_login_date_tmp = Tracking::get_last_connection_date_on_the_course(
1781
                    $userId,
1782
                    ['real_id' => $courseId],
1783
                    null,
1784
                    false
1785
                );
1786
1787
                if (false != $last_login_date_tmp && false == $last_login_date) {
1788
                    $last_login_date = $last_login_date_tmp;
1789
                    // TODO: Repeated previous condition. To be cleaned.
1790
                    // Find the max and assign it to first_login_date
1791
                    if (strtotime($last_login_date_tmp) > strtotime($last_login_date)) {
1792
                        $last_login_date = $last_login_date_tmp;
1793
                    }
1794
                }
1795
1796
                $exercise_results_tmp = self::exercises_results($userId, $courseCode);
1797
                $total_score_obtained += $exercise_results_tmp['score_obtained'];
1798
                $total_score_possible += $exercise_results_tmp['score_possible'];
1799
                $total_questions_answered += $exercise_results_tmp['questions_answered'];
1800
            }
1801
            if ($nb_progress_lp > 0) {
1802
                $avg_progress = round($progress / $nb_progress_lp, 2);
1803
            } else {
1804
                $avg_progress = 0;
1805
            }
1806
            if ($nb_score_lp > 0) {
1807
                $avg_score = round($score / $nb_score_lp, 2);
1808
            } else {
1809
                $avg_score = '-';
1810
            }
1811
            if ($last_login_date) {
1812
                $last_login_date = api_convert_and_format_date(
1813
                    $last_login_date,
1814
                    DATE_FORMAT_SHORT,
1815
                    date_default_timezone_get()
1816
                );
1817
            } else {
1818
                $last_login_date = '-';
1819
            }
1820
            if ($total_score_possible > 0) {
1821
                $total_score_percentage = round($total_score_obtained / $total_score_possible * 100, 2);
1822
            } else {
1823
                $total_score_percentage = 0;
1824
            }
1825
            // time spent in the course
1826
            $csv_row[] = api_time_to_hms($time_spent);
1827
            // student progress in course
1828
            $csv_row[] = $avg_progress;
1829
            // student score
1830
            $csv_row[] = $avg_score;
1831
            // student messages
1832
            $csv_row[] = $nb_messages;
1833
            // student assignments
1834
            $csv_row[] = $nb_assignments;
1835
            // student exercises results (obtained score, maximum score, number of exercises answered, score percentage)
1836
            $csv_row[] = $total_score_obtained;
1837
            $csv_row[] = $total_score_possible;
1838
            $csv_row[] = $total_questions_answered;
1839
            $csv_row[] = $total_score_percentage;
1840
            // last connection
1841
            $csv_row[] = $last_login_date;
1842
            $csv_content[] = $csv_row;
1843
        }
1844
        Export::arrayToCsv($csv_content, 'reporting_course_overview');
1845
        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...
1846
    }
1847
1848
    /**
1849
     * Display a sortable table that contains an overview of all the reporting
1850
     * progress of all sessions and all courses the user is subscribed to.
1851
     *
1852
     * @author Guillaume Viguier <[email protected]>
1853
     */
1854
    public static function display_tracking_session_overview()
1855
    {
1856
        // Build header for the "metrics" column (course + stats).
1857
        // We keep the inner table because session_tracking_filter expects it,
1858
        // but we use a specific class to style it cleanly with CSS.
1859
        $head  = '<table class="session-metrics-header" '
1860
            .'style="width:100%;border:0;padding:0;border-collapse:collapse;">';
1861
        $head .= '<tr>';
1862
        // Course (left aligned).
1863
        $head .= '<th style="border-left:0;border-bottom:0;">'
1864
            .'<span>'.get_lang('Course').'</span></th>';
1865
        // Time spent.
1866
        $head .= '<th style="padding:0;border-bottom:0;">'
1867
            .'<span>'.get_lang('Time').'</span></th>';
1868
        // Progress.
1869
        $head .= '<th style="padding:0;border-bottom:0;">'
1870
            .'<span>'.get_lang('Progress').'</span></th>';
1871
        // Average score in learning paths.
1872
        $head .= '<th style="padding:0;border-bottom:0;">'
1873
            .'<span>'.get_lang('Average score in learning paths').'</span></th>';
1874
        // Total number of messages.
1875
        $head .= '<th style="padding:0;border-bottom:0;">'
1876
            .'<span>'.get_lang('Total number of messages').'</span></th>';
1877
        // Total number of assignments.
1878
        $head .= '<th style="padding:0;border-bottom:0;">'
1879
            .'<span>'.get_lang('Total number of assignments').'</span></th>';
1880
        // Total score obtained for tests.
1881
        $head .= '<th style="padding:0;border-bottom:0;">'
1882
            .'<span>'.get_lang('Total score obtained for tests').'</span></th>';
1883
        // Number of tests answered.
1884
        $head .= '<th style="padding:0;border-bottom:0;">'
1885
            .'<span>'.get_lang('Number of tests answered').'</span></th>';
1886
        // Latest login.
1887
        $head .= '<th style="padding:0;border-bottom:0;border-right:0;">'
1888
            .'<span>'.get_lang('Latest login').'</span></th>';
1889
        $head .= '</tr>';
1890
        $head .= '</table>';
1891
1892
        // Keep display=session so paging keeps the same view.
1893
        $params = [
1894
            'view'    => 'admin',
1895
            'display' => 'session',
1896
        ];
1897
1898
        $table = new SortableTable(
1899
            'tracking_session_overview',
1900
            ['MySpace', 'get_total_number_sessions'],
1901
            ['MySpace', 'get_session_data_tracking_overview'],
1902
            1
1903
        );
1904
        $table->additional_parameters = $params;
1905
1906
        // Hidden internal id column.
1907
        $table->set_header(
1908
            0,
1909
            '',
1910
            false,
1911
            ['style' => 'display:none'],
1912
            ['style' => 'display:none']
1913
        );
1914
1915
        // Session name column.
1916
        $table->set_header(
1917
            1,
1918
            get_lang('Session'),
1919
            true,
1920
            ['style' => 'font-size:0.875rem;font-weight:600;'],
1921
            ['style' => 'font-size:0.875rem;']
1922
        );
1923
1924
        // Metrics block column (course + stats table).
1925
        $table->set_header(
1926
            2,
1927
            $head,
1928
            false,
1929
            ['style' => 'width:90%;border:0;padding:0;'],
1930
            ['style' => 'width:90%;padding:0;']
1931
        );
1932
1933
        // Use existing filter to render metrics table per session.
1934
        $table->set_column_filter(2, ['MySpace', 'session_tracking_filter']);
1935
1936
        $table->display();
1937
    }
1938
1939
1940
    /**
1941
     * Get the total number of sessions.
1942
     *
1943
     * @return int Total number of sessions
1944
     */
1945
    public static function get_total_number_sessions()
1946
    {
1947
        return SessionManager::count_sessions(api_get_current_access_url_id());
1948
    }
1949
1950
    /**
1951
     * Get data for the sessions.
1952
     *
1953
     * @param int    $from        Inferior limit
1954
     * @param int    $numberItems Number of items to select
1955
     * @param string $column      Column to order on
1956
     * @param string $direction   Order direction
1957
     *
1958
     * @return array Results
1959
     */
1960
    public static function get_session_data_tracking_overview(
1961
        $from,
1962
        $numberItems,
1963
        $column,
1964
        $direction
1965
    ) {
1966
        $from = (int) $from;
1967
        $numberItems = (int) $numberItems;
1968
        $direction = Database::escape_string($direction);
1969
        $columnName = 'name';
1970
        if (1 === $column) {
1971
            $columnName = 'id';
1972
        }
1973
1974
        $options = [
1975
            'order' => " $columnName $direction",
1976
            'limit' => " $from,$numberItems",
1977
        ];
1978
        $sessions = SessionManager::formatSessionsAdminForGrid($options);
1979
        $list = [];
1980
        foreach ($sessions as $session) {
1981
            $list[] = [
1982
                '0' => $session['id'],
1983
                'col0' => $session['id'],
1984
                '1' => strip_tags($session['title']),
1985
                'col1' => strip_tags($session['title']),
1986
            ];
1987
        }
1988
1989
        return $list;
1990
    }
1991
1992
    /**
1993
     * Fills in session reporting data.
1994
     *
1995
     * @param int   $session_id the id of the user
1996
     * @param array $url_params additonal url parameters
1997
     * @param array $row        the row information (the other columns)
1998
     *
1999
     * @return string html code
2000
     */
2001
    public static function session_tracking_filter($session_id, $url_params, $row)
2002
    {
2003
        $sessionId = $row[0];
2004
        $session = api_get_session_entity($sessionId);
2005
        // the table header
2006
        $return = '<table
2007
            class="data_table"
2008
            style="width: 100%;border:0;padding:0;border-collapse:collapse;table-layout: fixed">';
2009
2010
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2011
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
2012
        $sessionRelCourses = $session->getCourses();
2013
        foreach ($sessionRelCourses as $sessionRelCourse) {
2014
            $course = $sessionRelCourse->getCourse();
2015
            $courseId = $course->getId();
2016
            $courseCode = $course->getCode();
2017
            $return .= '<tr>';
2018
            $return .= '<td>'.$course->getTitle().'</td>';
2019
            //$users = Container::getSessionRepository()->getUsersByCourse($session, $course, $url);
2020
2021
            // get the users in the course
2022
            $sql = "SELECT u.id as user_id
2023
                    FROM $tbl_user AS u
2024
                    INNER JOIN $tbl_session_rel_course_rel_user AS scu
2025
                    ON u.id = scu.user_id
2026
                    WHERE u.active <> ".USER_SOFT_DELETED." AND scu.session_id = '".$session_id."' AND scu.c_id = '".$courseId."'";
2027
            $result_users = Database::query($sql);
2028
            $time_spent = 0;
2029
            $progress = 0;
2030
            $nb_progress_lp = 0;
2031
            $score = 0;
2032
            $nb_score_lp = 0;
2033
            $nb_messages = 0;
2034
            $nb_assignments = 0;
2035
            $last_login_date = false;
2036
            $total_score_obtained = 0;
2037
            $total_score_possible = 0;
2038
            $total_questions_answered = 0;
2039
            while ($row_user = Database::fetch_object($result_users)) {
2040
                $user = api_get_user_entity($row_user->user_id);
2041
                // get time spent in the course and session
2042
                $time_spent += Tracking::get_time_spent_on_the_course($row_user->user_id, $courseId, $session_id);
2043
                $progress_tmp = Tracking::get_avg_student_progress(
2044
                    $row_user->user_id,
2045
                    $course,
2046
                    [],
2047
                    $session_id,
2048
                    true
2049
                );
2050
                $progress += $progress_tmp[0];
2051
                $nb_progress_lp += $progress_tmp[1];
2052
                $score_tmp = Tracking::get_avg_student_score($row_user->user_id, $course, [], $session_id, true);
2053
                if (is_array($score_tmp)) {
2054
                    $score += $score_tmp[0];
2055
                    $nb_score_lp += $score_tmp[1];
2056
                }
2057
                $nb_messages += Container::getForumPostRepository()->countUserForumPosts($user, $course, $session);
2058
                $nb_assignments += Container::getStudentPublicationRepository()->countUserPublications(
2059
                    $user,
2060
                    $course,
2061
                    $session
2062
                );
2063
                $last_login_date_tmp = Tracking::get_last_connection_date_on_the_course(
2064
                    $row_user->user_id,
2065
                    ['real_id' => $courseId],
2066
                    $session_id,
2067
                    false
2068
                );
2069
                if (false != $last_login_date_tmp && false == $last_login_date) {
2070
                    // TODO: To be cleaned.
2071
                    $last_login_date = $last_login_date_tmp;
2072
                } elseif (false != $last_login_date_tmp && false != $last_login_date) {
2073
                    // TODO: Repeated previous condition! To be cleaned.
2074
                    // Find the max and assign it to first_login_date
2075
                    if (strtotime($last_login_date_tmp) > strtotime($last_login_date)) {
2076
                        $last_login_date = $last_login_date_tmp;
2077
                    }
2078
                }
2079
2080
                $exercise_results_tmp = self::exercises_results($row_user->user_id, $courseCode, $session_id);
2081
                $total_score_obtained += $exercise_results_tmp['score_obtained'];
2082
                $total_score_possible += $exercise_results_tmp['score_possible'];
2083
                $total_questions_answered += $exercise_results_tmp['questions_answered'];
2084
            }
2085
            if ($nb_progress_lp > 0) {
2086
                $avg_progress = round($progress / $nb_progress_lp, 2);
2087
            } else {
2088
                $avg_progress = 0;
2089
            }
2090
            if ($nb_score_lp > 0) {
2091
                $avg_score = round($score / $nb_score_lp, 2);
2092
            } else {
2093
                $avg_score = '-';
2094
            }
2095
            if ($last_login_date) {
2096
                $last_login_date = api_convert_and_format_date(
2097
                    $last_login_date,
2098
                    DATE_FORMAT_SHORT,
2099
                    date_default_timezone_get()
2100
                );
2101
            } else {
2102
                $last_login_date = '-';
2103
            }
2104
            if ($total_score_possible > 0) {
2105
                $total_score_percentage = round($total_score_obtained / $total_score_possible * 100, 2);
2106
            } else {
2107
                $total_score_percentage = 0;
2108
            }
2109
            if ($total_score_percentage > 0) {
2110
                $total_score = $total_score_obtained.'/'.$total_score_possible.' ('.$total_score_percentage.' %)';
2111
            } else {
2112
                $total_score = '-';
2113
            }
2114
            // time spent in the course
2115
            $return .= '    <td><div>'.api_time_to_hms($time_spent).'</div></td>';
2116
            // student progress in course
2117
            $return .= '    <td><div>'.$avg_progress.'</div></td>';
2118
            // student score
2119
            $return .= '    <td><div>'.$avg_score.'</div></td>';
2120
            // student messages
2121
            $return .= '    <td><div>'.$nb_messages.'</div></td>';
2122
            // student assignments
2123
            $return .= '    <td><div>'.$nb_assignments.'</div></td>';
2124
            // student exercises results (obtained score, maximum score, number of exercises answered, score percentage)
2125
            $return .= '<td width="105px;">'.$total_score.'</td>';
2126
            $return .= '<td>'.$total_questions_answered.'</td>';
2127
            // last connection
2128
            $return .= '    <td><div>'.$last_login_date.'</div></td>';
2129
            $return .= '<tr>';
2130
        }
2131
        $return .= '</table>';
2132
2133
        return $return;
2134
    }
2135
2136
    /**
2137
     * This function exports the table that we see in display_tracking_session_overview().
2138
     */
2139
    public static function export_tracking_session_overview()
2140
    {
2141
        // database table definition
2142
        $tbl_session_rel_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
2143
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2144
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2145
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
2146
2147
        // the values of the sortable table
2148
        $from = 0;
2149
        if ($_GET['tracking_session_overview_page_nr']) {
2150
            $from = $_GET['tracking_session_overview_page_nr'];
2151
        }
2152
2153
        $orderby = 0;
2154
        if ($_GET['tracking_session_overview_column']) {
2155
            $orderby = $_GET['tracking_session_overview_column'];
2156
        }
2157
2158
        $direction = 'ASC';
2159
        if ($_GET['tracking_session_overview_direction']) {
2160
            $direction = $_GET['tracking_session_overview_direction'];
2161
        }
2162
2163
        $session_data = self::get_session_data_tracking_overview($from, 1000, $orderby, $direction);
2164
2165
        $csv_content = [];
2166
2167
        // the first line of the csv file with the column headers
2168
        $csv_row = [];
2169
        $csv_row[] = get_lang('Session');
2170
        $csv_row[] = get_lang('Course');
2171
        $csv_row[] = get_lang('Time');
2172
        $csv_row[] = get_lang('Progress');
2173
        $csv_row[] = get_lang('Average score in learning paths');
2174
        $csv_row[] = get_lang('Total number of messages');
2175
        $csv_row[] = get_lang('Total number of assignments');
2176
        $csv_row[] = get_lang('Total score obtained for tests');
2177
        $csv_row[] = get_lang('Total possible score for tests');
2178
        $csv_row[] = get_lang('Number of tests answered');
2179
        $csv_row[] = get_lang('Total score percentage for tests');
2180
        $csv_row[] = get_lang('Latest login');
2181
        $csv_content[] = $csv_row;
2182
2183
        // the other lines (the data)
2184
        foreach ($session_data as $session) {
2185
            $session_id = $session[0];
2186
            $session_title = $session[1];
2187
2188
            // getting all the courses of the session
2189
            $sql = "SELECT * FROM $tbl_course AS c
2190
                    INNER JOIN $tbl_session_rel_course AS sc
2191
                    ON sc.c_id = c.id
2192
                    WHERE sc.session_id = '".$session_id."';";
2193
            $result = Database::query($sql);
2194
            while ($row = Database::fetch_object($result)) {
2195
                $courseId = $row->c_id;
2196
                $courseInfo = ['real_id' => $courseId];
2197
                $course = api_get_course_entity($courseId);
2198
                $csv_row = [];
2199
                $csv_row[] = $session_title;
2200
                $csv_row[] = $row->title;
2201
                // get the users in the course
2202
                $sql = "SELECT scu.user_id
2203
                        FROM $tbl_user AS u
2204
                        INNER JOIN $tbl_session_rel_course_rel_user AS scu
2205
                        ON u.id = scu.user_id
2206
                        WHERE u.active <> ".USER_SOFT_DELETED." AND scu.session_id = '".$session_id."' AND scu.c_id = '".$courseId."'";
2207
                $result_users = Database::query($sql);
2208
                $time_spent = 0;
2209
                $progress = 0;
2210
                $nb_progress_lp = 0;
2211
                $score = 0;
2212
                $nb_score_lp = 0;
2213
                $nb_messages = 0;
2214
                $nb_assignments = 0;
2215
                $last_login_date = false;
2216
                $total_score_obtained = 0;
2217
                $total_score_possible = 0;
2218
                $total_questions_answered = 0;
2219
                while ($row_user = Database::fetch_object($result_users)) {
2220
                    // get time spent in the course and session
2221
                    $time_spent += Tracking::get_time_spent_on_the_course($row_user->user_id, $courseId, $session_id);
2222
                    $progress_tmp = Tracking::get_avg_student_progress(
2223
                        $row_user->user_id,
2224
                        $row->code,
2225
                        [],
2226
                        $session_id,
2227
                        true
2228
                    );
2229
                    $progress += $progress_tmp[0];
2230
                    $nb_progress_lp += $progress_tmp[1];
2231
                    $score_tmp = Tracking::get_avg_student_score(
2232
                        $row_user->user_id,
2233
                        $course,
2234
                        [],
2235
                        $session_id,
2236
                        true
2237
                    );
2238
                    if (is_array($score_tmp)) {
2239
                        $score += $score_tmp[0];
2240
                        $nb_score_lp += $score_tmp[1];
2241
                    }
2242
                    $nb_messages += Tracking::count_student_messages(
2243
                        $row_user->user_id,
2244
                        $row->code,
2245
                        $session_id
2246
                    );
2247
2248
                    $nb_assignments += Tracking::count_student_assignments(
2249
                        $row_user->user_id,
2250
                        $row->code,
2251
                        $session_id
2252
                    );
2253
2254
                    $last_login_date_tmp = Tracking:: get_last_connection_date_on_the_course(
2255
                        $row_user->user_id,
2256
                        $courseInfo,
2257
                        $session_id,
2258
                        false
2259
                    );
2260
                    if (false != $last_login_date_tmp && false == $last_login_date) {
2261
                        // TODO: To be cleaned.
2262
                        $last_login_date = $last_login_date_tmp;
2263
                    } elseif (false != $last_login_date_tmp && false == $last_login_date) {
2264
                        // TODO: Repeated previous condition. To be cleaned.
2265
                        // Find the max and assign it to first_login_date
2266
                        if (strtotime($last_login_date_tmp) > strtotime($last_login_date)) {
2267
                            $last_login_date = $last_login_date_tmp;
2268
                        }
2269
                    }
2270
2271
                    $exercise_results_tmp = self::exercises_results($row_user->user_id, $row->code, $session_id);
2272
                    $total_score_obtained += $exercise_results_tmp['score_obtained'];
2273
                    $total_score_possible += $exercise_results_tmp['score_possible'];
2274
                    $total_questions_answered += $exercise_results_tmp['questions_answered'];
2275
                }
2276
                if ($nb_progress_lp > 0) {
2277
                    $avg_progress = round($progress / $nb_progress_lp, 2);
2278
                } else {
2279
                    $avg_progress = 0;
2280
                }
2281
                if ($nb_score_lp > 0) {
2282
                    $avg_score = round($score / $nb_score_lp, 2);
2283
                } else {
2284
                    $avg_score = '-';
2285
                }
2286
                if ($last_login_date) {
2287
                    $last_login_date = api_convert_and_format_date(
2288
                        $last_login_date,
2289
                        DATE_FORMAT_SHORT,
2290
                        date_default_timezone_get()
2291
                    );
2292
                } else {
2293
                    $last_login_date = '-';
2294
                }
2295
                if ($total_score_possible > 0) {
2296
                    $total_score_percentage = round($total_score_obtained / $total_score_possible * 100, 2);
2297
                } else {
2298
                    $total_score_percentage = 0;
2299
                }
2300
                if ($total_score_percentage > 0) {
2301
                    $total_score = $total_score_obtained.'/'.$total_score_possible.' ('.$total_score_percentage.' %)';
2302
                } else {
2303
                    $total_score = '-';
2304
                }
2305
                // time spent in the course
2306
                $csv_row[] = api_time_to_hms($time_spent);
2307
                // student progress in course
2308
                $csv_row[] = $avg_progress;
2309
                // student score
2310
                $csv_row[] = $avg_score;
2311
                // student messages
2312
                $csv_row[] = $nb_messages;
2313
                // student assignments
2314
                $csv_row[] = $nb_assignments;
2315
                // student exercises results (obtained score, maximum score, number of exercises answered, score percentage)
2316
                $csv_row[] = $total_score_obtained;
2317
                $csv_row[] = $total_score_possible;
2318
                $csv_row[] = $total_questions_answered;
2319
                $csv_row[] = $total_score_percentage;
2320
                // last connection
2321
                $csv_row[] = $last_login_date;
2322
                $csv_content[] = $csv_row;
2323
            }
2324
        }
2325
        Export::arrayToCsv($csv_content, 'reporting_session_overview');
2326
        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...
2327
    }
2328
2329
    /**
2330
     * Get general information about the exercise performance of the user
2331
     * the total obtained score (all the score on all the questions)
2332
     * the maximum score that could be obtained
2333
     * the number of questions answered
2334
     * the success percentage.
2335
     *
2336
     * @param int    $user_id     the id of the user
2337
     * @param string $course_code the course code
2338
     * @param int    $session_id
2339
     *
2340
     * @return array
2341
     *
2342
     * @author Patrick Cool <[email protected]>, Ghent University, Belgium
2343
     *
2344
     * @version Dokeos 1.8.6
2345
     *
2346
     * @since November 2008
2347
     */
2348
    public static function exercises_results($user_id, $course_code, $session_id = 0)
2349
    {
2350
        $user_id = (int) $user_id;
2351
        $courseId = api_get_course_int_id($course_code);
2352
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2353
        $sessionCondition = api_get_session_condition($session_id);
2354
        $sql = "SELECT score, max_score
2355
                FROM $table
2356
                WHERE
2357
                    c_id = $courseId AND
2358
                    exe_user_id = $user_id
2359
                    $sessionCondition
2360
                    ";
2361
2362
        $result = Database::query($sql);
2363
        $score_obtained = 0;
2364
        $score_possible = 0;
2365
        $questions_answered = 0;
2366
        while ($row = Database::fetch_array($result)) {
2367
            $score_obtained += $row['score'];
2368
            $score_possible += $row['max_score'];
2369
            $questions_answered++;
2370
        }
2371
2372
        $percentage = null;
2373
        if (0 != $score_possible) {
2374
            $percentage = round(($score_obtained / $score_possible * 100), 2);
2375
        }
2376
2377
        return [
2378
            'score_obtained' => $score_obtained,
2379
            'score_possible' => $score_possible,
2380
            'questions_answered' => $questions_answered,
2381
            'percentage' => $percentage,
2382
        ];
2383
    }
2384
2385
    /**
2386
     * This function exports the table that we see in display_tracking_user_overview().
2387
     *
2388
     * @author Patrick Cool <[email protected]>, Ghent University, Belgium
2389
     *
2390
     * @version Dokeos 1.8.6
2391
     *
2392
     * @since October 2008
2393
     */
2394
    public static function export_tracking_user_overview()
2395
    {
2396
        // database table definitions
2397
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2398
        $is_western_name_order = api_is_western_name_order(PERSON_NAME_DATA_EXPORT);
2399
2400
        // the values of the sortable table
2401
        if ($_GET['tracking_user_overview_page_nr']) {
2402
            $from = $_GET['tracking_user_overview_page_nr'];
2403
        } else {
2404
            $from = 0;
2405
        }
2406
        if ($_GET['tracking_user_overview_column']) {
2407
            $orderby = $_GET['tracking_user_overview_column'];
2408
        } else {
2409
            $orderby = 0;
2410
        }
2411
        if ($is_western_name_order != api_is_western_name_order() && (1 == $orderby || 2 == $orderby)) {
2412
            // Swapping the sorting column if name order for export is different than the common name order.
2413
            $orderby = 3 - $orderby;
2414
        }
2415
        if ($_GET['tracking_user_overview_direction']) {
2416
            $direction = $_GET['tracking_user_overview_direction'];
2417
        } else {
2418
            $direction = 'ASC';
2419
        }
2420
2421
        $user_data = self::get_user_data_tracking_overview(
2422
            $from,
2423
            1000,
2424
            $orderby,
2425
            $direction
2426
        );
2427
2428
        // the first line of the csv file with the column headers
2429
        $csv_row = [];
2430
        $csv_row[] = get_lang('Code');
2431
        if ($is_western_name_order) {
2432
            $csv_row[] = get_lang('First name');
2433
            $csv_row[] = get_lang('Last name');
2434
        } else {
2435
            $csv_row[] = get_lang('Last name');
2436
            $csv_row[] = get_lang('First name');
2437
        }
2438
        $csv_row[] = get_lang('Login');
2439
        $csv_row[] = get_lang('Code');
2440
2441
        // the additional user defined fields (only those that were selected to be exported)
2442
        $fields = UserManager::get_extra_fields(0, 50, 5, 'ASC');
2443
2444
        $additionalExportFields = Session::read('additional_export_fields');
2445
2446
        if (is_array($additionalExportFields)) {
2447
            foreach ($additionalExportFields as $key => $extra_field_export) {
2448
                $csv_row[] = $fields[$extra_field_export][3];
2449
                $field_names_to_be_exported[] = 'extra_'.$fields[$extra_field_export][1];
2450
            }
2451
        }
2452
        $csv_row[] = get_lang('Time');
2453
        $csv_row[] = get_lang('Progress');
2454
        $csv_row[] = get_lang('Average score in learning paths');
2455
        $csv_row[] = get_lang('Tests score');
2456
        $csv_row[] = get_lang('Messages per learner');
2457
        $csv_row[] = get_lang('Assignments');
2458
        $csv_row[] = get_lang('Total score obtained for tests');
2459
        $csv_row[] = get_lang('Total possible score for tests');
2460
        $csv_row[] = get_lang('Number of tests answered');
2461
        $csv_row[] = get_lang('Total score percentage for tests');
2462
        $csv_row[] = get_lang('First connection');
2463
        $csv_row[] = get_lang('Latest login');
2464
        $csv_content[] = $csv_row;
2465
2466
        // the other lines (the data)
2467
        foreach ($user_data as $user) {
2468
            // getting all the courses of the user
2469
            $sql = "SELECT * FROM $tbl_course_user
2470
                    WHERE user_id = '".intval($user[4])."' AND relation_type<>".COURSE_RELATION_TYPE_RRHH." ";
2471
            $result = Database::query($sql);
2472
            while ($row = Database::fetch_row($result)) {
2473
                $course = api_get_course_entity($row['c_id']);
2474
                $courseId = $course->getId();
2475
                $courseCode = $course->getCode();
2476
2477
                $csv_row = [];
2478
                // user official code
2479
                $csv_row[] = $user[0];
2480
                // user first|last name
2481
                $csv_row[] = $user[1];
2482
                // user last|first name
2483
                $csv_row[] = $user[2];
2484
                // user login name
2485
                $csv_row[] = $user[3];
2486
                // course code
2487
                $csv_row[] = $row[0];
2488
                // the additional defined user fields
2489
                $extra_fields = self::get_user_overview_export_extra_fields($user[4]);
2490
2491
                if (is_array($field_names_to_be_exported)) {
2492
                    foreach ($field_names_to_be_exported as $key => $extra_field_export) {
2493
                        $csv_row[] = $extra_fields[$extra_field_export];
2494
                    }
2495
                }
2496
                // time spent in the course
2497
                $csv_row[] = api_time_to_hms(Tracking::get_time_spent_on_the_course($user[4], $courseId));
2498
                // student progress in course
2499
                $csv_row[] = round(Tracking::get_avg_student_progress($user[4], $course), 2);
2500
                // student score
2501
                $csv_row[] = round(Tracking::get_avg_student_score($user[4], $course), 2);
2502
                // student tes score
2503
                $csv_row[] = round(Tracking::get_avg_student_exercise_score($user[4], $courseCode), 2);
2504
                // student messages
2505
                //$csv_row[] = Tracking::count_student_messages($user[4], $row[0]);
2506
                // student assignments
2507
                //$csv_row[] = Tracking::count_student_assignments($user[4], $row[0]);
2508
                // student exercises results
2509
                $exercises_results = self::exercises_results($user[4], $row[0]);
2510
                $csv_row[] = $exercises_results['score_obtained'];
2511
                $csv_row[] = $exercises_results['score_possible'];
2512
                $csv_row[] = $exercises_results['questions_answered'];
2513
                $csv_row[] = $exercises_results['percentage'];
2514
                // first connection
2515
                $csv_row[] = Tracking::get_first_connection_date_on_the_course($user[4], $courseId);
2516
                // last connection
2517
                $csv_row[] = strip_tags(Tracking::get_last_connection_date_on_the_course($user[4], $courseInfo));
2518
2519
                $csv_content[] = $csv_row;
2520
            }
2521
        }
2522
        Export::arrayToCsv($csv_content, 'reporting_user_overview');
2523
        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...
2524
    }
2525
2526
    /**
2527
     * Get data for courses list in sortable with pagination.
2528
     *
2529
     * @return array
2530
     */
2531
    public static function get_course_data($from, $number_of_items, $column, $direction)
2532
    {
2533
        global $courses, $csv_content, $charset, $session_id;
2534
2535
        // definition database tables
2536
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2537
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2538
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2539
2540
        $course_data = [];
2541
        $courses_code = array_keys($courses);
2542
2543
        foreach ($courses_code as &$code) {
2544
            $code = "'$code'";
2545
        }
2546
2547
        // get all courses with limit
2548
        $sql = "SELECT course.code as col1, course.title as col2
2549
                FROM $tbl_course course
2550
                WHERE course.code IN (".implode(',', $courses_code).")";
2551
2552
        if (!in_array($direction, ['ASC', 'DESC'])) {
2553
            $direction = 'ASC';
2554
        }
2555
2556
        $column = (int) $column;
2557
        $from = (int) $from;
2558
        $number_of_items = (int) $number_of_items;
2559
        $sql .= " ORDER BY col$column $direction ";
2560
        $sql .= " LIMIT $from,$number_of_items";
2561
2562
        $res = Database::query($sql);
2563
        while ($row_course = Database::fetch_row($res)) {
2564
            $course_code = $row_course[0];
2565
            $courseInfo = api_get_course_info($course_code);
2566
            $courseId = $courseInfo['real_id'];
2567
            $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;
2568
2569
            // students directly subscribed to the course
2570
            if (empty($session_id)) {
2571
                $sql = "SELECT user_id
2572
                        FROM $tbl_course_user as course_rel_user
2573
                        WHERE
2574
                            course_rel_user.status='5' AND
2575
                            course_rel_user.c_id = '$courseId'";
2576
            } else {
2577
                $sql = "SELECT user_id FROM $tbl_session_course_user srcu
2578
                        WHERE
2579
                            c_id = '$courseId' AND
2580
                            session_id = '$session_id' AND
2581
                            status = ".SessionEntity::STUDENT;
2582
            }
2583
            $rs = Database::query($sql);
2584
            $users = [];
2585
            while ($row = Database::fetch_array($rs)) {
2586
                $users[] = $row['user_id'];
2587
            }
2588
2589
            if (count($users) > 0) {
2590
                $nb_students_in_course = count($users);
2591
                $avg_assignments_in_course = Tracking::count_student_assignments($users, $course_code, $session_id);
2592
                $avg_messages_in_course = Tracking::count_student_messages($users, $course_code, $session_id);
2593
                $avg_progress_in_course = Tracking::get_avg_student_progress($users, $course_code, [], $session_id);
2594
                $avg_score_in_course = Tracking::get_avg_student_score($users, $course_code, [], $session_id);
2595
                $avg_score_in_exercise = Tracking::get_avg_student_exercise_score($users, $course_code, 0, $session_id);
2596
                $avg_time_spent_in_course = Tracking::get_time_spent_on_the_course(
2597
                    $users,
2598
                    $courseInfo['real_id'],
2599
                    $session_id
2600
                );
2601
2602
                $avg_progress_in_course = round($avg_progress_in_course / $nb_students_in_course, 2);
2603
                if (is_numeric($avg_score_in_course)) {
2604
                    $avg_score_in_course = round($avg_score_in_course / $nb_students_in_course, 2);
2605
                }
2606
                $avg_time_spent_in_course = api_time_to_hms($avg_time_spent_in_course / $nb_students_in_course);
2607
            } else {
2608
                $avg_time_spent_in_course = null;
2609
                $avg_progress_in_course = null;
2610
                $avg_score_in_course = null;
2611
                $avg_score_in_exercise = null;
2612
                $avg_messages_in_course = null;
2613
                $avg_assignments_in_course = null;
2614
            }
2615
            $table_row = [];
2616
            $table_row[] = $row_course[1];
2617
            $table_row[] = $nb_students_in_course;
2618
            $table_row[] = $avg_time_spent_in_course;
2619
            $table_row[] = is_null($avg_progress_in_course) ? '' : $avg_progress_in_course.'%';
2620
            $table_row[] = is_null($avg_score_in_course) ? '' : $avg_score_in_course.'%';
2621
            $table_row[] = is_null($avg_score_in_exercise) ? '' : $avg_score_in_exercise.'%';
2622
            $table_row[] = $avg_messages_in_course;
2623
            $table_row[] = $avg_assignments_in_course;
2624
2625
            //set the "from" value to know if I access the Reporting by the chamilo tab or the course link
2626
            $table_row[] = '<center><a href="../../tracking/courseLog.php?cidReq='.$course_code.'&from=myspace&id_session='.$session_id.'">
2627
                             '.Display::getMdiIcon('fast-forward-outline', 'ch-tool-icon', null, 22, get_lang('Details')).'
2628
                             </a>
2629
                            </center>';
2630
2631
            $scoreInCourse = null;
2632
            if (null !== $avg_score_in_course) {
2633
                if (is_numeric($avg_score_in_course)) {
2634
                    $scoreInCourse = $avg_score_in_course.'%';
2635
                } else {
2636
                    $scoreInCourse = $avg_score_in_course;
2637
                }
2638
            }
2639
2640
            $csv_content[] = [
2641
                api_html_entity_decode($row_course[1], ENT_QUOTES, $charset),
2642
                $nb_students_in_course,
2643
                $avg_time_spent_in_course,
2644
                is_null($avg_progress_in_course) ? null : $avg_progress_in_course.'%',
2645
                $scoreInCourse,
2646
                is_null($avg_score_in_exercise) ? null : $avg_score_in_exercise.'%',
2647
                $avg_messages_in_course,
2648
                $avg_assignments_in_course,
2649
            ];
2650
            $course_data[] = $table_row;
2651
        }
2652
2653
        return $course_data;
2654
    }
2655
2656
    /**
2657
     * Get the number of users of the platform.
2658
     *
2659
     * @return int
2660
     */
2661
    public static function get_number_of_users_tracking_overview()
2662
    {
2663
        return UserManager::get_number_of_users(0, api_get_current_access_url_id());
2664
    }
2665
2666
    /**
2667
     * Get all the data for the sortable table of the reporting progress of
2668
     * all users and all the courses the user is subscribed to.
2669
     *
2670
     * @param int    $from
2671
     * @param int    $numberItems
2672
     * @param int    $column
2673
     * @param string $direction
2674
     *
2675
     * @return array
2676
     */
2677
    public static function get_user_data_tracking_overview($from, $numberItems, $column, $direction)
2678
    {
2679
        $isWestern = api_is_western_name_order();
2680
2681
        switch ($column) {
2682
            case '0':
2683
                $column = $isWestern ? 'firstname' : 'lastname';
2684
                break;
2685
        }
2686
2687
        $order = [
2688
            " `$column` $direction",
2689
        ];
2690
        $userList = UserManager::get_user_list([], $order, $from, $numberItems);
2691
        $return = [];
2692
        foreach ($userList as $user) {
2693
            $return[] = [
2694
                '0' => $user['user_id'],
2695
                'col0' => $user['user_id'],
2696
            ];
2697
        }
2698
2699
        return $return;
2700
    }
2701
2702
    /**
2703
     * Get all information that the user with user_id = $user_data has
2704
     * entered in the additionally defined profile fields.
2705
     *
2706
     * @param int $user_id the id of the user
2707
     *
2708
     * @return array
2709
     *
2710
     * @author Patrick Cool <[email protected]>, Ghent University, Belgium
2711
     *
2712
     * @version Dokeos 1.8.6
2713
     *
2714
     * @since November 2008
2715
     */
2716
    public static function get_user_overview_export_extra_fields($user_id)
2717
    {
2718
        // include the user manager
2719
        $data = UserManager::get_extra_user_data($user_id, true);
2720
2721
        return $data;
2722
    }
2723
2724
    /**
2725
     * Checks if a username exist in the DB otherwise it create a "double"
2726
     * i.e. if we look into for jmontoya but the user's name already exist we create the user jmontoya2
2727
     * the return array will be array(username=>'jmontoya', sufix='2').
2728
     *
2729
     * @param string firstname
2730
     * @param string lastname
2731
     * @param string username
2732
     *
2733
     * @return array with the username, the sufix
2734
     *
2735
     * @author Julio Montoya
2736
     */
2737
    public static function make_username($firstname, $lastname, $username, $language = null, $encoding = null)
2738
    {
2739
        // if username exist
2740
        if (!Container::getUserRepository()->isUsernameAvailable($username) || empty($username)) {
2741
            $i = 0;
2742
            while (1) {
2743
                if (0 == $i) {
2744
                    $sufix = '';
2745
                } else {
2746
                    $sufix = $i;
2747
                }
2748
                $desired_username = UserManager::create_username(
2749
                    $firstname,
2750
                    $lastname
2751
                );
2752
                if (Container::getUserRepository()->isUsernameAvailable($desired_username.$sufix)) {
2753
                    break;
2754
                } else {
2755
                    $i++;
2756
                }
2757
            }
2758
            $username_array = ['username' => $desired_username, 'sufix' => $sufix];
2759
2760
            return $username_array;
2761
        } else {
2762
            $username_array = ['username' => $username, 'sufix' => ''];
2763
2764
            return $username_array;
2765
        }
2766
    }
2767
2768
    /**
2769
     * Checks if there are repeted users in a given array.
2770
     *
2771
     * @param array $usernames  list of the usernames in the uploaded file
2772
     * @param array $user_array $user_array['username'] and $user_array['sufix']
2773
     *                          where suffix is the number part in a login i.e -> jmontoya2
2774
     *
2775
     * @return array with the $usernames array and the $user_array array
2776
     *
2777
     * @author Julio Montoya
2778
     */
2779
    public static function check_user_in_array($usernames, $user_array)
2780
    {
2781
        $user_list = array_keys($usernames);
2782
        $username = $user_array['username'].$user_array['sufix'];
2783
2784
        if (in_array($username, $user_list)) {
2785
            $user_array['sufix'] += $usernames[$username];
2786
            $usernames[$username]++;
2787
        } else {
2788
            $usernames[$username] = 1;
2789
        }
2790
        $result_array = [$usernames, $user_array];
2791
2792
        return $result_array;
2793
    }
2794
2795
    /**
2796
     * Checks whether a username has been already subscribed in a session.
2797
     *
2798
     * @param string $username    a given username
2799
     * @param array  $course_list the array with the course list id
2800
     * @param int    $id_session  the session id
2801
     *
2802
     * @return int 0 if the user is not subscribed otherwise it returns the user_id of the given username
2803
     *
2804
     * @author Julio Montoya
2805
     */
2806
    public static function user_available_in_session($username, $course_list, $id_session)
2807
    {
2808
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
2809
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2810
        $id_session = (int) $id_session;
2811
        $username = Database::escape_string($username);
2812
        foreach ($course_list as $courseId) {
2813
            $courseId = (int) $courseId;
2814
            $sql = " SELECT u.id as user_id FROM $tbl_session_rel_course_rel_user rel
2815
                     INNER JOIN $table_user u
2816
                     ON (rel.user_id = u.id)
2817
                     WHERE
2818
                        rel.session_id='$id_session' AND
2819
                        u.status='5' AND
2820
                        u.username ='$username' AND
2821
                        rel.c_id='$courseId'";
2822
            $rs = Database::query($sql);
2823
            if (Database::num_rows($rs) > 0) {
2824
                return Database::result($rs, 0, 0);
2825
            }
2826
        }
2827
2828
        return 0;
2829
    }
2830
2831
    /**
2832
     * This function checks whether some users in the uploaded file
2833
     * repeated and creates unique usernames if necesary.
2834
     * A case: Within the file there is an user repeted twice (Julio Montoya / Julio Montoya)
2835
     * and the username fields are empty.
2836
     * Then, this function would create unique usernames based on the first and the last name.
2837
     * Two users wiould be created - jmontoya and jmontoya2.
2838
     * Of course, if in the database there is a user with the name jmontoya,
2839
     * the newly created two users registered would be jmontoya2 and jmontoya3.
2840
     *
2841
     * @param $users list of users
2842
     *
2843
     * @return array
2844
     *
2845
     * @author Julio Montoya Armas
2846
     */
2847
    public static function check_all_usernames($users, $course_list, $id_session)
2848
    {
2849
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
2850
        $usernames = [];
2851
        $new_users = [];
2852
        foreach ($users as $index => $user) {
2853
            $desired_username = [];
2854
            if (empty($user['UserName'])) {
2855
                $desired_username = self::make_username($user['FirstName'], $user['LastName'], '');
2856
                $pre_username = $desired_username['username'].$desired_username['sufix'];
2857
                $user['UserName'] = $pre_username;
2858
                $user['create'] = '1';
2859
            } else {
2860
                if (Container::getUserRepository()->isUsernameAvailable($user['UserName'])) {
2861
                    $desired_username = self::make_username($user['FirstName'], $user['LastName'], $user['UserName']);
2862
                    $user['UserName'] = $desired_username['username'].$desired_username['sufix'];
2863
                    $user['create'] = '1';
2864
                } else {
2865
                    $is_session_avail = self::user_available_in_session($user['UserName'], $course_list, $id_session);
2866
                    if (0 == $is_session_avail) {
2867
                        $user_name = $user['UserName'];
2868
                        $sql_select = "SELECT user_id FROM $table_user WHERE username ='$user_name' ";
2869
                        $rs = Database::query($sql_select);
2870
                        $user['create'] = Database::result($rs, 0, 0);
2871
                    } else {
2872
                        $user['create'] = $is_session_avail;
2873
                    }
2874
                }
2875
            }
2876
            // Usernames is the current list of users in the file.
2877
            $result_array = self::check_user_in_array($usernames, $desired_username);
2878
            $usernames = $result_array[0];
2879
            $desired_username = $result_array[1];
2880
            $user['UserName'] = $desired_username['username'].$desired_username['sufix'];
2881
            $new_users[] = $user;
2882
        }
2883
2884
        return $new_users;
2885
    }
2886
2887
    /**
2888
     * This functions checks whether there are users that are already
2889
     * registered in the DB by different creator than the current coach.
2890
     *
2891
     * @param array $users
2892
     *
2893
     * @return array
2894
     *
2895
     * @author Julio Montoya Armas
2896
     */
2897
    public static function get_user_creator($users)
2898
    {
2899
        $errors = [];
2900
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
2901
        foreach ($users as $index => $user) {
2902
            $username = Database::escape_string($user['UserName']);
2903
            $sql = "SELECT creator_id FROM $table_user WHERE username='$username' ";
2904
2905
            $rs = Database::query($sql);
2906
            $creator_id = Database::result($rs, 0, 0);
2907
            // check if we are the creators or not
2908
            if ('' != $creator_id) {
2909
                if ($creator_id != api_get_user_id()) {
2910
                    $user['error'] = get_lang('User already register by other coach.');
2911
                    $errors[] = $user;
2912
                }
2913
            }
2914
        }
2915
2916
        return $errors;
2917
    }
2918
2919
    /**
2920
     * Validates imported data.
2921
     *
2922
     * @param array $users list of users
2923
     */
2924
    public static function validate_data($users, $id_session = null)
2925
    {
2926
        $errors = [];
2927
        $new_users = [];
2928
        foreach ($users as $index => $user) {
2929
            // 1. Check whether mandatory fields are set.
2930
            $mandatory_fields = ['LastName', 'FirstName'];
2931
            if ('true' == api_get_setting('registration', 'email')) {
2932
                $mandatory_fields[] = 'Email';
2933
            }
2934
2935
            foreach ($mandatory_fields as $key => $field) {
2936
                if (!isset($user[$field]) || 0 == strlen($user[$field])) {
2937
                    $user['error'] = get_lang($field.'Mandatory');
2938
                    $errors[] = $user;
2939
                }
2940
            }
2941
            // 2. Check whether the username is too long.
2942
            if (UserManager::is_username_too_long($user['UserName'])) {
2943
                $user['error'] = get_lang('This login is too long');
2944
                $errors[] = $user;
2945
            }
2946
2947
            $user['UserName'] = trim($user['UserName']);
2948
2949
            if (empty($user['UserName'])) {
2950
                $user['UserName'] = UserManager::create_username($user['FirstName'], $user['LastName']);
2951
            }
2952
            $new_users[] = $user;
2953
        }
2954
        $results = ['errors' => $errors, 'users' => $new_users];
2955
2956
        return $results;
2957
    }
2958
2959
    /**
2960
     * Adds missing user-information (which isn't required, like password, etc).
2961
     */
2962
    public static function complete_missing_data($user)
2963
    {
2964
        // 1. Generate a password if it is necessary.
2965
        if (!isset($user['Password']) || 0 == strlen($user['Password'])) {
2966
            $user['Password'] = api_generate_password();
2967
        }
2968
2969
        return $user;
2970
    }
2971
2972
    /**
2973
     * Saves imported data.
2974
     */
2975
    public static function save_data($users, $course_list, $id_session)
2976
    {
2977
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2978
        $tbl_session_rel_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
2979
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2980
        $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
2981
2982
        $id_session = (int) $id_session;
2983
        $sendMail = $_POST['sendMail'] ? 1 : 0;
2984
2985
        // Adding users to the platform.
2986
        $new_users = [];
2987
        foreach ($users as $index => $user) {
2988
            $user = self::complete_missing_data($user);
2989
            // coach only will registered users
2990
            $default_status = STUDENT;
2991
            if (COURSEMANAGER == $user['create']) {
2992
                $user['id'] = UserManager:: create_user(
2993
                    $user['FirstName'],
2994
                    $user['LastName'],
2995
                    $default_status,
2996
                    $user['Email'],
2997
                    $user['UserName'],
2998
                    $user['Password'],
2999
                    $user['OfficialCode'],
3000
                    api_get_setting('PlatformLanguage'),
3001
                    $user['PhoneNumber']
3002
                );
3003
                $user['added_at_platform'] = 1;
3004
            } else {
3005
                $user['id'] = $user['create'];
3006
                $user['added_at_platform'] = 0;
3007
            }
3008
            $new_users[] = $user;
3009
        }
3010
        // Update user list.
3011
        $users = $new_users;
3012
3013
        // Inserting users.
3014
        SessionManager::insertUsersInCourses(
3015
            array_column($users, 'id'),
3016
            $course_list,
3017
            $id_session
3018
        );
3019
3020
        array_walk(
3021
            $users,
3022
            function (array &$user) {
3023
                $user['added_at_session'] = 1;
3024
            }
3025
        );
3026
3027
        $registered_users = get_lang('File imported').'<br /> Import file results : <br />';
3028
        // Sending emails.
3029
        $addedto = '';
3030
        if ($sendMail) {
3031
            foreach ($users as $index => $user) {
3032
                $emailsubject = '['.api_get_setting('siteName').'] '.get_lang('Your registration on').' '.api_get_setting('siteName');
3033
                $emailbody = get_lang('Dear').' '.
3034
                    api_get_person_name($user['First name'], $user['Last name']).",\n\n".
3035
                    get_lang('You are registered to')." ".api_get_setting('siteName')." ".get_lang('with the following settings:')."\n\n".
3036
                    get_lang('Username')." : $user[UserName]\n".
3037
                    get_lang('Pass')." : $user[Password]\n\n".
3038
                    get_lang('The address of')." ".api_get_setting('siteName')." ".get_lang('is')." : ".api_get_path(WEB_PATH)." \n\n".
3039
                    get_lang('In case of trouble, contact us.')."\n\n".
3040
                    get_lang('Sincerely').",\n\n".
3041
                    api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'))."\n".
3042
                    get_lang('Administrator')." ".api_get_setting('siteName')."\nT. ".
3043
                    api_get_setting('administratorTelephone')."\n".get_lang('E-mail')." : ".api_get_setting('emailAdministrator');
3044
3045
                api_mail_html(
3046
                    api_get_person_name($user['First name'], $user['Last name'], null, PERSON_NAME_EMAIL_ADDRESS),
3047
                    $user['e-mail'],
3048
                    $emailsubject,
3049
                    $emailbody
3050
                );
3051
                $userInfo = api_get_user_info($user['id']);
3052
3053
                if ((1 == $user['added_at_platform'] && 1 == $user['added_at_session']) || 1 == $user['added_at_session']) {
3054
                    if (1 == $user['added_at_platform']) {
3055
                        $addedto = get_lang('User created in portal');
3056
                    } else {
3057
                        $addedto = '          ';
3058
                    }
3059
3060
                    if (1 == $user['added_at_session']) {
3061
                        $addedto .= get_lang('User added into the session');
3062
                    }
3063
                } else {
3064
                    $addedto = get_lang('User not added.');
3065
                }
3066
3067
                $registered_users .= UserManager::getUserProfileLink($userInfo).' - '.$addedto.'<br />';
3068
            }
3069
        } else {
3070
            foreach ($users as $index => $user) {
3071
                $userInfo = api_get_user_info($user['id']);
3072
                if ((1 == $user['added_at_platform'] && 1 == $user['added_at_session']) || 1 == $user['added_at_session']) {
3073
                    if (1 == $user['added_at_platform']) {
3074
                        $addedto = get_lang('User created in portal');
3075
                    } else {
3076
                        $addedto = '          ';
3077
                    }
3078
3079
                    if (1 == $user['added_at_session']) {
3080
                        $addedto .= ' '.get_lang('User added into the session');
3081
                    }
3082
                } else {
3083
                    $addedto = get_lang('User not added.');
3084
                }
3085
                $registered_users .= "<a href=\"../user/userInfo.php?uInfo=".$user['id']."\">".
3086
                    Security::remove_XSS($userInfo['complete_user_name'])."</a> - ".$addedto.'<br />';
3087
            }
3088
        }
3089
        Display::addFlash(Display::return_message($registered_users, 'normal', false));
3090
        header('Location: course.php?id_session='.$id_session);
3091
        exit;
3092
    }
3093
3094
    /**
3095
     * Reads CSV-file.
3096
     *
3097
     * @param string $file Path to the CSV-file
3098
     *
3099
     * @return array All userinformation read from the file
3100
     */
3101
    public static function parse_csv_data($file)
3102
    {
3103
        $users = Import::csvToArray($file);
3104
        foreach ($users as $index => $user) {
3105
            if (isset($user['Courses'])) {
3106
                $user['Courses'] = explode('|', trim($user['Courses']));
3107
            }
3108
            $users[$index] = $user;
3109
        }
3110
3111
        return $users;
3112
    }
3113
3114
    /**
3115
     * Reads XML-file.
3116
     *
3117
     * @param string $file Path to the XML-file
3118
     *
3119
     * @return array All userinformation read from the file
3120
     */
3121
    public static function parse_xml_data($file)
3122
    {
3123
        $crawler = new \Symfony\Component\DomCrawler\Crawler();
3124
        $crawler->addXmlContent(file_get_contents($file));
3125
        $crawler = $crawler->filter('Contacts > Contact ');
3126
        $array = [];
3127
        foreach ($crawler as $domElement) {
3128
            $row = [];
3129
            foreach ($domElement->childNodes as $node) {
3130
                if ('#text' != $node->nodeName) {
3131
                    $row[$node->nodeName] = $node->nodeValue;
3132
                }
3133
            }
3134
            if (!empty($row)) {
3135
                $array[] = $row;
3136
            }
3137
        }
3138
3139
        return $array;
3140
    }
3141
3142
    /**
3143
     * @param int $courseId
3144
     * @param int $sessionId
3145
     * @param int $studentId
3146
     */
3147
    public static function displayTrackingAccessOverView(
3148
        $courseId,
3149
        $sessionId,
3150
        $studentId,
3151
        $perPage = 20,
3152
        $dates = null
3153
    ) {
3154
        $courseId = (int) $courseId;
3155
        $sessionId = (int) $sessionId;
3156
        $studentId = (int) $studentId;
3157
3158
        $courseList = [];
3159
        $sessionList = [];
3160
        $studentList = [];
3161
3162
        if (!empty($courseId)) {
3163
            $course = api_get_course_entity($courseId);
3164
            if ($course) {
3165
                $courseList[$course->getId()] = $course->getTitle();
3166
            }
3167
        }
3168
3169
        if (!empty($sessionId)) {
3170
            $session = api_get_session_entity($sessionId);
3171
            if ($session) {
3172
                $sessionList[$session->getId()] = $session->getTitle();
3173
            }
3174
        }
3175
3176
        if (!empty($studentId)) {
3177
            $student = api_get_user_entity($studentId);
3178
            if ($student) {
3179
                $studentList[$student->getId()] = UserManager::formatUserFullName($student);
3180
            }
3181
        }
3182
3183
        $form = new FormValidator('access_overview', 'GET');
3184
        $form->addElement(
3185
            'select_ajax',
3186
            'course_id',
3187
            get_lang('Search courses'),
3188
            $courseList,
3189
            [
3190
                'url' => api_get_path(WEB_AJAX_PATH).'course.ajax.php?'.http_build_query([
3191
                    'a' => 'search_course_by_session_all',
3192
                    'session_id' => $sessionId,
3193
                    'course_id' => $courseId,
3194
                ]),
3195
            ]
3196
        );
3197
3198
        $form->addElement(
3199
            'select_ajax',
3200
            'session_id',
3201
            get_lang('Search sessions'),
3202
            $sessionList,
3203
            [
3204
                'url_function' => "
3205
                    function () {
3206
                        var params = $.param({
3207
                            a: 'search_session_by_course',
3208
                            course_id: $('#access_overview_course_id').val() || 0
3209
                        });
3210
3211
                        return '".api_get_path(WEB_AJAX_PATH)."session.ajax.php?' + params;
3212
                    }
3213
                ",
3214
            ]
3215
        );
3216
3217
        $form->addSelect(
3218
            'profile',
3219
            get_lang('Profile'),
3220
            [
3221
                '' => get_lang('Select'),
3222
                STUDENT => get_lang('Learner'),
3223
                COURSEMANAGER => get_lang('Teacher'),
3224
                DRH => get_lang('Human Resources Manager'),
3225
            ],
3226
            ['id' => 'profile']
3227
        );
3228
3229
        $form->addElement(
3230
            'select_ajax',
3231
            'student_id',
3232
            get_lang('Search users'),
3233
            $studentList,
3234
            [
3235
                'placeholder' => get_lang('All'),
3236
                'url_function' => "
3237
                    function () {
3238
                        var params = $.param({
3239
                            a: 'search_user_by_course',
3240
                            session_id: $('#access_overview_session_id').val(),
3241
                            course_id: $('#access_overview_course_id').val()
3242
                        });
3243
3244
                        return '".api_get_path(WEB_AJAX_PATH)."course.ajax.php?' + params;
3245
                    }
3246
                ",
3247
            ]
3248
        );
3249
        $form->addDateRangePicker(
3250
            'date',
3251
            get_lang('Date range'),
3252
            true,
3253
            [
3254
                'id' => 'date_range',
3255
                'format' => 'YYYY-MM-DD HH:mm',
3256
                'timePicker' => 'true',
3257
            ]
3258
        );
3259
        $form->addHidden('display', 'accessoverview');
3260
        $form->addRule('course_id', get_lang('Required'), 'required');
3261
        $form->addRule('profile', get_lang('Required'), 'required');
3262
        $form->addButton('submit', get_lang('Generate'), 'gear', 'primary');
3263
3264
        $table = null;
3265
        if (!empty($dates)) {
3266
            $table = new SortableTable(
3267
                'tracking_access_overview',
3268
                ['MySpace', 'getNumberOfTrackAccessOverview'],
3269
                ['MySpace', 'getUserDataAccessTrackingOverview'],
3270
                0,
3271
                $perPage
3272
            );
3273
            $table->set_additional_parameters(
3274
                [
3275
                    'course_id' => $courseId,
3276
                    'session_id' => $sessionId,
3277
                    'student_id' => $studentId,
3278
                    'date' => $dates,
3279
                    'tracking_access_overview_per_page' => $perPage,
3280
                    'display' => 'accessoverview',
3281
                ]
3282
            );
3283
            $table->set_header(0, get_lang('Login date'), true);
3284
            $table->set_header(1, get_lang('Username'), true);
3285
            if (api_is_western_name_order()) {
3286
                $table->set_header(2, get_lang('First name'), true);
3287
                $table->set_header(3, get_lang('Last name'), true);
3288
            } else {
3289
                $table->set_header(2, get_lang('Last name'), true);
3290
                $table->set_header(3, get_lang('First name'), true);
3291
            }
3292
            $table->set_header(4, get_lang('IP'), false);
3293
            $table->set_header(5, get_lang('Time connected (hh:mm)'), false);
3294
        }
3295
3296
        $template = new Template(
3297
            null,
3298
            false,
3299
            false,
3300
            false,
3301
            false,
3302
            false,
3303
            false
3304
        );
3305
        $template->assign('form', $form->returnForm());
3306
        $template->assign('table', $table ? $table->return_table() : null);
3307
3308
        echo $template->fetch(
3309
            $template->get_template('my_space/accessoverview.tpl')
3310
        );
3311
    }
3312
3313
    /**
3314
     * @return int
3315
     */
3316
    public static function getNumberOfTrackAccessOverview()
3317
    {
3318
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
3319
        $sql = "SELECT COUNT(course_access_id) count FROM $table";
3320
        $result = Database::query($sql);
3321
        $row = Database::fetch_assoc($result);
3322
3323
        if ($row) {
3324
            return $row['count'];
3325
        }
3326
3327
        return 0;
3328
    }
3329
3330
    /**
3331
     * @param $from
3332
     * @param $numberItems
3333
     * @param $column
3334
     * @param $orderDirection
3335
     *
3336
     * @return array
3337
     */
3338
    public static function getUserDataAccessTrackingOverview(
3339
        $from,
3340
        $numberItems,
3341
        $column,
3342
        $orderDirection
3343
    ) {
3344
        $from = (int) $from;
3345
        $numberItems = (int) $numberItems;
3346
        $column = (int) $column;
3347
        $orderDirection = Database::escape_string($orderDirection);
3348
        $orderDirection = !in_array(strtolower(trim($orderDirection)), ['asc', 'desc']) ? 'asc' : $orderDirection;
3349
3350
        $user = Database::get_main_table(TABLE_MAIN_USER);
3351
        $course = Database::get_main_table(TABLE_MAIN_COURSE);
3352
        $track_e_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
3353
        $trackCourseAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
3354
3355
        global $export_csv;
3356
        $is_western_name_order = api_is_western_name_order();
3357
        if ($export_csv) {
3358
            $is_western_name_order = api_is_western_name_order(PERSON_NAME_DATA_EXPORT);
3359
        }
3360
3361
        //TODO add course name
3362
        $sql = "SELECT
3363
                a.login_course_date as col0,
3364
                u.username as col1,
3365
                ".(
3366
                    $is_western_name_order ? "
3367
                        u.firstname AS col2,
3368
                        u.lastname AS col3,
3369
                    " : "
3370
                        u.lastname AS col2,
3371
                        u.firstname AS col3,
3372
                "
3373
        )."
3374
                a.login_course_date,
3375
                a.logout_course_date,
3376
                c.title,
3377
                c.code,
3378
                u.id as user_id,
3379
                user_ip
3380
            FROM $trackCourseAccess a
3381
            INNER JOIN $user u
3382
            ON a.user_id = u.id
3383
            INNER JOIN $course c
3384
            ON a.c_id = c.id
3385
            WHERE 1=1 ";
3386
3387
        $sql = self::getDataAccessTrackingFilters($sql);
3388
3389
        $sql .= " ORDER BY col$column $orderDirection ";
3390
        $sql .= " LIMIT $from,$numberItems";
3391
3392
        $result = Database::query($sql);
3393
3394
        $data = [];
3395
        while ($user = Database::fetch_assoc($result)) {
3396
            $data[] = $user;
3397
        }
3398
3399
        $return = [];
3400
        //TODO: Dont use numeric index
3401
        foreach ($data as $key => $info) {
3402
            $return[] = [
3403
                api_get_local_time($info['login_course_date']),
3404
                $info['col1'],
3405
                $info['col2'],
3406
                $info['col3'],
3407
                $info['user_ip'],
3408
                gmdate('H:i:s', strtotime($info['logout_course_date']) - strtotime($info['login_course_date'])),
3409
            ];
3410
        }
3411
3412
        return $return;
3413
    }
3414
3415
    /**
3416
     * Gets the connections to a course as an array of login and logout time.
3417
     *
3418
     * @param int    $user_id
3419
     * @param array  $course_info
3420
     * @param int    $sessionId
3421
     * @param string $start_date
3422
     * @param string $end_date
3423
     * @param bool   $addUserIp
3424
     *
3425
     * @author  Jorge Frisancho Jibaja
3426
     * @author  Julio Montoya <[email protected]> fixing the function
3427
     *
3428
     * @version OCT-22- 2010
3429
     *
3430
     * @return array
3431
     */
3432
    public static function get_connections_to_course_by_date(
3433
        $user_id,
3434
        $course_info,
3435
        $sessionId,
3436
        $start_date,
3437
        $end_date,
3438
        $addUserIp = false
3439
    ) {
3440
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
3441
        $user_id = (int) $user_id;
3442
        $connections = [];
3443
        if (!empty($course_info)) {
3444
            $courseId = (int) $course_info['real_id'];
3445
            $end_date = self::add_day_to($end_date);
3446
3447
            $start_date = Database::escape_string($start_date);
3448
            $end_date = Database::escape_string($end_date);
3449
            $sessionCondition = api_get_session_condition($sessionId);
3450
            $sql = "SELECT
3451
                        login_course_date,
3452
                        logout_course_date,
3453
                        TIMESTAMPDIFF(SECOND, login_course_date, logout_course_date) duration,
3454
                        user_ip
3455
                    FROM $table
3456
                    WHERE
3457
                        user_id = $user_id AND
3458
                        c_id = $courseId AND
3459
                        login_course_date BETWEEN '$start_date' AND '$end_date' AND
3460
                        logout_course_date BETWEEN '$start_date' AND '$end_date'
3461
                        $sessionCondition
3462
                    ORDER BY login_course_date ASC";
3463
            $rs = Database::query($sql);
3464
3465
            while ($row = Database::fetch_array($rs)) {
3466
                $item = [
3467
                    'login' => $row['login_course_date'],
3468
                    'logout' => $row['logout_course_date'],
3469
                    'duration' => $row['duration'],
3470
                ];
3471
                if ($addUserIp) {
3472
                    $item['user_ip'] = $row['user_ip'];
3473
                }
3474
                $connections[] = $item;
3475
            }
3476
        }
3477
3478
        return $connections;
3479
    }
3480
3481
    /**
3482
     * @param int   $user_id
3483
     * @param array $course_info
3484
     * @param int   $sessionId
3485
     * @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...
3486
     * @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...
3487
     *
3488
     * @return array
3489
     */
3490
    public static function getStats($user_id, $course_info, $sessionId, $start_date = null, $end_date = null)
3491
    {
3492
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
3493
        $result = [];
3494
        if (!empty($course_info)) {
3495
            $stringStartDate = '';
3496
            $stringEndDate = '';
3497
            if (null != $start_date && null != $end_date) {
3498
                $end_date = self::add_day_to($end_date);
3499
3500
                $start_date = Database::escape_string($start_date);
3501
                $end_date = Database::escape_string($end_date);
3502
3503
                $stringStartDate = "AND login_course_date BETWEEN '$start_date' AND '$end_date'";
3504
                $stringEndDate = "AND logout_course_date BETWEEN '$start_date' AND '$end_date'";
3505
            }
3506
            $user_id = (int) $user_id;
3507
            $courseId = (int) $course_info['real_id'];
3508
            $sessionCondition = api_get_session_condition($sessionId);
3509
            $sql = "SELECT
3510
                SEC_TO_TIME(AVG(time_to_sec(timediff(logout_course_date,login_course_date)))) as avrg,
3511
                SEC_TO_TIME(SUM(time_to_sec(timediff(logout_course_date,login_course_date)))) as total,
3512
                count(user_id) as times
3513
                FROM $table
3514
                WHERE
3515
                    user_id = $user_id AND
3516
                    c_id = $courseId $stringStartDate $stringEndDate
3517
                    $sessionCondition
3518
                ORDER BY login_course_date ASC";
3519
3520
            $rs = Database::query($sql);
3521
            if ($row = Database::fetch_array($rs)) {
3522
                $foo_avg = $row['avrg'];
3523
                $foo_total = $row['total'];
3524
                $foo_times = $row['times'];
3525
                $result = [
3526
                'avg' => $foo_avg,
3527
                'total' => $foo_total,
3528
                'times' => $foo_times,
3529
            ];
3530
            }
3531
        }
3532
3533
        return $result;
3534
    }
3535
3536
    public static function add_day_to($end_date)
3537
    {
3538
        $foo_date = strtotime($end_date);
3539
        $foo_date = strtotime(' +1 day', $foo_date);
3540
        $foo_date = date('Y-m-d', $foo_date);
3541
3542
        return $foo_date;
3543
    }
3544
3545
    /**
3546
     * This function draw the graphic to be displayed on the user view as an image.
3547
     *
3548
     * @param array  $sql_result
3549
     * @param string $start_date
3550
     * @param string $end_date
3551
     * @param string $type
3552
     *
3553
     * @author Jorge Frisancho Jibaja
3554
     *
3555
     * @version OCT-22- 2010
3556
     *
3557
     * @return string
3558
     */
3559
    public static function grapher($sql_result, $start_date, $end_date, $type = '')
3560
    {
3561
        if (empty($start_date)) {
3562
            $start_date = '';
3563
        }
3564
        if (empty($end_date)) {
3565
            $end_date = '';
3566
        }
3567
        if ('' == $type) {
3568
            $type = 'day';
3569
        }
3570
        $main_year = $main_month_year = $main_day = [];
3571
3572
        $period = new DatePeriod(
3573
        new DateTime($start_date),
3574
        new DateInterval('P1D'),
3575
        new DateTime($end_date)
3576
    );
3577
3578
        foreach ($period as $date) {
3579
            $main_day[$date->format('d-m-Y')] = 0;
3580
        }
3581
3582
        $period = new DatePeriod(
3583
        new DateTime($start_date),
3584
        new DateInterval('P1M'),
3585
        new DateTime($end_date)
3586
    );
3587
3588
        foreach ($period as $date) {
3589
            $main_month_year[$date->format('m-Y')] = 0;
3590
        }
3591
3592
        $i = 0;
3593
        if (is_array($sql_result) && count($sql_result) > 0) {
3594
            foreach ($sql_result as $key => $data) {
3595
                $login = api_strtotime($data['login']);
3596
                $logout = api_strtotime($data['logout']);
3597
                //creating the main array
3598
                if (isset($main_month_year[date('m-Y', $login)])) {
3599
                    $main_month_year[date('m-Y', $login)] += (float) ($logout - $login) / 60;
3600
                }
3601
                if (isset($main_day[date('d-m-Y', $login)])) {
3602
                    $main_day[date('d-m-Y', $login)] += (float) ($logout - $login) / 60;
3603
                }
3604
                if ($i > 500) {
3605
                    break;
3606
                }
3607
                $i++;
3608
            }
3609
            switch ($type) {
3610
            case 'day':
3611
                $main_date = $main_day;
3612
                break;
3613
            case 'month':
3614
                $main_date = $main_month_year;
3615
                break;
3616
            case 'year':
3617
                $main_date = $main_year;
3618
                break;
3619
        }
3620
3621
            $labels = array_keys($main_date);
3622
            if (1 == count($main_date)) {
3623
                $labels = $labels[0];
3624
                $main_date = $main_date[$labels];
3625
            }
3626
3627
            /* Create and populate the pData object */
3628
            $myData = new pData();
3629
            $myData->addPoints($main_date, 'Serie1');
3630
            if (1 != count($main_date)) {
3631
                $myData->addPoints($labels, 'Labels');
3632
                $myData->setSerieDescription('Labels', 'Months');
3633
                $myData->setAbscissa('Labels');
3634
            }
3635
            $myData->setSerieWeight('Serie1', 1);
3636
            $myData->setSerieDescription('Serie1', get_lang('My results'));
3637
            $myData->setAxisName(0, get_lang('Minutes'));
3638
            $myData->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
3639
3640
            // Cache definition
3641
            $cachePath = api_get_path(SYS_ARCHIVE_PATH);
3642
            $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]);
3643
            $chartHash = $myCache->getHash($myData);
3644
3645
            if ($myCache->isInCache($chartHash)) {
3646
                //if we already created the img
3647
                $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
3648
                $myCache->saveFromCache($chartHash, $imgPath);
3649
                $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
3650
            } else {
3651
                /* Define width, height and angle */
3652
                $mainWidth = 760;
3653
                $mainHeight = 230;
3654
                $angle = 50;
3655
3656
                /* Create the pChart object */
3657
                $myPicture = new pImage($mainWidth, $mainHeight, $myData);
3658
3659
                /* Turn of Antialiasing */
3660
                $myPicture->Antialias = false;
3661
                /* Draw the background */
3662
                $settings = ["R" => 255, "G" => 255, "B" => 255];
3663
                $myPicture->drawFilledRectangle(0, 0, $mainWidth, $mainHeight, $settings);
3664
3665
                /* Add a border to the picture */
3666
                $myPicture->drawRectangle(
3667
                0,
3668
                0,
3669
                $mainWidth - 1,
3670
                $mainHeight - 1,
3671
                ["R" => 0, "G" => 0, "B" => 0]
3672
            );
3673
3674
                /* Set the default font */
3675
                $myPicture->setFontProperties(
3676
                [
3677
                    "FontName" => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
3678
                    "FontSize" => 10, ]
3679
            );
3680
                /* Write the chart title */
3681
                $myPicture->drawText(
3682
                $mainWidth / 2,
3683
                30,
3684
                get_lang('Time spent in the course'),
3685
                [
3686
                    "FontSize" => 12,
3687
                    "Align" => TEXT_ALIGN_BOTTOMMIDDLE,
3688
                ]
3689
            );
3690
3691
                /* Set the default font */
3692
                $myPicture->setFontProperties(
3693
                [
3694
                    "FontName" => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
3695
                    "FontSize" => 8,
3696
                ]
3697
            );
3698
3699
                /* Define the chart area */
3700
                $myPicture->setGraphArea(50, 40, $mainWidth - 40, $mainHeight - 80);
3701
3702
                /* Draw the scale */
3703
                $scaleSettings = [
3704
                'XMargin' => 10,
3705
                'YMargin' => 10,
3706
                'Floating' => true,
3707
                'GridR' => 200,
3708
                'GridG' => 200,
3709
                'GridB' => 200,
3710
                'DrawSubTicks' => true,
3711
                'CycleBackground' => true,
3712
                'LabelRotation' => $angle,
3713
                'Mode' => SCALE_MODE_ADDALL_START0,
3714
            ];
3715
                $myPicture->drawScale($scaleSettings);
3716
3717
                /* Turn on Antialiasing */
3718
                $myPicture->Antialias = true;
3719
3720
                /* Enable shadow computing */
3721
                $myPicture->setShadow(
3722
                true,
3723
                [
3724
                    "X" => 1,
3725
                    "Y" => 1,
3726
                    "R" => 0,
3727
                    "G" => 0,
3728
                    "B" => 0,
3729
                    "Alpha" => 10,
3730
                ]
3731
            );
3732
3733
                /* Draw the line chart */
3734
                $myPicture->setFontProperties(
3735
                [
3736
                    "FontName" => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
3737
                    "FontSize" => 10,
3738
                ]
3739
            );
3740
                $myPicture->drawSplineChart();
3741
                $myPicture->drawPlotChart(
3742
                [
3743
                    "DisplayValues" => true,
3744
                    "PlotBorder" => true,
3745
                    "BorderSize" => 1,
3746
                    "Surrounding" => -60,
3747
                    "BorderAlpha" => 80,
3748
                ]
3749
            );
3750
3751
                /* Do NOT Write the chart legend */
3752
3753
                /* Write and save into cache */
3754
                $myCache->writeToCache($chartHash, $myPicture);
3755
                $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
3756
                $myCache->saveFromCache($chartHash, $imgPath);
3757
                $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
3758
            }
3759
3760
            return '<img src="'.$imgPath.'">';
3761
        } else {
3762
            return api_convert_encoding(
3763
                '<div id="messages" class="warning-message">'.get_lang('Graphic not available').'</div>',
3764
            'UTF-8'
3765
        );
3766
        }
3767
    }
3768
3769
    /**
3770
     * Gets a list of users who were enrolled in the lessons.
3771
     * It is necessary that in the extra field, a company is defined.
3772
     *
3773
     *  if lpId is different to 0, this search by lp id too
3774
     *
3775
     * @param string|null $startDate
3776
     * @param string|null $endDate
3777
     * @param int         $lpId
3778
     * @param bool        $whitCompany
3779
     *
3780
     * @return array
3781
     */
3782
    protected static function getCompanyLearnpathSubscription(
3783
        $startDate = null,
3784
        $endDate = null,
3785
        $lpId = 0,
3786
        $whitCompany = false
3787
    ) {
3788
        $tblItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
3789
        $tblLp = Database::get_course_table(TABLE_LP_MAIN);
3790
        $tblExtraField = Database::get_main_table(TABLE_EXTRA_FIELD);
3791
        $tblExtraFieldValue = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
3792
3793
        $whereCondition = '';
3794
3795
        //Validating dates
3796
        if (!empty($startDate)) {
3797
            $startDate = new DateTime($startDate);
3798
        }
3799
        if (!empty($endDate)) {
3800
            $endDate = new DateTime($endDate);
3801
        }
3802
        if (!empty($startDate) and !empty($endDate)) {
3803
            if ($startDate > $endDate) {
3804
                $dateTemp = $endDate;
3805
                $endDate = $startDate;
3806
                $startDate = $dateTemp;
3807
                unset($dateTemp);
3808
            }
3809
        }
3810
3811
        // Settings condition and parametter GET to right date
3812
        if (!empty($startDate)) {
3813
            $startDate = api_get_utc_datetime($startDate->setTime(0, 0, 0)->format('Y-m-d H:i:s'));
3814
            $_GET['startDate'] = $startDate;
3815
            $whereCondition .= "
3816
            AND $tblItemProperty.lastedit_date >= '$startDate' ";
3817
        }
3818
        if (!empty($endDate)) {
3819
            $endDate = api_get_utc_datetime($endDate->setTime(23, 59, 59)->format('Y-m-d H:i:s'));
3820
            $_GET['endDate'] = $endDate;
3821
            $whereCondition .= "
3822
            AND $tblItemProperty.lastedit_date <= '$endDate' ";
3823
        }
3824
        if (0 != $lpId) {
3825
            $whereCondition .= "
3826
            AND c_item_property.ref = $lpId ";
3827
        }
3828
3829
        $companys = [];
3830
        if (!empty($startDate) or !empty($endDate)) {
3831
            // get Compnay data
3832
            $selectToCompany = " (
3833
            SELECT
3834
                value
3835
            FROM
3836
                $tblExtraFieldValue
3837
            WHERE
3838
                field_id IN (
3839
                    SELECT
3840
                        id
3841
                    FROM
3842
                        $tblExtraField
3843
                    WHERE
3844
                        variable = 'company'
3845
                )
3846
            AND item_id = $tblItemProperty.to_user_id
3847
            ) ";
3848
            $query = "
3849
            SELECT
3850
                * ,
3851
                 $selectToCompany  as company,
3852
                    (
3853
                    SELECT
3854
                        name
3855
                    FROM
3856
                        $tblLp
3857
                    WHERE
3858
                    $tblLp.iid = c_item_property.ref
3859
                 ) as name_lp
3860
            FROM
3861
                $tblItemProperty
3862
            WHERE
3863
                c_id IN (
3864
                    SELECT
3865
                        c_id
3866
                    FROM
3867
                        ".TABLE_MAIN_COURSE_USER."
3868
                    WHERE
3869
                        STATUS = 5
3870
                )
3871
                AND lastedit_type = 'LearnpathSubscription'
3872
3873
                ";
3874
            // -- AND $selectToCompany IS NOT NULL
3875
            if (strlen($whereCondition) > 2) {
3876
                $query .= $whereCondition;
3877
            }
3878
            $queryResult = Database::query($query);
3879
            while ($row = Database::fetch_assoc($queryResult)) {
3880
                // $courseId = (int)$row['c_id'];
3881
                $studentId = (int) $row['to_user_id'];
3882
                $company = isset($row['company']) ? $row['company'] : '';
3883
                if ('' == $company) {
3884
                    $company = get_lang('No organization');
3885
                }
3886
                // $lpId = $row['ref'];
3887
                if (0 != $lpId && 0 != $studentId) {
3888
                    if (true == $whitCompany) {
3889
                        $companys[] = [
3890
                            'id' => $studentId,
3891
                            'company' => $company,
3892
                        ];
3893
                    } else {
3894
                        $companys[] = $studentId;
3895
                    }
3896
                } else {
3897
                    $companys[$company][] = $studentId;
3898
                    $companys[$company] = array_unique($companys[$company]);
3899
                }
3900
            }
3901
        }
3902
3903
        return $companys;
3904
    }
3905
3906
    private static function getDataAccessTrackingFilters($sql)
3907
    {
3908
        if (isset($_GET['course_id']) && !empty($_GET['course_id'])) {
3909
            $courseId = (int) $_GET['course_id'];
3910
            $sql .= " AND c.id = ".$courseId;
3911
        }
3912
3913
        if (isset($_GET['session_id']) && !empty($_GET['session_id'])) {
3914
            $sessionId = (int) $_GET['session_id'];
3915
            $sql .= " AND a.session_id = ".$sessionId;
3916
        }
3917
3918
        if (isset($_GET['student_id']) && !empty($_GET['student_id'])) {
3919
            $userId = (int) $_GET['student_id'];
3920
            $sql .= " AND u.id = ".$userId;
3921
        }
3922
3923
        $sql .= " AND u.status <> ".ANONYMOUS;
3924
3925
        if (isset($_GET['date']) && !empty($_GET['date'])) {
3926
            $dateRangePicker = new DateRangePicker('date', '', ['timePicker' => 'true']);
3927
            $dates = $dateRangePicker->parseDateRange($_GET['date']);
3928
            if (isset($dates['start']) && !empty($dates['start'])) {
3929
                $dates['start'] = Database::escape_string(api_get_utc_datetime($dates['start']));
3930
                $sql .= " AND login_course_date >= '".$dates['start']."'";
3931
            }
3932
            if (isset($dates['end']) && !empty($dates['end'])) {
3933
                $dates['end'] = Database::escape_string(api_get_utc_datetime($dates['end']));
3934
                $sql .= " AND logout_course_date <= '".$dates['end']."'";
3935
            }
3936
        }
3937
3938
        return $sql;
3939
    }
3940
3941
    /**
3942
     * Render the admin reports navigation cards (common layout for tracking pages).
3943
     *
3944
     * @param string|null $activeDisplay            Report key used in ?display=... (admin_view)
3945
     * @param string|null $currentScript            Current PHP script name (e.g. "tc_report.php")
3946
     * @param bool        $includeCurrentReportNote Append the "Current report" helper text
3947
     *
3948
     * @return string
3949
     */
3950
    public static function renderAdminReportCardsSection(
3951
        ?string $activeDisplay = null,
3952
        ?string $currentScriptName = null,
3953
        bool $includeNote = false
3954
    ): string {
3955
        $actions = self::generateAdminActionLinks();
3956
        $currentReportLabel = null;
3957
3958
        // If there is no display parameter we fall back to script-based matching.
3959
        $useScriptMatching = null === $activeDisplay;
3960
3961
        if ($useScriptMatching && empty($currentScriptName)) {
3962
            $currentScriptName = basename($_SERVER['SCRIPT_NAME'] ?? '');
3963
        } else {
3964
            // Normalize in case a full path is passed.
3965
            $currentScriptName = basename((string) $currentScriptName);
3966
        }
3967
3968
        $html = '';
3969
3970
        $html .= '<section class="bg-white rounded-xl shadow-sm border border-gray-50 reporting-admin-list w-full">';
3971
        $html .= '  <div class="p-4 md:p-5 space-y-4">';
3972
        $html .= '    <h2 class="text-base md:text-lg font-semibold text-gray-800">'.get_lang('Available reports').'</h2>';
3973
        $html .= '    <div class="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">';
3974
3975
        foreach ($actions as $action) {
3976
            $url       = $action['url'];
3977
            $labelHtml = $action['content'];
3978
            $labelText = strip_tags($labelHtml);
3979
3980
            $parsedUrl   = parse_url($url);
3981
            $queryParams = [];
3982
            if (!empty($parsedUrl['query'])) {
3983
                parse_str($parsedUrl['query'], $queryParams);
3984
            }
3985
            $reportKey = $queryParams['display'] ?? null;
3986
3987
            // -------- Active state detection --------
3988
            $isActive = false;
3989
3990
            // 1) Classic admin_view.php (?display=...)
3991
            if (null !== $activeDisplay && null !== $reportKey && $reportKey === $activeDisplay) {
3992
                $isActive = true;
3993
                // 2) Fallback: match by script name (tc_report.php, bosses report, etc.)
3994
            } elseif (
3995
                $useScriptMatching &&
3996
                !empty($parsedUrl['path']) &&
3997
                !empty($currentScriptName) &&
3998
                str_contains($parsedUrl['path'], $currentScriptName)
3999
            ) {
4000
                $isActive = true;
4001
            }
4002
4003
            if ($isActive) {
4004
                $currentReportLabel = $labelText;
4005
            }
4006
4007
            // -------- Icon selection --------
4008
            $iconName = 'file-chart';
4009
            switch ($reportKey) {
4010
                case 'coaches':
4011
                    $iconName = 'account-tie';
4012
                    break;
4013
                case 'user':
4014
                    $iconName = 'account-multiple';
4015
                    break;
4016
                case 'session':
4017
                    $iconName = 'calendar-multiple';
4018
                    break;
4019
                case 'course':
4020
                    $iconName = 'book-open-page-variant';
4021
                    break;
4022
                case 'company':
4023
                    $iconName = 'office-building';
4024
                    break;
4025
                case 'learningPath':
4026
                    $iconName = 'timeline-text';
4027
                    break;
4028
                case 'learningPathByItem':
4029
                    $iconName = 'format-list-bulleted';
4030
                    break;
4031
                case 'accessoverview':
4032
                    $iconName = 'eye';
4033
                    break;
4034
                default:
4035
                    // Special icon for the general coach report without ?display=...
4036
                    if (!empty($parsedUrl['path']) && basename($parsedUrl['path']) === 'tc_report.php') {
4037
                        $iconName = 'account-group';
4038
                    } else {
4039
                        $iconName = 'file-chart';
4040
                    }
4041
            }
4042
4043
            $cardClass = 'admin-report-card block rounded-xl border border-gray-50 bg-gray-20 '.
4044
                'hover:bg-white hover:border-sky-400 shadow-sm hover:shadow-md transition';
4045
            if ($isActive) {
4046
                $cardClass .= ' admin-report-card-active';
4047
            }
4048
4049
            $html .= '      <a href="'.$url.'" class="'.$cardClass.'">';
4050
            $html .= '        <div class="flex items-center gap-3 p-3 md:p-4">';
4051
            $html .= '          <div class="flex-shrink-0">';
4052
            $html .=                Display::getMdiIcon(
4053
                $iconName,
4054
                'ch-tool-icon',
4055
                null,
4056
                32,
4057
                $labelText
4058
            );
4059
            $html .= '          </div>';
4060
            $html .= '          <div class="text-sm md:text-base text-gray-800">';
4061
            $html .=                $labelHtml;
4062
            $html .= '          </div>';
4063
            $html .= '        </div>';
4064
            $html .= '      </a>';
4065
        }
4066
4067
        $html .= '    </div>';
4068
        $html .= '  </div>';
4069
        $html .= '</section>';
4070
4071
        if ($includeNote && !empty($currentReportLabel)) {
4072
            $html .= '<div class="mt-2">';
4073
            $html .= '  <p class="text-sm text-gray-600">'.
4074
                get_lang('Current report').': <span class="font-semibold text-gray-900">'.
4075
                $currentReportLabel.
4076
                '</span></p>';
4077
            $html .= '</div>';
4078
        }
4079
4080
        return $html;
4081
    }
4082
}
4083