Passed
Push — master ( f801c1...492dcf )
by Julito
10:30 queued 10s
created

Event::accessCourse()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 42
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 26
nc 5
nop 0
dl 0
loc 42
rs 9.504
c 0
b 0
f 0
1
<?php
2
/* See license terms in /license.txt */
3
4
//use Chamilo\UserBundle\Entity\User;
5
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
6
use ChamiloSession as Session;
7
8
/**
9
 * Class Event
10
 * Functions of this library are used to record informations when some kind
11
 * of event occur. Each event has his own types of informations then each event
12
 * use its own function.
13
 */
14
class Event
15
{
16
    /**
17
     * @author Sebastien Piraux <[email protected]> old code
18
     * @author Julio Montoya
19
     *
20
     * @param int $userId
21
     *
22
     * @return bool
23
     * @desc Record information for login event when an user identifies himself with username & password
24
     */
25
    public static function eventLogin($userId)
26
    {
27
        $userInfo = api_get_user_info($userId);
28
        $userId = (int) $userId;
29
30
        if (empty($userInfo)) {
31
            return false;
32
        }
33
34
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
35
        $reallyNow = api_get_utc_datetime();
36
        $userIp = Database::escape_string(api_get_real_ip());
37
38
        $sql = "INSERT INTO $table (login_user_id, user_ip, login_date, logout_date) VALUES
39
                    ($userId,
40
                    '$userIp',
41
                    '$reallyNow',
42
                    '$reallyNow'
43
                )";
44
        Database::query($sql);
45
46
        // Auto subscribe
47
        $user_status = $userInfo['status'] == SESSIONADMIN ? 'sessionadmin' : $userInfo['status'] == COURSEMANAGER ? 'teacher' : $userInfo['status'] == DRH ? 'DRH' : 'student';
48
        $autoSubscribe = api_get_setting($user_status.'_autosubscribe');
49
        if ($autoSubscribe) {
50
            $autoSubscribe = explode('|', $autoSubscribe);
51
            foreach ($autoSubscribe as $code) {
52
                if (CourseManager::course_exists($code)) {
53
                    CourseManager::subscribe_user($userId, $code);
54
                }
55
            }
56
        }
57
58
        return true;
59
    }
60
61
    /**
62
     * @author Sebastien Piraux <[email protected]>
63
     * @desc Record information for access event for courses
64
     */
65
    public static function accessCourse()
66
    {
67
        if (Session::read('login_as')) {
68
            return false;
69
        }
70
71
        $TABLETRACK_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
72
        //for "what's new" notification
73
        $TABLETRACK_LASTACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
74
75
        $id_session = api_get_session_id();
76
        $now = api_get_utc_datetime();
77
        $courseId = api_get_course_int_id();
78
        $userId = api_get_user_id();
79
        $ip = Database::escape_string(api_get_real_ip());
80
81
        if ($userId) {
82
            $userId = $userId;
83
        } else {
84
            $userId = "0"; // no one
85
        }
86
        $sql = "INSERT INTO $TABLETRACK_ACCESS  (user_ip, access_user_id, c_id, access_date, access_session_id) 
87
                VALUES ('$ip', $userId, $courseId, '$now', $id_session)";
88
89
        Database::query($sql);
90
91
        // added for "what's new" notification
92
        $sql = "UPDATE $TABLETRACK_LASTACCESS  SET access_date = '$now'
93
                WHERE 
94
                  access_user_id = $userId AND
95
                  c_id = $courseId AND 
96
                  access_tool IS NULL AND 
97
                  access_session_id = $id_session";
98
        $result = Database::query($sql);
99
100
        if (Database::affected_rows($result) == 0) {
101
            $sql = "INSERT INTO $TABLETRACK_LASTACCESS (access_user_id, c_id, access_date, access_session_id)
102
                    VALUES ($userId, $courseId, '$now', $id_session)";
103
            Database::query($sql);
104
        }
105
106
        return 1;
107
    }
108
109
    /**
110
     * @param string $tool name of the tool
111
     *
112
     * @author Sebastien Piraux <[email protected]>
113
     * @desc Record information for access event for tools
114
     *
115
     *  $tool can take this values :
116
     *  Links, Calendar, Document, Announcements,
117
     *  Group, Video, Works, Users, Exercises, Course Desc
118
     *  ...
119
     *  Values can be added if new modules are created (15char max)
120
     *  I encourage to use $nameTool as $tool when calling this function
121
     *
122
     * Functionality for "what's new" notification is added by Toon Van Hoecke
123
     *
124
     * @return bool
125
     */
126
    public static function event_access_tool($tool)
127
    {
128
        if (Session::read('login_as')) {
129
            return false;
130
        }
131
132
        $tool = Database::escape_string($tool);
133
134
        if (empty($tool)) {
135
            return false;
136
        }
137
138
        $courseInfo = api_get_course_info();
139
        $sessionId = api_get_session_id();
140
        $reallyNow = api_get_utc_datetime();
141
        $userId = api_get_user_id();
142
143
        if (empty($courseInfo)) {
144
            return false;
145
        }
146
        $courseId = $courseInfo['real_id'];
147
148
        $tableAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
149
        //for "what's new" notification
150
        $tableLastAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
151
152
        // record information
153
        // only if user comes from the course $_cid
154
        //if( eregi($_configuration['root_web'].$_cid,$_SERVER['HTTP_REFERER'] ) )
155
        //$pos = strpos($_SERVER['HTTP_REFERER'],$_configuration['root_web'].$_cid);
156
        $coursePath = isset($courseInfo['path']) ? $courseInfo['path'] : null;
157
158
        $pos = isset($_SERVER['HTTP_REFERER']) ? strpos(strtolower($_SERVER['HTTP_REFERER']), strtolower(api_get_path(WEB_COURSE_PATH).$coursePath)) : false;
159
        // added for "what's new" notification
160
        $pos2 = isset($_SERVER['HTTP_REFERER']) ? strpos(strtolower($_SERVER['HTTP_REFERER']), strtolower(api_get_path(WEB_PATH)."index")) : false;
161
162
        // end "what's new" notification
163
        if ($pos !== false || $pos2 !== false) {
164
            $params = [
165
                'access_user_id' => $userId,
166
                'c_id' => $courseId,
167
                'access_tool' => $tool,
168
                'access_date' => $reallyNow,
169
                'access_session_id' => $sessionId,
170
                'user_ip' => Database::escape_string(api_get_real_ip()),
171
            ];
172
            Database::insert($tableAccess, $params);
173
        }
174
175
        // "what's new" notification
176
        $sql = "UPDATE $tableLastAccess
177
                SET access_date = '$reallyNow'
178
                WHERE 
179
                    access_user_id = $userId AND 
180
                    c_id = $courseId AND 
181
                    access_tool = '$tool' AND 
182
                    access_session_id = $sessionId";
183
        $result = Database::query($sql);
184
185
        if (Database::affected_rows($result) == 0) {
186
            $params = [
187
                'access_user_id' => $userId,
188
                'c_id' => $courseId,
189
                'access_tool' => $tool,
190
                'access_date' => $reallyNow,
191
                'access_session_id' => $sessionId,
192
            ];
193
            Database::insert($tableLastAccess, $params);
194
        }
195
196
        return true;
197
    }
198
199
    /**
200
     * Record information for download event (when an user click to d/l a
201
     * document) it will be used in a redirection page.
202
     *
203
     * @param string $documentUrl
204
     *
205
     * @return int
206
     *
207
     * @author Sebastien Piraux <[email protected]>
208
     * @author Evie Embrechts (bug fixed: The user id is put in single quotes)
209
     */
210
    public static function event_download($documentUrl)
211
    {
212
        if (Session::read('login_as')) {
213
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
214
        }
215
216
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
217
        $documentUrl = Database::escape_string($documentUrl);
218
219
        $reallyNow = api_get_utc_datetime();
220
        $userId = api_get_user_id();
221
        $courseId = api_get_course_int_id();
222
        $sessionId = api_get_session_id();
223
224
        $sql = "INSERT INTO $table (
225
                 down_user_id,
226
                 c_id,
227
                 down_doc_path,
228
                 down_date,
229
                 down_session_id
230
                )
231
                VALUES (
232
                 $userId,
233
                 $courseId,
234
                 '$documentUrl',
235
                 '$reallyNow',
236
                 $sessionId
237
                )";
238
        Database::query($sql);
239
240
        return 1;
241
    }
242
243
    /**
244
     * @param int $documentId of document (id in mainDb.document table)
245
     *
246
     * @author Sebastien Piraux <[email protected]>
247
     * @desc Record information for upload event
248
     * used in the works tool to record informations when
249
     * an user upload 1 work
250
     *
251
     * @return int
252
     */
253
    public static function event_upload($documentId)
254
    {
255
        if (Session::read('login_as')) {
256
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
257
        }
258
259
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_UPLOADS);
260
        $courseId = api_get_course_int_id();
261
        $reallyNow = api_get_utc_datetime();
262
        $userId = api_get_user_id();
263
        $documentId = (int) $documentId;
264
        $sessionId = api_get_session_id();
265
266
        $sql = "INSERT INTO $table
267
                ( upload_user_id,
268
                  c_id,
269
                  upload_work_id,
270
                  upload_date,
271
                  upload_session_id
272
                )
273
                VALUES (
274
                 $userId,
275
                 $courseId,
276
                 $documentId,
277
                 '$reallyNow',
278
                 $sessionId
279
                )";
280
        Database::query($sql);
281
282
        return 1;
283
    }
284
285
    /**
286
     * Record information for link event (when an user click on an added link)
287
     * it will be used in a redirection page.
288
     *
289
     * @param int $linkId (id in c_link table)
290
     *
291
     * @return int
292
     *
293
     * @author Sebastien Piraux <[email protected]>
294
     */
295
    public static function event_link($linkId)
296
    {
297
        if (Session::read('login_as')) {
298
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
299
        }
300
301
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
302
        $reallyNow = api_get_utc_datetime();
303
        $userId = api_get_user_id();
304
        $courseId = api_get_course_int_id();
305
        $linkId = (int) $linkId;
306
        $sessionId = api_get_session_id();
307
        $sql = "INSERT INTO ".$table."
308
                    ( links_user_id,
309
                     c_id,
310
                     links_link_id,
311
                     links_date,
312
                     links_session_id
313
                    ) VALUES (
314
                     $userId,
315
                     $courseId,
316
                     $linkId,
317
                     '$reallyNow',
318
                     $sessionId
319
                    )";
320
        Database::query($sql);
321
322
        return 1;
323
    }
324
325
    /**
326
     * Update the TRACK_E_EXERCICES exercises.
327
     *
328
     * @param   int     exeid id of the attempt
329
     * @param   int     exo_id    exercise id
330
     * @param   mixed   result    score
331
     * @param   int     weighting ( higher score )
332
     * @param   int     duration ( duration of the attempt in seconds )
333
     * @param   int     session_id
334
     * @param   int     learnpath_id (id of the learnpath)
335
     * @param   int     learnpath_item_id (id of the learnpath_item)
336
     *
337
     * @return bool
338
     *
339
     * @author Sebastien Piraux <[email protected]>
340
     * @author Julio Montoya Armas <[email protected]> Reworked 2010
341
     * @desc Record result of user when an exercise was done
342
     */
343
    public static function updateEventExercise(
344
        $exeId,
345
        $exoId,
346
        $score,
347
        $weighting,
348
        $sessionId,
349
        $learnpathId = 0,
350
        $learnpathItemId = 0,
351
        $learnpathItemViewId = 0,
352
        $duration = 0,
353
        $questionsList = [],
354
        $status = '',
355
        $remindList = [],
356
        $endDate = null
357
    ) {
358
        if (empty($exeId)) {
359
            return false;
360
        }
361
362
        /*
363
         * Code commented due BT#8423 do not change the score to 0.
364
         *
365
         * Validation in case of fraud with actived control time
366
        if (!ExerciseLib::exercise_time_control_is_valid($exo_id, $learnpath_id, $learnpath_item_id)) {
367
            $score = 0;
368
        }
369
        */
370
        if (!isset($status) || empty($status)) {
371
            $status = '';
372
        } else {
373
            $status = Database::escape_string($status);
374
        }
375
376
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
377
378
        if (!empty($questionsList)) {
379
            $questionsList = array_map('intval', $questionsList);
380
        }
381
382
        if (!empty($remindList)) {
383
            $remindList = array_map('intval', $remindList);
384
            $remindList = array_filter($remindList);
385
            $remindList = implode(",", $remindList);
386
        } else {
387
            $remindList = '';
388
        }
389
390
        if (empty($endDate)) {
391
            $endDate = api_get_utc_datetime();
392
        }
393
        $exoId = (int) $exoId;
394
        $sessionId = (int) $sessionId;
395
        $learnpathId = (int) $learnpathId;
396
        $learnpathItemId = (int) $learnpathItemId;
397
        $learnpathItemViewId = (int) $learnpathItemViewId;
398
        $duration = (int) $duration;
399
        $exeId = (int) $exeId;
400
        $score = Database::escape_string($score);
401
        $weighting = Database::escape_string($weighting);
402
        $questions = implode(',', $questionsList);
403
        $userIp = Database::escape_string(api_get_real_ip());
404
405
        $sql = "UPDATE $table SET
406
               exe_exo_id = $exoId,
407
               score = '$score',
408
               max_score = '$weighting',
409
               session_id = $sessionId,
410
               orig_lp_id = $learnpathId,
411
               orig_lp_item_id = $learnpathItemId,
412
               orig_lp_item_view_id = $learnpathItemViewId,
413
               exe_duration = $duration,
414
               exe_date = '$endDate',
415
               status = '$status',
416
               questions_to_check = '$remindList',
417
               data_tracking = '$questions',
418
               user_ip = '$userIp'
419
             WHERE exe_id = $exeId";
420
        Database::query($sql);
421
422
        //Deleting control time session track
423
        //ExerciseLib::exercise_time_control_delete($exo_id);
424
        return true;
425
    }
426
427
    /**
428
     * Record an event for this attempt at answering an exercise.
429
     *
430
     * @param    float    Score achieved
431
     * @param    string    Answer given
432
     * @param    int    Question ID
433
     * @param    int Exercise attempt ID a.k.a exe_id (from track_e_exercise)
434
     * @param    int    Position
435
     * @param    int Exercise ID (from c_quiz)
436
     * @param    bool update results?
437
     * @param $fileName string  Filename (for audio answers - using nanogong)
438
     * @param    int User ID The user who's going to get this score. Default value of null means "get from context".
439
     * @param    int Course ID (from the "id" column of course table). Default value of null means "get from context".
440
     * @param    int Session ID (from the session table). Default value of null means "get from context".
441
     * @param    int Learnpath ID (from c_lp table). Default value of null means "get from context".
442
     * @param    int Learnpath item ID (from the c_lp_item table). Default value of null means "get from context".
443
     *
444
     * @return bool Result of the insert query
445
     */
446
    public static function saveQuestionAttempt(
447
        $score,
448
        $answer,
449
        $question_id,
450
        $exe_id,
451
        $position,
452
        $exercise_id = 0,
453
        $updateResults = false,
454
        $fileName = null,
455
        $user_id = null,
456
        $course_id = null,
457
        $session_id = null,
458
        $learnpath_id = null,
459
        $learnpath_item_id = null
460
    ) {
461
        global $debug;
462
        $question_id = Database::escape_string($question_id);
463
        $exe_id = Database::escape_string($exe_id);
464
        $position = Database::escape_string($position);
465
        $now = api_get_utc_datetime();
466
467
        // check user_id or get from context
468
        if (empty($user_id)) {
469
            $user_id = api_get_user_id();
470
            // anonymous
471
            if (empty($user_id)) {
472
                $user_id = api_get_anonymous_id();
473
            }
474
        }
475
        // check course_id or get from context
476
        if (empty($course_id) or intval($course_id) != $course_id) {
477
            $course_id = api_get_course_int_id();
478
        }
479
        // check session_id or get from context
480
        if (empty($session_id)) {
481
            $session_id = api_get_session_id();
482
        }
483
        // check learnpath_id or get from context
484
        if (empty($learnpath_id)) {
485
            global $learnpath_id;
486
        }
487
        // check learnpath_item_id or get from context
488
        if (empty($learnpath_item_id)) {
489
            global $learnpath_item_id;
490
        }
491
492
        $TBL_TRACK_ATTEMPT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
493
494
        if ($debug) {
495
            error_log("----- entering saveQuestionAttempt() function ------");
496
            error_log("answer: $answer");
497
            error_log("score: $score");
498
            error_log("question_id : $question_id");
499
            error_log("position: $position");
500
        }
501
502
        //Validation in case of fraud with active control time
503
        if (!ExerciseLib::exercise_time_control_is_valid($exercise_id, $learnpath_id, $learnpath_item_id)) {
504
            if ($debug) {
505
                error_log("exercise_time_control_is_valid is false");
506
            }
507
            $score = 0;
508
            $answer = 0;
509
        }
510
511
        $session_id = api_get_session_id();
512
513
        if (!empty($question_id) && !empty($exe_id) && !empty($user_id)) {
514
            if (is_null($answer)) {
515
                $answer = '';
516
            }
517
518
            if (is_null($score)) {
519
                $score = 0;
520
            }
521
522
            $attempt = [
523
                'user_id' => $user_id,
524
                'question_id' => $question_id,
525
                'answer' => $answer,
526
                'marks' => $score,
527
                'c_id' => $course_id,
528
                'session_id' => $session_id,
529
                'position' => $position,
530
                'tms' => $now,
531
                'filename' => !empty($fileName) ? basename($fileName) : $fileName,
532
                'teacher_comment' => '',
533
            ];
534
535
            // Check if attempt exists.
536
            $sql = "SELECT exe_id FROM $TBL_TRACK_ATTEMPT
537
                    WHERE
538
                        c_id = $course_id AND
539
                        session_id = $session_id AND
540
                        exe_id = $exe_id AND
541
                        user_id = $user_id AND
542
                        question_id = $question_id AND
543
                        position = $position";
544
            $result = Database::query($sql);
545
            if (Database::num_rows($result)) {
546
                if ($debug) {
547
                    error_log("Attempt already exist: exe_id: $exe_id - user_id:$user_id - question_id:$question_id");
548
                }
549
                if ($updateResults == false) {
550
                    //The attempt already exist do not update use  update_event_exercise() instead
551
                    return false;
552
                }
553
            } else {
554
                $attempt['exe_id'] = $exe_id;
555
            }
556
557
            if ($debug) {
558
                error_log("updateResults : $updateResults");
559
                error_log("Saving question attempt: ");
560
                error_log($sql);
561
            }
562
563
            $recording_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
564
565
            if ($updateResults == false) {
566
                $attempt_id = Database::insert($TBL_TRACK_ATTEMPT, $attempt);
567
568
                if ($debug) {
569
                    error_log("Insert attempt with id #$attempt_id");
570
                }
571
572
                if (defined('ENABLED_LIVE_EXERCISE_TRACKING')) {
573
                    if ($debug) {
574
                        error_log("Saving e attempt recording ");
575
                    }
576
                    $attempt_recording = [
577
                        'exe_id' => $attempt_id,
578
                        'question_id' => $question_id,
579
                        'marks' => $score,
580
                        'insert_date' => $now,
581
                        'author' => '',
582
                        'session_id' => $session_id,
583
                    ];
584
                    Database::insert($recording_table, $attempt_recording);
585
                }
586
            } else {
587
                Database::update(
588
                    $TBL_TRACK_ATTEMPT,
589
                    $attempt,
590
                    [
591
                        'exe_id = ? AND question_id = ? AND user_id = ? ' => [
592
                            $exe_id,
593
                            $question_id,
594
                            $user_id,
595
                        ],
596
                    ]
597
                );
598
599
                if (defined('ENABLED_LIVE_EXERCISE_TRACKING')) {
600
                    $attempt_recording = [
601
                        'exe_id' => $exe_id,
602
                        'question_id' => $question_id,
603
                        'marks' => $score,
604
                        'insert_date' => $now,
605
                        'author' => '',
606
                        'session_id' => $session_id,
607
                    ];
608
609
                    Database::update(
610
                        $recording_table,
611
                        $attempt_recording,
612
                        [
613
                            'exe_id = ? AND question_id = ? AND session_id = ? ' => [
614
                                $exe_id,
615
                                $question_id,
616
                                $session_id,
617
                            ],
618
                        ]
619
                    );
620
                }
621
                $attempt_id = $exe_id;
622
            }
623
624
            return $attempt_id;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $attempt_id also could return the type integer|string which is incompatible with the documented return type boolean.
Loading history...
625
        } else {
626
            return false;
627
        }
628
    }
629
630
    /**
631
     * Record an hotspot spot for this attempt at answering an hotspot question.
632
     *
633
     * @param int    $exeId
634
     * @param int    $questionId    Question ID
635
     * @param int    $answerId      Answer ID
636
     * @param int    $correct
637
     * @param string $coords        Coordinates of this point (e.g. 123;324)
638
     * @param bool   $updateResults
639
     * @param int    $exerciseId
640
     *
641
     * @return bool Result of the insert query
642
     *
643
     * @uses \Course code and user_id from global scope $_cid and $_user
644
     */
645
    public static function saveExerciseAttemptHotspot(
646
        $exeId,
647
        $questionId,
648
        $answerId,
649
        $correct,
650
        $coords,
651
        $updateResults = false,
652
        $exerciseId = 0
653
    ) {
654
        $debug = false;
655
        global $safe_lp_id, $safe_lp_item_id;
656
657
        if ($updateResults == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
658
            // Validation in case of fraud with activated control time
659
            if (!ExerciseLib::exercise_time_control_is_valid($exerciseId, $safe_lp_id, $safe_lp_item_id)) {
660
                if ($debug) {
661
                    error_log('Attempt is fraud');
662
                }
663
                $correct = 0;
664
            }
665
        }
666
667
        if (empty($exeId)) {
668
            if ($debug) {
669
                error_log('exe id is empty');
670
            }
671
672
            return false;
673
        }
674
675
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT);
676
        if ($updateResults) {
677
            if ($debug) {
678
                error_log("Insert hotspot results: exeId: $exeId correct: $correct");
679
            }
680
            $params = [
681
                'hotspot_correct' => $correct,
682
                'hotspot_coordinate' => $coords,
683
            ];
684
            Database::update(
685
                $table,
686
                $params,
687
                [
688
                    'hotspot_user_id = ? AND hotspot_exe_id = ? AND hotspot_question_id = ? AND hotspot_answer_id = ? ' => [
689
                        api_get_user_id(),
690
                        $exeId,
691
                        $questionId,
692
                        $answerId,
693
                    ],
694
                ]
695
            );
696
        } else {
697
            if ($debug) {
698
                error_log("Insert hotspot results: exeId: $exeId correct: $correct");
699
            }
700
701
            return Database::insert(
0 ignored issues
show
Bug Best Practice introduced by
The expression return Database::insert(...oordinate' => $coords)) also could return the type integer which is incompatible with the documented return type boolean.
Loading history...
702
                $table,
703
                [
704
                    'hotspot_user_id' => api_get_user_id(),
705
                    'c_id' => api_get_course_int_id(),
706
                    'hotspot_exe_id' => $exeId,
707
                    'hotspot_question_id' => $questionId,
708
                    'hotspot_answer_id' => $answerId,
709
                    'hotspot_correct' => $correct,
710
                    'hotspot_coordinate' => $coords,
711
                ]
712
            );
713
        }
714
    }
715
716
    /**
717
     * Records information for common (or admin) events (in the track_e_default table).
718
     *
719
     * @author Yannick Warnier <[email protected]>
720
     *
721
     * @param string $event_type       Type of event
722
     * @param string $event_value_type Type of value
723
     * @param mixed  $event_value      Value (string, or array in the case of user info)
724
     * @param string $datetime         Datetime (UTC) (defaults to null)
725
     * @param int    $user_id          User ID (defaults to null)
726
     * @param int    $course_id        Course ID (defaults to null)
727
     * @param int    $sessionId        Session ID
728
     *
729
     * @return bool
730
     * @assert ('','','') === false
731
     */
732
    public static function addEvent(
733
        $event_type,
734
        $event_value_type,
735
        $event_value,
736
        $datetime = null,
737
        $user_id = null,
738
        $course_id = null,
739
        $sessionId = 0
740
    ) {
741
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DEFAULT);
742
743
        if (empty($event_type)) {
744
            return false;
745
        }
746
        $event_type = Database::escape_string($event_type);
747
        $event_value_type = Database::escape_string($event_value_type);
748
        if (!empty($course_id)) {
749
            $course_id = (int) $course_id;
750
        } else {
751
            $course_id = api_get_course_int_id();
752
        }
753
        if (!empty($sessionId)) {
754
            $sessionId = (int) $sessionId;
755
        } else {
756
            $sessionId = api_get_session_id();
757
        }
758
759
        //Clean the user_info
760
        if ($event_value_type == LOG_USER_OBJECT) {
761
            if (is_array($event_value)) {
762
                unset($event_value['complete_name']);
763
                unset($event_value['complete_name_with_username']);
764
                unset($event_value['firstName']);
765
                unset($event_value['lastName']);
766
                unset($event_value['avatar_small']);
767
                unset($event_value['avatar']);
768
                unset($event_value['mail']);
769
                unset($event_value['password']);
770
                unset($event_value['last_login']);
771
                unset($event_value['picture_uri']);
772
                $event_value = serialize($event_value);
773
            }
774
        }
775
        // If event is an array then the $event_value_type should finish with
776
        // the suffix _array for example LOG_WORK_DATA = work_data_array
777
        if (is_array($event_value)) {
778
            $event_value = serialize($event_value);
779
        }
780
781
        $event_value = Database::escape_string($event_value);
782
        $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
783
784
        if (!isset($datetime)) {
785
            $datetime = api_get_utc_datetime();
786
        }
787
788
        $datetime = Database::escape_string($datetime);
789
790
        if (!isset($user_id)) {
791
            $user_id = api_get_user_id();
792
        }
793
794
        $params = [
795
            'default_user_id' => $user_id,
796
            'c_id' => $course_id,
797
            'default_date' => $datetime,
798
            'default_event_type' => $event_type,
799
            'default_value_type' => $event_value_type,
800
            'default_value' => $event_value,
801
            'session_id' => $sessionId,
802
        ];
803
        Database::insert($table, $params);
804
805
        return true;
806
    }
807
808
    /**
809
     * Gets the last attempt of an exercise based in the exe_id.
810
     *
811
     * @param int $exeId
812
     *
813
     * @return mixed
814
     */
815
    public static function getLastAttemptDateOfExercise($exeId)
816
    {
817
        $exeId = (int) $exeId;
818
        $track_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
819
        $sql = "SELECT max(tms) as last_attempt_date
820
                FROM $track_attempts
821
                WHERE exe_id = $exeId";
822
        $rs_last_attempt = Database::query($sql);
823
        $row_last_attempt = Database::fetch_array($rs_last_attempt);
824
        $date = $row_last_attempt['last_attempt_date']; //Get the date of last attempt
825
826
        return $date;
827
    }
828
829
    /**
830
     * Gets the last attempt of an exercise based in the exe_id.
831
     *
832
     * @param int $exeId
833
     *
834
     * @return mixed
835
     */
836
    public static function getLatestQuestionIdFromAttempt($exeId)
837
    {
838
        $exeId = (int) $exeId;
839
        $track_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
840
        $sql = "SELECT question_id FROM $track_attempts
841
                WHERE exe_id = $exeId
842
                ORDER BY tms DESC
843
                LIMIT 1";
844
        $result = Database::query($sql);
845
        if (Database::num_rows($result)) {
846
            $row = Database::fetch_array($result);
847
848
            return $row['question_id'];
849
        } else {
850
            return false;
851
        }
852
    }
853
854
    /**
855
     * Gets how many attempts exists by user, exercise, learning path.
856
     *
857
     * @param   int user id
858
     * @param   int exercise id
859
     * @param   int lp id
860
     * @param   int lp item id
861
     * @param   int lp item view id
862
     *
863
     * @return int
864
     */
865
    public static function get_attempt_count(
866
        $user_id,
867
        $exerciseId,
868
        $lp_id,
869
        $lp_item_id,
870
        $lp_item_view_id
871
    ) {
872
        $stat_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
873
        $user_id = (int) $user_id;
874
        $exerciseId = (int) $exerciseId;
875
        $lp_id = (int) $lp_id;
876
        $lp_item_id = (int) $lp_item_id;
877
        $lp_item_view_id = (int) $lp_item_view_id;
878
        $courseId = api_get_course_int_id();
879
        $sessionId = api_get_session_id();
880
881
        $sql = "SELECT count(*) as count
882
                FROM $stat_table
883
                WHERE
884
                    exe_exo_id = $exerciseId AND
885
                    exe_user_id = $user_id AND
886
                    status != 'incomplete' AND
887
                    orig_lp_id = $lp_id AND
888
                    orig_lp_item_id = $lp_item_id AND
889
                    orig_lp_item_view_id = $lp_item_view_id AND
890
                    c_id = $courseId AND
891
                    session_id = $sessionId";
892
893
        $query = Database::query($sql);
894
        if (Database::num_rows($query) > 0) {
895
            $attempt = Database::fetch_array($query, 'ASSOC');
896
897
            return $attempt['count'];
898
        } else {
899
            return 0;
900
        }
901
    }
902
903
    /**
904
     * @param $user_id
905
     * @param $exerciseId
906
     * @param $lp_id
907
     * @param $lp_item_id
908
     *
909
     * @return int
910
     */
911
    public static function get_attempt_count_not_finished(
912
        $user_id,
913
        $exerciseId,
914
        $lp_id,
915
        $lp_item_id
916
    ) {
917
        $stat_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
918
        $user_id = (int) $user_id;
919
        $exerciseId = (int) $exerciseId;
920
        $lp_id = (int) $lp_id;
921
        $lp_item_id = (int) $lp_item_id;
922
        //$lp_item_view_id = (int) $lp_item_view_id;
923
        $courseId = api_get_course_int_id();
924
        $sessionId = api_get_session_id();
925
926
        $sql = "SELECT count(*) as count
927
                FROM $stat_table
928
                WHERE
929
                    exe_exo_id 			= $exerciseId AND
930
                    exe_user_id 		= $user_id AND
931
                    status 				!= 'incomplete' AND
932
                    orig_lp_id 			= $lp_id AND
933
                    orig_lp_item_id 	= $lp_item_id AND
934
                    c_id = $courseId AND
935
                    session_id = $sessionId";
936
937
        $query = Database::query($sql);
938
        if (Database::num_rows($query) > 0) {
939
            $attempt = Database::fetch_array($query, 'ASSOC');
940
941
            return $attempt['count'];
942
        } else {
943
            return 0;
944
        }
945
    }
946
947
    /**
948
     * @param int   $user_id
949
     * @param int   $lp_id
950
     * @param array $course
951
     * @param int   $session_id
952
     */
953
    public static function delete_student_lp_events(
954
        $user_id,
955
        $lp_id,
956
        $course,
957
        $session_id
958
    ) {
959
        $lp_view_table = Database::get_course_table(TABLE_LP_VIEW);
960
        $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW);
961
        $lpInteraction = Database::get_course_table(TABLE_LP_IV_INTERACTION);
962
        $lpObjective = Database::get_course_table(TABLE_LP_IV_OBJECTIVE);
963
964
        $course_id = $course['real_id'];
965
966
        if (empty($course_id)) {
967
            $course_id = api_get_course_int_id();
968
        }
969
970
        $track_e_exercises = Database::get_main_table(
971
            TABLE_STATISTIC_TRACK_E_EXERCISES
972
        );
973
        $track_attempts = Database::get_main_table(
974
            TABLE_STATISTIC_TRACK_E_ATTEMPT
975
        );
976
        $recording_table = Database::get_main_table(
977
            TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING
978
        );
979
980
        $user_id = (int) $user_id;
981
        $lp_id = (int) $lp_id;
982
        $session_id = (int) $session_id;
983
984
        //Make sure we have the exact lp_view_id
985
        $sql = "SELECT id FROM $lp_view_table
986
                WHERE
987
                    c_id = $course_id AND
988
                    user_id = $user_id AND
989
                    lp_id = $lp_id AND
990
                    session_id = $session_id";
991
        $result = Database::query($sql);
992
993
        if (Database::num_rows($result)) {
994
            $view = Database::fetch_array($result, 'ASSOC');
995
            $lp_view_id = $view['id'];
996
997
            $sql = "DELETE FROM $lp_item_view_table
998
                    WHERE c_id = $course_id AND lp_view_id = $lp_view_id";
999
            Database::query($sql);
1000
1001
            $sql = "DELETE FROM $lpInteraction
1002
                    WHERE c_id = $course_id AND lp_iv_id = $lp_view_id";
1003
            Database::query($sql);
1004
1005
            $sql = "DELETE FROM $lpObjective
1006
                    WHERE c_id = $course_id AND lp_iv_id = $lp_view_id";
1007
            Database::query($sql);
1008
        }
1009
1010
        $sql = "DELETE FROM $lp_view_table
1011
                WHERE
1012
                    c_id = $course_id AND
1013
                    user_id = $user_id AND
1014
                    lp_id= $lp_id AND
1015
                    session_id = $session_id
1016
            ";
1017
        Database::query($sql);
1018
1019
        $sql = "SELECT exe_id FROM $track_e_exercises
1020
                WHERE   
1021
                    exe_user_id = $user_id AND
1022
                    session_id = $session_id AND
1023
                    c_id = $course_id AND
1024
                    orig_lp_id = $lp_id";
1025
        $result = Database::query($sql);
1026
        $exe_list = [];
1027
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1028
            $exe_list[] = $row['exe_id'];
1029
        }
1030
1031
        if (!empty($exe_list) && is_array($exe_list) && count($exe_list) > 0) {
1032
            $exeListString = implode(',', $exe_list);
1033
            $sql = "DELETE FROM $track_e_exercises
1034
                WHERE exe_id IN ($exeListString)";
1035
            Database::query($sql);
1036
1037
            $sql = "DELETE FROM $track_attempts
1038
                WHERE exe_id IN ($exeListString)";
1039
            Database::query($sql);
1040
1041
            $sql = "DELETE FROM $recording_table
1042
                WHERE exe_id IN ($exeListString)";
1043
            Database::query($sql);
1044
        }
1045
1046
        self::addEvent(
1047
            LOG_LP_ATTEMPT_DELETE,
1048
            LOG_LP_ID,
1049
            $lp_id,
1050
            null,
1051
            null,
1052
            $course_id,
1053
            $session_id
1054
        );
1055
    }
1056
1057
    /**
1058
     * Delete all exercise attempts (included in LP or not).
1059
     *
1060
     * @param int user id
1061
     * @param int exercise id
1062
     * @param int $course_id
1063
     * @param int session id
1064
     */
1065
    public static function delete_all_incomplete_attempts(
1066
        $user_id,
1067
        $exercise_id,
1068
        $course_id,
1069
        $session_id = 0
1070
    ) {
1071
        $track_e_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1072
        $user_id = (int) $user_id;
1073
        $exercise_id = (int) $exercise_id;
1074
        $course_id = (int) $course_id;
1075
        $session_id = (int) $session_id;
1076
        if (!empty($user_id) && !empty($exercise_id) && !empty($course_code)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $course_code does not exist. Did you maybe mean $course_id?
Loading history...
1077
            $sql = "DELETE FROM $track_e_exercises
1078
                    WHERE
1079
                        exe_user_id = $user_id AND
1080
                        exe_exo_id = $exercise_id AND
1081
                        c_id = $course_id AND
1082
                        session_id = $session_id AND
1083
                        status = 'incomplete' ";
1084
            Database::query($sql);
1085
            self::addEvent(
1086
                LOG_EXERCISE_RESULT_DELETE,
1087
                LOG_EXERCISE_AND_USER_ID,
1088
                $exercise_id.'-'.$user_id,
1089
                null,
1090
                null,
1091
                $course_id,
1092
                $session_id
1093
            );
1094
        }
1095
    }
1096
1097
    /**
1098
     * Gets all exercise results (NO Exercises in LPs ) from a given exercise id, course, session.
1099
     *
1100
     * @param   int     exercise id
1101
     * @param int $courseId
1102
     * @param   int     session id
1103
     *
1104
     * @return array with the results
1105
     */
1106
    public static function get_all_exercise_results(
1107
        $exercise_id,
1108
        $courseId,
1109
        $session_id = 0,
1110
        $load_question_list = true,
1111
        $user_id = null
1112
    ) {
1113
        $TABLETRACK_EXERCICES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1114
        $TBL_TRACK_ATTEMPT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1115
        $courseId = (int) $courseId;
1116
        $exercise_id = (int) $exercise_id;
1117
        $session_id = (int) $session_id;
1118
1119
        $user_condition = null;
1120
        if (!empty($user_id)) {
1121
            $user_id = (int) $user_id;
1122
            $user_condition = "AND exe_user_id = $user_id ";
1123
        }
1124
        $sql = "SELECT * FROM $TABLETRACK_EXERCICES
1125
                WHERE
1126
                    status = ''  AND
1127
                    c_id = $courseId AND
1128
                    exe_exo_id = $exercise_id AND
1129
                    session_id = $session_id  AND
1130
                    orig_lp_id =0 AND
1131
                    orig_lp_item_id = 0
1132
                    $user_condition
1133
                ORDER BY exe_id";
1134
        $res = Database::query($sql);
1135
        $list = [];
1136
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1137
            $list[$row['exe_id']] = $row;
1138
            if ($load_question_list) {
1139
                $sql = "SELECT * FROM $TBL_TRACK_ATTEMPT
1140
                        WHERE exe_id = {$row['exe_id']}";
1141
                $res_question = Database::query($sql);
1142
                while ($row_q = Database::fetch_array($res_question, 'ASSOC')) {
1143
                    $list[$row['exe_id']]['question_list'][$row_q['question_id']] = $row_q;
1144
                }
1145
            }
1146
        }
1147
1148
        return $list;
1149
    }
1150
1151
    /**
1152
     * Gets all exercise results (NO Exercises in LPs ) from a given exercise id, course, session.
1153
     *
1154
     * @param int $courseId
1155
     * @param   int     session id
1156
     * @param bool $get_count
1157
     *
1158
     * @return array with the results
1159
     */
1160
    public static function get_all_exercise_results_by_course(
1161
        $courseId,
1162
        $session_id = 0,
1163
        $get_count = true
1164
    ) {
1165
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1166
        $courseId = (int) $courseId;
1167
        $session_id = (int) $session_id;
1168
1169
        $select = '*';
1170
        if ($get_count) {
1171
            $select = 'count(*) as count';
1172
        }
1173
        $sql = "SELECT $select FROM $table_track_exercises
1174
                WHERE   status = ''  AND
1175
                        c_id = $courseId AND
1176
                        session_id = $session_id  AND
1177
                        orig_lp_id = 0 AND
1178
                        orig_lp_item_id = 0
1179
                ORDER BY exe_id";
1180
        $res = Database::query($sql);
1181
        if ($get_count) {
1182
            $row = Database::fetch_array($res, 'ASSOC');
1183
1184
            return $row['count'];
1185
        } else {
1186
            $list = [];
1187
            while ($row = Database::fetch_array($res, 'ASSOC')) {
1188
                $list[$row['exe_id']] = $row;
1189
            }
1190
1191
            return $list;
1192
        }
1193
    }
1194
1195
    /**
1196
     * Gets all exercise results (NO Exercises in LPs) from a given exercise id, course, session.
1197
     *
1198
     * @param   int     exercise id
1199
     * @param int $courseId
1200
     * @param   int     session id
1201
     *
1202
     * @return array with the results
1203
     */
1204
    public static function get_all_exercise_results_by_user(
1205
        $user_id,
1206
        $courseId,
1207
        $session_id = 0
1208
    ) {
1209
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1210
        $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1211
        $courseId = (int) $courseId;
1212
        $session_id = (int) $session_id;
1213
        $user_id = (int) $user_id;
1214
1215
        $sql = "SELECT * FROM $table_track_exercises
1216
                WHERE
1217
                    status = '' AND
1218
                    exe_user_id = $user_id AND
1219
                    c_id = $courseId AND
1220
                    session_id = $session_id AND
1221
                    orig_lp_id = 0 AND
1222
                    orig_lp_item_id = 0
1223
                ORDER by exe_id";
1224
1225
        $res = Database::query($sql);
1226
        $list = [];
1227
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1228
            $list[$row['exe_id']] = $row;
1229
            $sql = "SELECT * FROM $table_track_attempt 
1230
                    WHERE exe_id = {$row['exe_id']}";
1231
            $res_question = Database::query($sql);
1232
            while ($row_q = Database::fetch_array($res_question, 'ASSOC')) {
1233
                $list[$row['exe_id']]['question_list'][$row_q['question_id']] = $row_q;
1234
            }
1235
        }
1236
1237
        return $list;
1238
    }
1239
1240
    /**
1241
     * Gets exercise results (NO Exercises in LPs) from a given exercise id, course, session.
1242
     *
1243
     * @param int    $exe_id exercise id
1244
     * @param string $status
1245
     *
1246
     * @return array with the results
1247
     */
1248
    public static function get_exercise_results_by_attempt($exe_id, $status = null)
1249
    {
1250
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1251
        $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1252
        $table_track_attempt_recording = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
1253
        $exe_id = (int) $exe_id;
1254
1255
        $status = Database::escape_string($status);
1256
1257
        $sql = "SELECT * FROM $table_track_exercises
1258
                WHERE status = '$status' AND exe_id = $exe_id";
1259
1260
        $res = Database::query($sql);
1261
        $list = [];
1262
        if (Database::num_rows($res)) {
1263
            $row = Database::fetch_array($res, 'ASSOC');
1264
1265
            //Checking if this attempt was revised by a teacher
1266
            $sql_revised = "SELECT exe_id FROM $table_track_attempt_recording
1267
                            WHERE author != '' AND exe_id = $exe_id 
1268
                            LIMIT 1";
1269
            $res_revised = Database::query($sql_revised);
1270
            $row['attempt_revised'] = 0;
1271
            if (Database::num_rows($res_revised) > 0) {
1272
                $row['attempt_revised'] = 1;
1273
            }
1274
            $list[$exe_id] = $row;
1275
            $sql = "SELECT * FROM $table_track_attempt
1276
                    WHERE exe_id = $exe_id 
1277
                    ORDER BY tms ASC";
1278
            $res_question = Database::query($sql);
1279
            while ($row_q = Database::fetch_array($res_question, 'ASSOC')) {
1280
                $list[$exe_id]['question_list'][$row_q['question_id']] = $row_q;
1281
            }
1282
        }
1283
1284
        return $list;
1285
    }
1286
1287
    /**
1288
     * Gets exercise results (NO Exercises in LPs) from a given user, exercise id, course, session, lp_id, lp_item_id.
1289
     *
1290
     * @param   int     user id
1291
     * @param   int     exercise id
1292
     * @param   string  course code
1293
     * @param   int     session id
1294
     * @param   int     lp id
1295
     * @param   int     lp item id
1296
     * @param   string order asc or desc
1297
     *
1298
     * @return array with the results
1299
     */
1300
    public static function getExerciseResultsByUser(
1301
        $user_id,
1302
        $exercise_id,
1303
        $courseId,
1304
        $session_id = 0,
1305
        $lp_id = 0,
1306
        $lp_item_id = 0,
1307
        $order = null
1308
    ) {
1309
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1310
        $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1311
        $table_track_attempt_recording = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
1312
        $courseId = (int) $courseId;
1313
        $exercise_id = (int) $exercise_id;
1314
        $session_id = (int) $session_id;
1315
        $user_id = (int) $user_id;
1316
        $lp_id = (int) $lp_id;
1317
        $lp_item_id = (int) $lp_item_id;
1318
1319
        if (!in_array(strtolower($order), ['asc', 'desc'])) {
1320
            $order = 'asc';
1321
        }
1322
1323
        $sql = "SELECT * FROM $table_track_exercises
1324
                WHERE
1325
                    status 			= '' AND
1326
                    exe_user_id 	= $user_id AND
1327
                    c_id 	        = $courseId AND
1328
                    exe_exo_id 		= $exercise_id AND
1329
                    session_id 		= $session_id AND
1330
                    orig_lp_id 		= $lp_id AND
1331
                    orig_lp_item_id = $lp_item_id
1332
                ORDER by exe_id $order ";
1333
1334
        $res = Database::query($sql);
1335
        $list = [];
1336
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1337
            // Checking if this attempt was revised by a teacher
1338
            $exeId = $row['exe_id'];
1339
            $sql = "SELECT exe_id FROM $table_track_attempt_recording
1340
                    WHERE author != '' AND exe_id = $exeId
1341
                    LIMIT 1";
1342
            $res_revised = Database::query($sql);
1343
            $row['attempt_revised'] = 0;
1344
            if (Database::num_rows($res_revised) > 0) {
1345
                $row['attempt_revised'] = 1;
1346
            }
1347
            $list[$row['exe_id']] = $row;
1348
            $sql = "SELECT * FROM $table_track_attempt
1349
                    WHERE exe_id = $exeId";
1350
            $res_question = Database::query($sql);
1351
            while ($row_q = Database::fetch_array($res_question, 'ASSOC')) {
1352
                $list[$row['exe_id']]['question_list'][$row_q['question_id']][] = $row_q;
1353
            }
1354
        }
1355
1356
        return $list;
1357
    }
1358
1359
    /**
1360
     * Count exercise attempts (NO Exercises in LPs ) from a given exercise id, course, session.
1361
     *
1362
     * @param int $user_id
1363
     * @param   int     exercise id
1364
     * @param int $courseId
1365
     * @param   int     session id
1366
     *
1367
     * @return array with the results
1368
     */
1369
    public static function count_exercise_attempts_by_user(
1370
        $user_id,
1371
        $exercise_id,
1372
        $courseId,
1373
        $session_id = 0
1374
    ) {
1375
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1376
        $courseId = (int) $courseId;
1377
        $exercise_id = (int) $exercise_id;
1378
        $session_id = (int) $session_id;
1379
        $user_id = (int) $user_id;
1380
1381
        $sql = "SELECT count(*) as count 
1382
                FROM $table
1383
                WHERE status = ''  AND
1384
                    exe_user_id = $user_id AND
1385
                    c_id = $courseId AND
1386
                    exe_exo_id = $exercise_id AND
1387
                    session_id = $session_id AND
1388
                    orig_lp_id =0 AND
1389
                    orig_lp_item_id = 0
1390
                ORDER BY exe_id";
1391
        $res = Database::query($sql);
1392
        $result = 0;
1393
        if (Database::num_rows($res) > 0) {
1394
            $row = Database::fetch_array($res, 'ASSOC');
1395
            $result = $row['count'];
1396
        }
1397
1398
        return $result;
1399
    }
1400
1401
    /**
1402
     * Gets all exercise BEST results attempts (NO Exercises in LPs)
1403
     * from a given exercise id, course, session per user.
1404
     *
1405
     * @param int $exercise_id
1406
     * @param int $courseId
1407
     * @param int $session_id
1408
     * @param int $userId
1409
     *
1410
     * @return array with the results
1411
     *
1412
     * @todo rename this function
1413
     */
1414
    public static function get_best_exercise_results_by_user(
1415
        $exercise_id,
1416
        $courseId,
1417
        $session_id = 0,
1418
        $userId = 0
1419
    ) {
1420
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1421
        $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1422
        $courseId = (int) $courseId;
1423
        $exercise_id = (int) $exercise_id;
1424
        $session_id = (int) $session_id;
1425
1426
        $sql = "SELECT * FROM $table_track_exercises
1427
                WHERE
1428
                    status = '' AND
1429
                    c_id = $courseId AND
1430
                    exe_exo_id = $exercise_id AND
1431
                    session_id = $session_id AND
1432
                    orig_lp_id = 0 AND
1433
                    orig_lp_item_id = 0";
1434
1435
        if (!empty($userId)) {
1436
            $userId = (int) $userId;
1437
            $sql .= " AND exe_user_id = $userId ";
1438
        }
1439
        $sql .= " ORDER BY exe_id";
1440
1441
        $res = Database::query($sql);
1442
        $list = [];
1443
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1444
            $list[$row['exe_id']] = $row;
1445
            $exeId = $row['exe_id'];
1446
            $sql = "SELECT * FROM $table_track_attempt 
1447
                    WHERE exe_id = $exeId";
1448
            $res_question = Database::query($sql);
1449
            while ($row_q = Database::fetch_array($res_question, 'ASSOC')) {
1450
                $list[$exeId]['question_list'][$row_q['question_id']] = $row_q;
1451
            }
1452
        }
1453
1454
        // Getting the best results of every student
1455
        $best_score_return = [];
1456
        foreach ($list as $student_result) {
1457
            $user_id = $student_result['exe_user_id'];
1458
            $current_best_score[$user_id] = $student_result['score'];
1459
            if (!isset($best_score_return[$user_id]['score'])) {
1460
                $best_score_return[$user_id] = $student_result;
1461
            }
1462
1463
            if ($current_best_score[$user_id] > $best_score_return[$user_id]['score']) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $current_best_score seems to be defined later in this foreach loop on line 1458. Are you sure it is defined here?
Loading history...
1464
                $best_score_return[$user_id] = $student_result;
1465
            }
1466
        }
1467
1468
        return $best_score_return;
1469
    }
1470
1471
    /**
1472
     * @param int $user_id
1473
     * @param int $exercise_id
1474
     * @param int $courseId
1475
     * @param int $session_id
1476
     *
1477
     * @return array
1478
     */
1479
    public static function get_best_attempt_exercise_results_per_user(
1480
        $user_id,
1481
        $exercise_id,
1482
        $courseId,
1483
        $session_id = 0
1484
    ) {
1485
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1486
        $courseId = (int) $courseId;
1487
        $exercise_id = (int) $exercise_id;
1488
        $session_id = (int) $session_id;
1489
        $user_id = (int) $user_id;
1490
1491
        $sql = "SELECT * FROM $table_track_exercises
1492
                WHERE
1493
                    status = ''  AND
1494
                    c_id = $courseId AND
1495
                    exe_exo_id = $exercise_id AND
1496
                    session_id = $session_id  AND
1497
                    exe_user_id = $user_id AND
1498
                    orig_lp_id = 0 AND
1499
                    orig_lp_item_id = 0
1500
                ORDER BY exe_id";
1501
1502
        $res = Database::query($sql);
1503
        $list = [];
1504
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1505
            $list[$row['exe_id']] = $row;
1506
        }
1507
        //Getting the best results of every student
1508
        $best_score_return = [];
1509
        $best_score_return['score'] = 0;
1510
1511
        foreach ($list as $result) {
1512
            $current_best_score = $result;
1513
            if ($current_best_score['score'] > $best_score_return['score']) {
1514
                $best_score_return = $result;
1515
            }
1516
        }
1517
        if (!isset($best_score_return['max_score'])) {
1518
            $best_score_return = [];
1519
        }
1520
1521
        return $best_score_return;
1522
    }
1523
1524
    /**
1525
     * @param int $exercise_id
1526
     * @param int $courseId
1527
     * @param int $session_id
1528
     *
1529
     * @return mixed
1530
     */
1531
    public static function count_exercise_result_not_validated(
1532
        $exercise_id,
1533
        $courseId,
1534
        $session_id = 0
1535
    ) {
1536
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1537
        $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
1538
        $courseId = (int) $courseId;
1539
        $session_id = (int) $session_id;
1540
        $exercise_id = (int) $exercise_id;
1541
1542
        $sql = "SELECT count(e.exe_id) as count
1543
                FROM $table_track_exercises e
1544
                LEFT JOIN $table_track_attempt a
1545
                ON e.exe_id = a.exe_id
1546
                WHERE
1547
                    exe_exo_id = $exercise_id AND
1548
                    c_id = $courseId AND
1549
                    e.session_id = $session_id  AND
1550
                    orig_lp_id = 0 AND
1551
                    marks IS NULL AND
1552
                    status = '' AND
1553
                    orig_lp_item_id = 0
1554
                ORDER BY e.exe_id";
1555
        $res = Database::query($sql);
1556
        $row = Database::fetch_array($res, 'ASSOC');
1557
1558
        return $row['count'];
1559
    }
1560
1561
    /**
1562
     * Gets all exercise BEST results attempts (NO Exercises in LPs)
1563
     * from a given exercise id, course, session per user.
1564
     *
1565
     * @param   int     exercise id
1566
     * @param   int   course id
1567
     * @param   int     session id
1568
     *
1569
     * @return array with the results
1570
     */
1571
    public static function get_count_exercises_attempted_by_course(
1572
        $courseId,
1573
        $session_id = 0
1574
    ) {
1575
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1576
        $courseId = (int) $courseId;
1577
        $session_id = (int) $session_id;
1578
1579
        $sql = "SELECT DISTINCT exe_exo_id, exe_user_id
1580
                FROM $table_track_exercises
1581
                WHERE
1582
                    status = '' AND
1583
                    c_id = $courseId AND
1584
                    session_id = $session_id AND
1585
                    orig_lp_id = 0 AND
1586
                    orig_lp_item_id = 0
1587
                ORDER BY exe_id";
1588
        $res = Database::query($sql);
1589
        $count = 0;
1590
        if (Database::num_rows($res) > 0) {
1591
            $count = Database::num_rows($res);
1592
        }
1593
1594
        return $count;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $count returns the type integer which is incompatible with the documented return type array.
Loading history...
1595
    }
1596
1597
    /**
1598
     * Gets all exercise events from a Learning Path within a Course    nd Session.
1599
     *
1600
     * @param int $exercise_id
1601
     * @param int $courseId
1602
     * @param int $session_id
1603
     *
1604
     * @return array
1605
     */
1606
    public static function get_all_exercise_event_from_lp(
1607
        $exercise_id,
1608
        $courseId,
1609
        $session_id = 0
1610
    ) {
1611
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1612
        $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1613
        $courseId = (int) $courseId;
1614
        $exercise_id = (int) $exercise_id;
1615
        $session_id = (int) $session_id;
1616
1617
        $sql = "SELECT * FROM $table_track_exercises
1618
                WHERE
1619
                    status = '' AND
1620
                    c_id = $courseId AND
1621
                    exe_exo_id = $exercise_id AND
1622
                    session_id = $session_id AND
1623
                    orig_lp_id !=0 AND
1624
                    orig_lp_item_id != 0";
1625
1626
        $res = Database::query($sql);
1627
        $list = [];
1628
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1629
            $exeId = $row['exe_id'];
1630
            $list[$exeId] = $row;
1631
            $sql = "SELECT * FROM $table_track_attempt 
1632
                    WHERE exe_id = $exeId";
1633
            $res_question = Database::query($sql);
1634
            while ($row_q = Database::fetch_array($res_question, 'ASSOC')) {
1635
                $list[$exeId]['question_list'][$row_q['question_id']] = $row_q;
1636
            }
1637
        }
1638
1639
        return $list;
1640
    }
1641
1642
    /**
1643
     * Get a list of all the exercises in a given learning path.
1644
     *
1645
     * @param int $lp_id
1646
     * @param int $course_id This parameter is probably deprecated as lp_id now is a global iid
1647
     *
1648
     * @return array
1649
     */
1650
    public static function get_all_exercises_from_lp($lp_id, $course_id)
1651
    {
1652
        $lp_item_table = Database::get_course_table(TABLE_LP_ITEM);
1653
        $course_id = (int) $course_id;
1654
        $lp_id = (int) $lp_id;
1655
        $sql = "SELECT * FROM $lp_item_table
1656
                WHERE
1657
                    c_id = $course_id AND
1658
                    lp_id = $lp_id AND
1659
                    item_type = 'quiz'
1660
                ORDER BY parent_item_id, display_order";
1661
        $res = Database::query($sql);
1662
1663
        $my_exercise_list = [];
1664
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1665
            $my_exercise_list[] = $row;
1666
        }
1667
1668
        return $my_exercise_list;
1669
    }
1670
1671
    /**
1672
     * This function gets the comments of an exercise.
1673
     *
1674
     * @param int $exe_id
1675
     * @param int $question_id
1676
     *
1677
     * @return string the comment
1678
     */
1679
    public static function get_comments($exe_id, $question_id)
1680
    {
1681
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1682
        $exe_id = (int) $exe_id;
1683
        $question_id = (int) $question_id;
1684
        $sql = "SELECT teacher_comment 
1685
                FROM $table
1686
                WHERE
1687
                    exe_id = $exe_id AND
1688
                    question_id = $question_id
1689
                ORDER by question_id";
1690
        $sqlres = Database::query($sql);
1691
        $comm = strval(Database::result($sqlres, 0, 'teacher_comment'));
1692
        $comm = trim($comm);
1693
1694
        return $comm;
1695
    }
1696
1697
    /**
1698
     * @param int $exeId
1699
     *
1700
     * @return array
1701
     */
1702
    public static function getAllExerciseEventByExeId($exeId)
1703
    {
1704
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1705
        $exeId = (int) $exeId;
1706
1707
        $sql = "SELECT * FROM $table
1708
                WHERE exe_id = $exeId
1709
                ORDER BY position";
1710
        $res_question = Database::query($sql);
1711
        $list = [];
1712
        if (Database::num_rows($res_question)) {
1713
            while ($row = Database::fetch_array($res_question, 'ASSOC')) {
1714
                $list[$row['question_id']][] = $row;
1715
            }
1716
        }
1717
1718
        return $list;
1719
    }
1720
1721
    /**
1722
     * @param int $exeId
1723
     * @param int $user_id
1724
     * @param int $courseId
1725
     * @param int $session_id
1726
     * @param int $question_id
1727
     */
1728
    public static function delete_attempt(
1729
        $exeId,
1730
        $user_id,
1731
        $courseId,
1732
        $session_id,
1733
        $question_id
1734
    ) {
1735
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1736
1737
        $exeId = (int) $exeId;
1738
        $user_id = (int) $user_id;
1739
        $courseId = (int) $courseId;
1740
        $session_id = (int) $session_id;
1741
        $question_id = (int) $question_id;
1742
1743
        $sql = "DELETE FROM $table
1744
                WHERE
1745
                    exe_id = $exeId AND
1746
                    user_id = $user_id AND
1747
                    c_id = $courseId AND
1748
                    session_id = $session_id AND
1749
                    question_id = $question_id ";
1750
        Database::query($sql);
1751
1752
        self::addEvent(
1753
            LOG_QUESTION_RESULT_DELETE,
1754
            LOG_EXERCISE_ATTEMPT_QUESTION_ID,
1755
            $exeId.'-'.$question_id,
1756
            null,
1757
            null,
1758
            $courseId,
1759
            $session_id
1760
        );
1761
    }
1762
1763
    /**
1764
     * @param $exeId
1765
     * @param $user_id
1766
     * @param int $courseId
1767
     * @param $question_id
1768
     * @param int $sessionId
1769
     */
1770
    public static function delete_attempt_hotspot(
1771
        $exeId,
1772
        $user_id,
1773
        $courseId,
1774
        $question_id,
1775
        $sessionId = null
1776
    ) {
1777
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT);
1778
1779
        $exeId = (int) $exeId;
1780
        $user_id = (int) $user_id;
1781
        $courseId = (int) $courseId;
1782
        $question_id = (int) $question_id;
1783
        if (!isset($sessionId)) {
1784
            $sessionId = api_get_session_id();
1785
        }
1786
1787
        $sql = "DELETE FROM $table
1788
                WHERE   
1789
                    hotspot_exe_id = $exeId AND
1790
                    hotspot_user_id = $user_id AND
1791
                    c_id = $courseId AND
1792
                    hotspot_question_id = $question_id ";
1793
        Database::query($sql);
1794
        self::addEvent(
1795
            LOG_QUESTION_RESULT_DELETE,
1796
            LOG_EXERCISE_ATTEMPT_QUESTION_ID,
1797
            $exeId.'-'.$question_id,
1798
            null,
1799
            null,
1800
            $courseId,
1801
            $sessionId
1802
        );
1803
    }
1804
1805
    /**
1806
     * Registers in track_e_course_access when user logs in for the first time to a course.
1807
     *
1808
     * @param int $courseId  ID of the course
1809
     * @param int $user_id   ID of the user
1810
     * @param int $sessionId ID of the session (if any)
1811
     *
1812
     * @return bool
1813
     */
1814
    public static function eventCourseLogin($courseId, $user_id, $sessionId)
1815
    {
1816
        if (Session::read('login_as')) {
1817
            return false;
1818
        }
1819
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1820
        $loginDate = $logoutDate = api_get_utc_datetime();
1821
1822
        // $counter represents the number of time this record has been refreshed
1823
        $counter = 1;
1824
        $courseId = (int) $courseId;
1825
        $user_id = (int) $user_id;
1826
        $sessionId = (int) $sessionId;
1827
        $ip = Database::escape_string(api_get_real_ip());
1828
1829
        $sql = "INSERT INTO $table(c_id, user_ip, user_id, login_course_date, logout_course_date, counter, session_id)
1830
                VALUES($courseId, '$ip', $user_id, '$loginDate', '$logoutDate', $counter, $sessionId)";
1831
        $courseAccessId = Database::query($sql);
1832
1833
        if ($courseAccessId) {
0 ignored issues
show
introduced by
$courseAccessId is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
1834
            // Course catalog stats modifications see #4191
1835
            CourseManager::update_course_ranking(
1836
                null,
1837
                null,
1838
                null,
1839
                null,
1840
                true,
1841
                false
1842
            );
1843
1844
            return true;
1845
        }
1846
    }
1847
1848
    /**
1849
     * Updates the user - course - session every X minutes
1850
     * In order to avoid.
1851
     *
1852
     * @param int $courseId
1853
     * @param int $userId
1854
     * @param int $sessionId
1855
     * @param int $minutes
1856
     *
1857
     * @return bool
1858
     */
1859
    public static function eventCourseLoginUpdate(
1860
        $courseId,
1861
        $userId,
1862
        $sessionId,
1863
        $minutes = 5
1864
    ) {
1865
        if (Session::read('login_as')) {
1866
            return false;
1867
        }
1868
1869
        if (empty($courseId) || empty($userId)) {
1870
            return false;
1871
        }
1872
1873
        $courseId = (int) $courseId;
1874
        $userId = (int) $userId;
1875
        $sessionId = (int) $sessionId;
1876
1877
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1878
        $sql = "SELECT course_access_id, logout_course_date 
1879
                FROM $table 
1880
                WHERE 
1881
                    c_id = $courseId AND
1882
                    session_id = $sessionId AND   
1883
                    user_id = $userId                     
1884
                ORDER BY login_course_date DESC
1885
                LIMIT 1";
1886
1887
        $result = Database::query($sql);
1888
1889
        // Save every 5 minutes by default
1890
        $seconds = $minutes * 60;
1891
        $maxSeconds = 3600; // Only update if max diff is one hour
1892
        if (Database::num_rows($result)) {
1893
            $row = Database::fetch_array($result);
1894
            $id = $row['course_access_id'];
1895
            $logout = $row['logout_course_date'];
1896
            $now = time();
1897
            $logout = api_strtotime($logout, 'UTC');
1898
            if ($now - $logout > $seconds &&
1899
                $now - $logout < $maxSeconds
1900
            ) {
1901
                $now = api_get_utc_datetime();
1902
                $sql = "UPDATE $table SET 
1903
                            logout_course_date = '$now', 
1904
                            counter = counter + 1
1905
                        WHERE course_access_id = $id";
1906
                Database::query($sql);
1907
            }
1908
1909
            return true;
1910
        }
1911
1912
        return false;
1913
    }
1914
1915
    /**
1916
     * Register the logout of the course (usually when logging out of the platform)
1917
     * from the track_e_course_access table.
1918
     *
1919
     * @param array $logoutInfo Information stored by local.inc.php
1920
     *                          before new context ['uid'=> x, 'cid'=>y, 'sid'=>z]
1921
     *
1922
     * @return bool
1923
     */
1924
    public static function courseLogout($logoutInfo)
1925
    {
1926
        if (Session::read('login_as')) {
1927
            return false;
1928
        }
1929
1930
        if (empty($logoutInfo['uid']) || empty($logoutInfo['cid'])) {
1931
            return false;
1932
        }
1933
1934
        $sessionLifetime = api_get_configuration_value('session_lifetime');
1935
        /*
1936
         * When $_configuration['session_lifetime'] is larger than ~100 hours
1937
         * (in order to let users take exercises with no problems)
1938
         * the function Tracking::get_time_spent_on_the_course() returns larger values (200h) due the condition:
1939
         * login_course_date > now() - INTERVAL $session_lifetime SECOND
1940
         */
1941
        if (empty($sessionLifetime) || $sessionLifetime > 86400) {
1942
            $sessionLifetime = 3600; // 1 hour
1943
        }
1944
        if (!empty($logoutInfo) && !empty($logoutInfo['cid'])) {
1945
            $tableCourseAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1946
            $userId = (int) $logoutInfo['uid'];
1947
            $courseId = (int) $logoutInfo['cid'];
1948
            $sessionId = 0;
1949
            if (!empty($logoutInfo['sid'])) {
1950
                $sessionId = (int) $logoutInfo['sid'];
1951
            }
1952
            $currentDate = api_get_utc_datetime();
1953
            // UTC time
1954
            $diff = time() - $sessionLifetime;
1955
            $time = api_get_utc_datetime($diff);
1956
            $sql = "SELECT course_access_id, logout_course_date
1957
                    FROM $tableCourseAccess
1958
                    WHERE 
1959
                        user_id = $userId AND
1960
                        c_id = $courseId  AND
1961
                        session_id = $sessionId AND
1962
                        login_course_date > '$time'
1963
                    ORDER BY login_course_date DESC 
1964
                    LIMIT 1";
1965
            $result = Database::query($sql);
1966
            $insert = false;
1967
            if (Database::num_rows($result) > 0) {
1968
                $row = Database::fetch_array($result, 'ASSOC');
1969
                $courseAccessId = $row['course_access_id'];
1970
                $sql = "UPDATE $tableCourseAccess SET 
1971
                                logout_course_date = '$currentDate', 
1972
                                counter = counter + 1
1973
                            WHERE course_access_id = $courseAccessId";
1974
                Database::query($sql);
1975
            } else {
1976
                $insert = true;
1977
            }
1978
1979
            if ($insert) {
1980
                $ip = Database::escape_string(api_get_real_ip());
1981
                $sql = "INSERT INTO $tableCourseAccess (c_id, user_ip, user_id, login_course_date, logout_course_date, counter, session_id)
1982
                        VALUES ($courseId, '$ip', $userId, '$currentDate', '$currentDate', 1, $sessionId)";
1983
                Database::query($sql);
1984
            }
1985
1986
            return true;
1987
        }
1988
    }
1989
1990
    /**
1991
     * Register a "fake" time spent on the platform, for example to match the
1992
     * estimated time he took to author an assignment/work, see configuration
1993
     * setting considered_working_time.
1994
     * This assumes there is already some connection of the student to the
1995
     * course, otherwise he wouldn't be able to upload an assignment.
1996
     * This works by creating a new record, copy of the current one, then
1997
     * updating the current one to be just the considered_working_time and
1998
     * end at the same second as the user connected to the course.
1999
     *
2000
     * @param int    $courseId    The course in which to add the time
2001
     * @param int    $userId      The user for whom to add the time
2002
     * @param int    $sessionId   The session in which to add the time (if any)
2003
     * @param string $virtualTime The amount of time to be added,
2004
     *                            in a hh:mm:ss format. If int, we consider it is expressed in hours.
2005
     * @param string $ip          IP address to go on record for this time record
2006
     *
2007
     * @return true on successful insertion, false otherwise
2008
     */
2009
    public static function eventAddVirtualCourseTime(
2010
        $courseId,
2011
        $userId,
2012
        $sessionId,
2013
        $virtualTime = '',
2014
        $ip = ''
2015
    ) {
2016
        $courseTrackingTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2017
        $time = $loginDate = $logoutDate = api_get_utc_datetime();
2018
2019
        $courseId = (int) $courseId;
2020
        $userId = (int) $userId;
2021
        $sessionId = (int) $sessionId;
2022
        $ip = Database::escape_string($ip);
2023
2024
        // Get the current latest course connection register. We need that
2025
        // record to re-use the data and create a new record.
2026
        $sql = "SELECT *
2027
                FROM $courseTrackingTable
2028
                WHERE
2029
                    user_id = $userId AND
2030
                    c_id = $courseId  AND
2031
                    session_id  = $sessionId AND
2032
                    login_course_date > '$time' - INTERVAL 3600 SECOND
2033
                ORDER BY login_course_date DESC 
2034
                LIMIT 0,1";
2035
        $result = Database::query($sql);
2036
2037
        // Ignore if we didn't find any course connection record in the last
2038
        // hour. In this case it wouldn't be right to add a "fake" time record.
2039
        if (Database::num_rows($result) > 0) {
2040
            // Found the latest connection
2041
            $row = Database::fetch_array($result);
2042
            $courseAccessId = $row['course_access_id'];
2043
            $courseAccessLoginDate = $row['login_course_date'];
2044
            $counter = $row['counter'];
2045
            $counter = $counter ? $counter : 0;
2046
            // Insert a new record, copy of the current one (except the logout
2047
            // date that we update to the current time)
2048
            $sql = "INSERT INTO $courseTrackingTable(
2049
                    c_id,
2050
                    user_ip, 
2051
                    user_id, 
2052
                    login_course_date, 
2053
                    logout_course_date, 
2054
                    counter, 
2055
                    session_id
2056
                ) VALUES(
2057
                    $courseId, 
2058
                    '$ip', 
2059
                    $userId, 
2060
                    '$courseAccessLoginDate', 
2061
                    '$logoutDate', 
2062
                    $counter, 
2063
                    $sessionId
2064
                )";
2065
            Database::query($sql);
2066
2067
            $loginDate = ChamiloApi::addOrSubTimeToDateTime(
2068
                $virtualTime,
2069
                $courseAccessLoginDate,
2070
                false
2071
            );
2072
            // We update the course tracking table
2073
            $sql = "UPDATE $courseTrackingTable  
2074
                    SET 
2075
                        login_course_date = '$loginDate',
2076
                        logout_course_date = '$courseAccessLoginDate',
2077
                        counter = 0
2078
                    WHERE 
2079
                        course_access_id = ".intval($courseAccessId)." AND 
2080
                        session_id = ".$sessionId;
2081
            Database::query($sql);
2082
2083
            return true;
2084
        }
2085
2086
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type true.
Loading history...
2087
    }
2088
2089
    /**
2090
     * Removes a "fake" time spent on the platform, for example to match the
2091
     * estimated time he took to author an assignment/work, see configuration
2092
     * setting considered_working_time.
2093
     * This method should be called when something that generated a fake
2094
     * time record is removed. Given the database link is weak (no real
2095
     * relationship kept between the deleted item and this record), this
2096
     * method just looks for the latest record that has the same time as the
2097
     * item's fake time, is in the past and in this course+session. If such a
2098
     * record cannot be found, it doesn't do anything.
2099
     * The IP address is not considered a useful filter here.
2100
     *
2101
     * @param int    $courseId    The course in which to add the time
2102
     * @param int    $userId      The user for whom to add the time
2103
     * @param int    $sessionId   The session in which to add the time (if any)
2104
     * @param string $virtualTime The amount of time to be added, in a hh:mm:ss format. If int, we consider it is expressed in hours.
2105
     *
2106
     * @return true on successful removal, false otherwise
2107
     */
2108
    public static function eventRemoveVirtualCourseTime(
2109
        $courseId,
2110
        $userId,
2111
        $sessionId = 0,
2112
        $virtualTime = ''
2113
    ) {
2114
        if (empty($virtualTime)) {
2115
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type true.
Loading history...
2116
        }
2117
        $courseTrackingTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2118
        $time = $loginDate = $logoutDate = api_get_utc_datetime();
2119
2120
        $courseId = (int) $courseId;
2121
        $userId = (int) $userId;
2122
        $sessionId = (int) $sessionId;
2123
        // Change $virtualTime format from hh:mm:ss to hhmmss which is the
2124
        // format returned by SQL for a subtraction of two datetime values
2125
        // @todo make sure this is portable between DBMSes
2126
        if (preg_match('/:/', $virtualTime)) {
2127
            list($h, $m, $s) = preg_split('/:/', $virtualTime);
2128
            $virtualTime = $h * 3600 + $m * 60 + $s;
2129
        } else {
2130
            $virtualTime *= 3600;
2131
        }
2132
2133
        // Get the current latest course connection register. We need that
2134
        // record to re-use the data and create a new record.
2135
        $sql = "SELECT course_access_id
2136
                FROM $courseTrackingTable
2137
                WHERE
2138
                    user_id = $userId AND
2139
                    c_id = $courseId  AND
2140
                    session_id  = $sessionId AND
2141
                    counter = 0 AND
2142
                    (UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) = '$virtualTime'
2143
                ORDER BY login_course_date DESC LIMIT 0,1";
2144
        $result = Database::query($sql);
2145
2146
        // Ignore if we didn't find any course connection record in the last
2147
        // hour. In this case it wouldn't be right to add a "fake" time record.
2148
        if (Database::num_rows($result) > 0) {
2149
            // Found the latest connection
2150
            $row = Database::fetch_row($result);
2151
            $courseAccessId = $row[0];
2152
            $sql = "DELETE FROM $courseTrackingTable 
2153
                    WHERE course_access_id = $courseAccessId";
2154
            $result = Database::query($sql);
2155
2156
            return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result returns the type Doctrine\DBAL\Driver\Statement which is incompatible with the documented return type true.
Loading history...
2157
        }
2158
2159
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type true.
Loading history...
2160
    }
2161
}
2162