Passed
Push — master ( c12494...619086 )
by Julito
15:29
created

CourseManager::addVisibilityOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 39
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 32
nc 1
nop 1
dl 0
loc 39
rs 9.408
c 1
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt*/
4
5
use Chamilo\CoreBundle\Entity\AccessUrlRelSession;
6
use Chamilo\CoreBundle\Entity\Course;
7
use Chamilo\CoreBundle\Entity\CourseRelUser;
8
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
9
use Chamilo\CoreBundle\Entity\SequenceResource;
10
use Chamilo\CoreBundle\Framework\Container;
11
use Chamilo\CoreBundle\Repository\SequenceResourceRepository;
12
use Chamilo\CourseBundle\Component\CourseCopy\CourseBuilder;
13
use Chamilo\CourseBundle\Component\CourseCopy\CourseRestorer;
14
use Chamilo\CourseBundle\Entity\CGroup;
15
use ChamiloSession as Session;
16
use Doctrine\Common\Collections\Criteria;
17
18
/**
19
 * Class CourseManager.
20
 *
21
 * This is the course library for Chamilo.
22
 *
23
 * All main course functions should be placed here.
24
 *
25
 * There are probably some places left with the wrong code.
26
 */
27
class CourseManager
28
{
29
    public const MAX_COURSE_LENGTH_CODE = 40;
30
    /** This constant is used to show separate user names in the course
31
     * list (userportal), footer, etc */
32
    public const USER_SEPARATOR = ' |';
33
34
    /**
35
     * Creates a course.
36
     *
37
     * @param array $params      Columns in the main.course table.
38
     * @param int   $authorId    Optional.
39
     * @param int   $accessUrlId Optional.
40
     *
41
     * @return mixed false if the course was not created, array with the course info
42
     */
43
    public static function create_course($params, $authorId = 0, $accessUrlId = 0)
44
    {
45
        global $_configuration;
46
47
        // Check portal limits
48
        $accessUrlId = !empty($accessUrlId) ? (int) $accessUrlId : api_get_current_access_url_id();
49
        $authorId = empty($authorId) ? api_get_user_id() : (int) $authorId;
50
51
        if (isset($_configuration[$accessUrlId]) && is_array($_configuration[$accessUrlId])) {
52
            $return = self::checkCreateCourseAccessUrlParam(
53
                $_configuration,
54
                $accessUrlId,
55
                'hosting_limit_courses',
56
                'PortalCoursesLimitReached'
57
            );
58
            if (false != $return) {
59
                return $return;
60
            }
61
            $return = self::checkCreateCourseAccessUrlParam(
62
                $_configuration,
63
                $accessUrlId,
64
                'hosting_limit_active_courses',
65
                'PortalActiveCoursesLimitReached'
66
            );
67
            if (false != $return) {
68
                return $return;
69
            }
70
        }
71
72
        if (empty($params['title'])) {
73
            return false;
74
        }
75
76
        if (empty($params['wanted_code'])) {
77
            $params['wanted_code'] = $params['title'];
78
            // Check whether the requested course code has already been occupied.
79
            $substring = api_substr($params['title'], 0, self::MAX_COURSE_LENGTH_CODE);
80
            if (false === $substring || empty($substring)) {
81
                return false;
82
            } else {
83
                $params['wanted_code'] = self::generate_course_code($substring);
84
            }
85
        }
86
87
        // Create the course keys
88
        $keys = AddCourse::define_course_keys($params['wanted_code']);
89
        $params['exemplary_content'] = isset($params['exemplary_content']) ? $params['exemplary_content'] : false;
90
91
        if (count($keys)) {
92
            $params['code'] = $keys['currentCourseCode'];
93
            $params['visual_code'] = $keys['currentCourseId'];
94
            $params['directory'] = $keys['currentCourseRepository'];
95
            $courseInfo = api_get_course_info($params['code']);
96
            if (empty($courseInfo)) {
97
                $courseId = AddCourse::register_course($params, $accessUrlId);
98
                $courseInfo = api_get_course_info_by_id($courseId);
99
                if (!empty($courseInfo)) {
100
                    self::fillCourse($courseInfo, $params, $authorId);
101
102
                    return $courseInfo;
103
                }
104
            }
105
        }
106
107
        return false;
108
    }
109
110
    /**
111
     * Returns all the information of a given course code.
112
     *
113
     * @param string $course_code , the course code
114
     *
115
     * @return array with all the fields of the course table
116
     *
117
     * @deprecated Use api_get_course_info() instead
118
     *
119
     * @author Patrick Cool <[email protected]>, Ghent University
120
     * @assert ('') === false
121
     */
122
    public static function get_course_information($course_code)
123
    {
124
        return Database::fetch_array(
125
            Database::query(
126
                "SELECT *, id as real_id FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
127
                WHERE code = '".Database::escape_string($course_code)."'"
128
            ),
129
            'ASSOC'
130
        );
131
    }
132
133
    /**
134
     * Returns a list of courses. Should work with quickform syntax.
135
     *
136
     * @param int    $from               Offset (from the 7th = '6'). Optional.
137
     * @param int    $howmany            Number of results we want. Optional.
138
     * @param string $orderby            The column we want to order it by. Optional, defaults to first column.
139
     * @param string $orderdirection     The direction of the order (ASC or DESC). Optional, defaults to ASC.
140
     * @param int    $visibility         the visibility of the course, or all by default
141
     * @param string $startwith          If defined, only return results for which the course *title* begins with this
142
     *                                   string
143
     * @param string $urlId              The Access URL ID, if using multiple URLs
144
     * @param bool   $alsoSearchCode     An extension option to indicate that we also want to search for course codes
145
     *                                   (not *only* titles)
146
     * @param array  $conditionsLike
147
     * @param array  $onlyThisCourseList
148
     *
149
     * @return array
150
     */
151
    public static function get_courses_list(
152
        $from = 0,
153
        $howmany = 0,
154
        $orderby = 'title',
155
        $orderdirection = 'ASC',
156
        $visibility = -1,
157
        $startwith = '',
158
        $urlId = null,
159
        $alsoSearchCode = false,
160
        $conditionsLike = [],
161
        $onlyThisCourseList = []
162
    ) {
163
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
164
        $sql = "SELECT course.*, course.id as real_id
165
                FROM $courseTable course  ";
166
167
        if (!empty($urlId)) {
168
            $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
169
            $sql .= " INNER JOIN $table url ON (url.c_id = course.id) ";
170
        }
171
172
173
        $visibility = (int) $visibility;
174
175
        if (!empty($startwith)) {
176
            $sql .= "WHERE (title LIKE '".Database::escape_string($startwith)."%' ";
177
            if ($alsoSearchCode) {
178
                $sql .= "OR code LIKE '".Database::escape_string($startwith)."%' ";
179
            }
180
            $sql .= ') ';
181
            if (-1 !== $visibility) {
182
                $sql .= " AND visibility = $visibility ";
183
            }
184
        } else {
185
            $sql .= 'WHERE 1 ';
186
            if (-1 !== $visibility) {
187
                $sql .= " AND visibility = $visibility ";
188
            }
189
        }
190
191
        if (!empty($urlId)) {
192
            $urlId = (int) $urlId;
193
            $sql .= " AND access_url_id = $urlId";
194
        }
195
196
        if (!empty($onlyThisCourseList)) {
197
            $onlyThisCourseList = array_map('intval', $onlyThisCourseList);
198
            $onlyThisCourseList = implode("','", $onlyThisCourseList);
199
            $sql .= " AND course.id IN ('$onlyThisCourseList') ";
200
        }
201
202
        $allowedFields = [
203
            'title',
204
            'code',
205
        ];
206
207
        if (count($conditionsLike) > 0) {
208
            $sql .= ' AND ';
209
            $temp_conditions = [];
210
            foreach ($conditionsLike as $field => $value) {
211
                if (!in_array($field, $allowedFields)) {
212
                    continue;
213
                }
214
                $field = Database::escape_string($field);
215
                $value = Database::escape_string($value);
216
                $simple_like = false;
217
                if ($simple_like) {
218
                    $temp_conditions[] = $field." LIKE '$value%'";
219
                } else {
220
                    $temp_conditions[] = $field.' LIKE \'%'.$value.'%\'';
221
                }
222
            }
223
            $condition = ' AND ';
224
            if (!empty($temp_conditions)) {
225
                $sql .= implode(' '.$condition.' ', $temp_conditions);
226
            }
227
        }
228
229
        if (empty($orderby)) {
230
            $sql .= ' ORDER BY title ';
231
        } else {
232
            if (in_array($orderby, ['title'])) {
233
                $sql .= " ORDER BY `".Database::escape_string($orderby)."` ";
234
            } else {
235
                $sql .= ' ORDER BY title ';
236
            }
237
        }
238
239
        $orderdirection = strtoupper($orderdirection);
240
        if (!in_array($orderdirection, ['ASC', 'DESC'])) {
241
            $sql .= 'ASC';
242
        } else {
243
            $sql .= $orderdirection === 'ASC' ? 'ASC' : 'DESC';
244
        }
245
246
        $howmany = (int) $howmany;
247
        if (!empty($howmany)) {
248
            $sql .= ' LIMIT '.$howmany;
249
        } else {
250
            $sql .= ' LIMIT 1000000'; //virtually no limit
251
        }
252
        if (!empty($from)) {
253
            $from = intval($from);
254
            $sql .= ' OFFSET '.intval($from);
255
        } else {
256
            $sql .= ' OFFSET 0';
257
        }
258
259
        $data = [];
260
        $res = Database::query($sql);
261
        if (Database::num_rows($res) > 0) {
262
            while ($row = Database::fetch_array($res, 'ASSOC')) {
263
                $data[] = $row;
264
            }
265
        }
266
267
        return $data;
268
    }
269
270
    /**
271
     * Returns the status of a user in a course, which is COURSEMANAGER or STUDENT.
272
     *
273
     * @param int $userId
274
     * @param int $courseId
275
     *
276
     * @return int|bool the status of the user in that course (or false if the user is not in that course)
277
     */
278
    public static function getUserInCourseStatus($userId, $courseId)
279
    {
280
        $courseId = (int) $courseId;
281
        $userId = (int) $userId;
282
        if (empty($courseId)) {
283
            return false;
284
        }
285
286
        $result = Database::fetch_array(
287
            Database::query(
288
                "SELECT status FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
289
                WHERE
290
                    c_id  = $courseId AND
291
                    user_id = $userId"
292
            )
293
        );
294
295
        if (empty($result['status'])) {
296
            return false;
297
        }
298
299
        return $result['status'];
300
    }
301
302
    /**
303
     * @param int $userId
304
     * @param int $courseId
305
     *
306
     * @return mixed
307
     */
308
    public static function getUserCourseInfo($userId, $courseId)
309
    {
310
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
311
                WHERE
312
                    c_id  = ".intval($courseId)." AND
313
                    user_id = ".intval($userId);
314
315
        return Database::fetch_array(Database::query($sql));
316
    }
317
318
    /**
319
     * @param int  $userId
320
     * @param int  $courseId
321
     * @param bool $isTutor
322
     *
323
     * @return bool
324
     */
325
    public static function updateUserCourseTutor($userId, $courseId, $isTutor)
326
    {
327
        $table = Database::escape_string(TABLE_MAIN_COURSE_USER);
328
329
        $courseId = (int) $courseId;
330
        $isTutor = (int) $isTutor;
331
332
        $sql = "UPDATE $table SET is_tutor = '".$isTutor."'
333
			    WHERE
334
				    user_id = ".$userId." AND
335
				    c_id = ".$courseId;
336
337
        $result = Database::query($sql);
338
339
        if (Database::affected_rows($result) > 0) {
340
            return true;
341
        }
342
343
        return false;
344
    }
345
346
    /**
347
     * @param int $userId
348
     * @param int $courseId
349
     *
350
     * @return mixed
351
     */
352
    public static function get_tutor_in_course_status($userId, $courseId)
353
    {
354
        $userId = intval($userId);
355
        $courseId = intval($courseId);
356
        $result = Database::fetch_array(
357
            Database::query(
358
                "SELECT is_tutor
359
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
360
                WHERE
361
                    c_id = $courseId AND
362
                    user_id = $userId"
363
            )
364
        );
365
366
        return $result['is_tutor'];
367
    }
368
369
    /**
370
     * Unsubscribe one or more users from a course.
371
     *
372
     * @param   mixed   user_id or an array with user ids
373
     * @param   string  course code
374
     * @param   int     session id
375
     *
376
     * @return bool
377
     *
378
     * @assert ('', '') === false
379
     */
380
    public static function unsubscribe_user($user_id, $course_code, $session_id = 0)
381
    {
382
        if (empty($user_id)) {
383
            return false;
384
        }
385
        if (!is_array($user_id)) {
386
            $user_id = [$user_id];
387
        }
388
389
        if (0 == count($user_id)) {
390
            return false;
391
        }
392
393
        if (!empty($session_id)) {
394
            $session_id = (int) $session_id;
395
        } else {
396
            $session_id = api_get_session_id();
397
        }
398
399
        if (empty($course_code)) {
400
            return false;
401
        }
402
403
        $userList = [];
404
        // Cleaning the $user_id variable
405
        if (is_array($user_id)) {
406
            $new_user_id_list = [];
407
            foreach ($user_id as $my_user_id) {
408
                $new_user_id_list[] = (int) $my_user_id;
409
            }
410
            $new_user_id_list = array_filter($new_user_id_list);
411
            $userList = $new_user_id_list;
412
            $user_ids = implode(',', $new_user_id_list);
413
        } else {
414
            $user_ids = (int) $user_id;
415
            $userList[] = $user_id;
416
        }
417
418
        $course_info = api_get_course_info($course_code);
419
        $course_id = $course_info['real_id'];
420
421
        // Unsubscribe user from all groups in the course.
422
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_GROUP_USER)."
423
                WHERE c_id = $course_id AND user_id IN (".$user_ids.")";
424
        Database::query($sql);
425
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_GROUP_TUTOR)."
426
                WHERE c_id = $course_id AND user_id IN (".$user_ids.")";
427
        Database::query($sql);
428
429
        // Erase user student publications (works) in the course - by André Boivin
430
        // @todo this should be handled by doctrine.
431
        /*if (!empty($userList)) {
432
            foreach ($userList as $userId) {
433
                // Getting all work from user
434
                $workList = getWorkPerUser($userId);
435
                if (!empty($workList)) {
436
                    foreach ($workList as $work) {
437
                        $work = $work['work'];
438
                        // Getting user results
439
                        if (!empty($work->user_results)) {
440
                            foreach ($work->user_results as $workSent) {
441
                                deleteWorkItem($workSent['id'], $course_info);
442
                            }
443
                        }
444
                    }
445
                }
446
            }
447
        }*/
448
449
        // Unsubscribe user from all blogs in the course.
450
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_BLOGS_REL_USER)."
451
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
452
        Database::query($sql);
453
454
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_BLOGS_TASKS_REL_USER)."
455
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
456
        Database::query($sql);
457
458
        // Deleting users in forum_notification and mailqueue course tables
459
        $sql = "DELETE FROM  ".Database::get_course_table(TABLE_FORUM_NOTIFICATION)."
460
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
461
        Database::query($sql);
462
463
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_FORUM_MAIL_QUEUE)."
464
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
465
        Database::query($sql);
466
467
        // Unsubscribe user from the course.
468
        if (!empty($session_id)) {
469
            foreach ($userList as $uid) {
470
                SessionManager::unSubscribeUserFromCourseSession($uid, $course_id, $session_id);
471
472
                // check if a user is register in the session with other course
473
                $sql = "SELECT user_id FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)."
474
                        WHERE session_id = $session_id AND user_id = $uid";
475
                $rs = Database::query($sql);
476
477
                if (0 == Database::num_rows($rs)) {
478
                    SessionManager::unsubscribe_user_from_session($uid, $session_id);
479
                }
480
            }
481
482
            Event::addEvent(
483
                LOG_UNSUBSCRIBE_USER_FROM_COURSE,
484
                LOG_COURSE_CODE,
485
                $course_code,
486
                api_get_utc_datetime(),
487
                $user_id,
488
                $course_id,
489
                $session_id
490
            );
491
        } else {
492
            $sql = "DELETE FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
493
                    WHERE
494
                        user_id IN ($user_ids) AND
495
                        relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
496
                        c_id = $course_id";
497
            Database::query($sql);
498
499
            // add event to system log
500
            $user_id = api_get_user_id();
501
502
            Event::addEvent(
503
                LOG_UNSUBSCRIBE_USER_FROM_COURSE,
504
                LOG_COURSE_CODE,
505
                $course_code,
506
                api_get_utc_datetime(),
507
                $user_id,
508
                $course_id
509
            );
510
511
            foreach ($userList as $userId) {
512
                $userInfo = api_get_user_info($userId);
513
                Event::addEvent(
514
                    LOG_UNSUBSCRIBE_USER_FROM_COURSE,
515
                    LOG_USER_OBJECT,
516
                    $userInfo,
517
                    api_get_utc_datetime(),
518
                    $user_id,
519
                    $course_id
520
                );
521
            }
522
        }
523
        if (api_get_configuration_value('catalog_course_subscription_in_user_s_session')) {
524
            // Also unlink the course from the users' currently accessible sessions
525
            /** @var Course $course */
526
            $course = Container::getCourseRepository()->findOneBy([
527
                'code' => $course_code,
528
            ]);
529
            if (is_null($course)) {
530
                return false;
531
            }
532
            /** @var Chamilo\CoreBundle\Entity\User $user */
533
            foreach (UserManager::getRepository()->matching(
534
                Criteria::create()->where(Criteria::expr()->in('id', $userList))
535
            ) as $user) {
536
                foreach ($user->getCurrentlyAccessibleSessions() as $session) {
537
                    $session->removeCourse($course);
538
                    // unsubscribe user from course within this session
539
                    SessionManager::unSubscribeUserFromCourseSession($user->getId(), $course->getId(), $session->getId());
540
                }
541
            }
542
            try {
543
                Database::getManager()->flush();
544
            } catch (\Doctrine\ORM\OptimisticLockException $exception) {
545
                Display::addFlash(
546
                    Display::return_message(
547
                        get_lang('InternalDatabaseError').': '.$exception->getMessage(),
548
                        'warning'
549
                    )
550
                );
551
552
                return false;
553
            }
554
        }
555
556
        return true;
557
    }
558
559
    /**
560
     * @param string $courseCode
561
     * @param int    $status
562
     *
563
     * @return bool
564
     */
565
    public static function autoSubscribeToCourse($courseCode, $status = STUDENT)
566
    {
567
        if (api_is_anonymous()) {
568
            return false;
569
        }
570
571
        $course = Container::getCourseRepository()->findOneBy(['code' => $courseCode]);
572
573
        if (null === $course) {
574
            return false;
575
        }
576
577
        $visibility = (int) $course->getVisibility();
578
579
        if (in_array($visibility, [
580
                COURSE_VISIBILITY_CLOSED,
581
                //Course::REGISTERED,
582
                COURSE_VISIBILITY_HIDDEN,
583
        ])) {
584
            Display::addFlash(
585
                Display::return_message(
586
                    get_lang('SubscribingNotAllowed'),
587
                    'warning'
588
        )
589
            );
590
591
            return false;
592
        }
593
594
        // Private course can allow auto subscription
595
        if (Course::REGISTERED === $visibility && false === $course->getSubscribe()) {
596
            Display::addFlash(
597
                Display::return_message(
598
                    get_lang('Subscribing not allowed'),
599
                    'warning'
600
                )
601
            );
602
603
            return false;
604
        }
605
606
        $userId = api_get_user_id();
607
608
        if (api_get_configuration_value('catalog_course_subscription_in_user_s_session')) {
609
            $user = api_get_user_entity($userId);
610
            $sessions = $user->getCurrentlyAccessibleSessions();
611
            if (empty($sessions)) {
612
                // user has no accessible session
613
                if ($user->getStudentSessions()) {
614
                    // user has ancient or future student session(s) but not available now
615
                    Display::addFlash(
616
                        Display::return_message(
617
                            get_lang('CanNotSubscribeToCourseUserSessionExpired'),
618
                            'warning'
619
                        )
620
                    );
621
622
                    return false;
623
                }
624
                // user has no session at all, create one starting now
625
                $numberOfDays = api_get_configuration_value('user_s_session_duration') ?: 3 * 365;
626
                try {
627
                    $duration = new DateInterval(sprintf('P%dD', $numberOfDays));
628
                } catch (Exception $exception) {
629
                    Display::addFlash(
630
                        Display::return_message(
631
                            get_lang('WrongNumberOfDays').': '.$numberOfDays.': '.$exception->getMessage(),
632
                            'warning'
633
                        )
634
                    );
635
636
                    return false;
637
                }
638
                $endDate = new DateTime();
639
                $endDate->add($duration);
640
                $session = new \Chamilo\CoreBundle\Entity\Session();
641
                $session->setName(
642
                    sprintf(get_lang('FirstnameLastnameCourses'), $user->getFirstname(), $user->getLastname())
643
                );
644
                $session->setAccessEndDate($endDate);
645
                $session->setCoachAccessEndDate($endDate);
646
                $session->setDisplayEndDate($endDate);
647
                $session->setSendSubscriptionNotification(false);
648
                $adminId = api_get_configuration_value('session_automatic_creation_user_id') ?: 1;
649
                $session->setSessionAdmin(api_get_user_entity($adminId));
650
                $session->addUserInSession(0, $user);
651
                Database::getManager()->persist($session);
652
                try {
653
                    Database::getManager()->flush();
654
                } catch (\Doctrine\ORM\OptimisticLockException $exception) {
655
                    Display::addFlash(
656
                        Display::return_message(
657
                            get_lang('InternalDatabaseError').': '.$exception->getMessage(),
658
                            'warning'
659
                        )
660
                    );
661
662
                    return false;
663
                }
664
                $accessUrlRelSession = new AccessUrlRelSession();
665
                $accessUrlRelSession->setUrl(api_get_url_entity());
666
                $accessUrlRelSession->setSession($session);
667
                Database::getManager()->persist($accessUrlRelSession);
668
                try {
669
                    Database::getManager()->flush();
670
                } catch (\Doctrine\ORM\OptimisticLockException $exception) {
671
                    Display::addFlash(
672
                        Display::return_message(
673
                            get_lang('InternalDatabaseError').': '.$exception->getMessage(),
674
                            'warning'
675
                        )
676
                    );
677
678
                    return false;
679
                }
680
            } else {
681
                // user has at least one accessible session, let's use it
682
                $session = $sessions[0];
683
            }
684
            // add chosen course to the user session
685
            $session->addCourse($course);
686
            Database::getManager()->persist($session);
687
            try {
688
                Database::getManager()->flush();
689
            } catch (\Doctrine\ORM\OptimisticLockException $exception) {
690
                Display::addFlash(
691
                    Display::return_message(
692
                        get_lang('InternalDatabaseError').': '.$exception->getMessage(),
693
                        'warning'
694
                    )
695
                );
696
697
                return false;
698
            }
699
            // subscribe user to course within this session
700
            SessionManager::subscribe_users_to_session_course([$userId], $session->getId(), $course->getCode());
701
702
            return true;
703
        }
704
705
        return self::subscribeUser($userId, $course->getId(), $status, 0);
706
    }
707
708
    /**
709
     * Subscribe a user to a course. No checks are performed here to see if
710
     * course subscription is allowed.
711
     *
712
     * @param int    $userId
713
     * @param int $courseId
714
     * @param int    $status                 (STUDENT, COURSEMANAGER, COURSE_ADMIN, NORMAL_COURSE_MEMBER)
715
     * @param int    $sessionId
716
     * @param int    $userCourseCategoryId
717
     * @param bool   $checkTeacherPermission
718
     *
719
     * @return bool True on success, false on failure
720
     *
721
     * @assert ('', '') === false
722
     */
723
    public static function subscribeUser(
724
        $userId,
725
        $courseId,
726
        $status = STUDENT,
727
        $sessionId = 0,
728
        $userCourseCategoryId = 0,
729
        $checkTeacherPermission = true
730
    ) {
731
        $userId = (int) $userId;
732
        $status = (int) $status;
733
734
        if (empty($userId) || empty($courseId)) {
735
            return false;
736
        }
737
738
        $course = api_get_course_entity($courseId);
739
740
        if (null === $course) {
741
            Display::addFlash(Display::return_message(get_lang('This course doesn\'t exist'), 'warning'));
742
743
            return false;
744
        }
745
746
        $user = api_get_user_entity($userId);
747
748
        if (null === $user) {
749
            Display::addFlash(Display::return_message(get_lang('This user doesn\'t exist'), 'warning'));
750
751
            return false;
752
        }
753
754
        $courseCode = $course->getCode();
755
        $userCourseCategoryId = (int) $userCourseCategoryId;
756
        $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
757
        $status = STUDENT === $status || COURSEMANAGER === $status ? $status : STUDENT;
758
759
        if (!empty($sessionId)) {
760
            SessionManager::subscribe_users_to_session_course(
761
                [$userId],
762
                $sessionId,
763
                $courseCode
764
            );
765
766
            // Add event to the system log
767
            Event::addEvent(
768
                LOG_SUBSCRIBE_USER_TO_COURSE,
769
                LOG_COURSE_CODE,
770
                $courseCode,
771
                api_get_utc_datetime(),
772
                api_get_user_id(),
773
                $courseId,
774
                $sessionId
775
            );
776
            Event::addEvent(
777
                LOG_SUBSCRIBE_USER_TO_COURSE,
778
                LOG_USER_OBJECT,
779
                $user,
780
                api_get_utc_datetime(),
781
                api_get_user_id(),
782
                $courseId,
783
                $sessionId
784
            );
785
786
            return true;
787
        } else {
788
            // Check whether the user has not been already subscribed to the course.
789
            $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
790
                    WHERE
791
                        user_id = $userId AND
792
                        relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
793
                        c_id = $courseId
794
                    ";
795
            if (Database::num_rows(Database::query($sql)) > 0) {
796
                Display::addFlash(Display::return_message(get_lang('Already registered in course'), 'warning'));
797
798
                return false;
799
            }
800
801
            if ($checkTeacherPermission && !api_is_course_admin()) {
802
                // Check in advance whether subscription is allowed or not for this course.
803
                if (SUBSCRIBE_NOT_ALLOWED === (int) $course->getSubscribe()) {
804
                    Display::addFlash(Display::return_message(get_lang('Subscription not allowed'), 'warning'));
805
806
                    return false;
807
                }
808
            }
809
810
            if (STUDENT === $status) {
811
                // Check if max students per course extra field is set
812
                $extraFieldValue = new ExtraFieldValue('course');
813
                $value = $extraFieldValue->get_values_by_handler_and_field_variable(
814
                    $courseId,
815
                    'max_subscribed_students'
816
                );
817
                if (!empty($value) && isset($value['value']) && '' !== $value['value']) {
818
                    $maxStudents = (int) $value['value'];
819
                    $count = self::get_user_list_from_course_code(
820
                        $courseCode,
821
                        0,
822
                        null,
823
                        null,
824
                        STUDENT,
825
                        true,
826
                        false
827
                    );
828
829
                    if ($count >= $maxStudents) {
830
                        Display::addFlash(
831
                            Display::return_message(
832
                                get_lang(
833
                                    'The maximum number of student has already been reached, it is not possible to subscribe more student.'
834
                                ),
835
                                'warning'
836
                            )
837
                        );
838
839
                        return false;
840
                    }
841
                }
842
            }
843
844
            $maxSort = api_max_sort_value('0', $userId);
845
846
            $courseRelUser = new CourseRelUser();
847
            $courseRelUser
848
                ->setCourse($course)
849
                ->setUser($user)
850
                ->setStatus($status)
851
                ->setSort($maxSort + 1)
852
                ->setUserCourseCat($userCourseCategoryId)
853
            ;
854
855
            $em = Database::getManager();
856
            $em->persist($courseRelUser);
857
            $em->flush();
858
859
            $insertId = $courseRelUser->getId();
860
861
            if ($insertId) {
862
                Display::addFlash(
863
                    Display::return_message(
864
                        sprintf(
865
                            get_lang('User %s has been registered to course %s'),
866
                            UserManager::formatUserFullName($user, true),
867
                            $course->getTitle()
868
                        )
869
                    )
870
                );
871
872
                $send = (int) api_get_course_setting('email_alert_to_teacher_on_new_user_in_course', $course);
873
874
                if (1 === $send) {
875
                    self::email_to_tutor(
876
                        $userId,
877
                        $courseId,
878
                        false
879
                    );
880
                } elseif (2 === $send) {
881
                    self::email_to_tutor(
882
                        $userId,
883
                        $courseId,
884
                        true
885
                    );
886
                }
887
888
                $subscribe = (int) api_get_course_setting('subscribe_users_to_forum_notifications', $course);
889
                if (1 === $subscribe) {
890
                    /*$forums = get_forums(0,  true, $sessionId);
891
                    foreach ($forums as $forum) {
892
                        set_notification('forum', $forum->getIid(), false, $userInfo, $courseInfo);
893
                    }*/
894
                }
895
896
                // Add event to the system log
897
                Event::addEvent(
898
                    LOG_SUBSCRIBE_USER_TO_COURSE,
899
                    LOG_COURSE_CODE,
900
                    $courseCode,
901
                    api_get_utc_datetime(),
902
                    api_get_user_id(),
903
                    $courseId
904
                );
905
906
                Event::addEvent(
907
                    LOG_SUBSCRIBE_USER_TO_COURSE,
908
                    LOG_USER_OBJECT,
909
                    $user,
910
                    api_get_utc_datetime(),
911
                    api_get_user_id(),
912
                    $courseId
913
                );
914
915
                return true;
916
            }
917
918
            return false;
919
        }
920
    }
921
922
    /**
923
     * Get the course id based on the original id and field name in the
924
     * extra fields. Returns 0 if course was not found.
925
     *
926
     * @param string $original_course_id_value
927
     * @param string $original_course_id_name
928
     *
929
     * @return int Course id
930
     *
931
     * @assert ('', '') === false
932
     */
933
    public static function get_course_code_from_original_id(
934
        $original_course_id_value,
935
        $original_course_id_name
936
    ) {
937
        $t_cfv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
938
        $table_field = Database::get_main_table(TABLE_EXTRA_FIELD);
939
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
940
        $original_course_id_value = Database::escape_string($original_course_id_value);
941
        $original_course_id_name = Database::escape_string($original_course_id_name);
942
943
        $sql = "SELECT item_id
944
                FROM $table_field cf
945
                INNER JOIN $t_cfv cfv
946
                ON cfv.field_id=cf.id
947
                WHERE
948
                    variable = '$original_course_id_name' AND
949
                    value = '$original_course_id_value' AND
950
                    cf.extra_field_type = $extraFieldType
951
                ";
952
        $res = Database::query($sql);
953
        $row = Database::fetch_object($res);
954
        if ($row) {
955
            return $row->item_id;
956
        } else {
957
            return 0;
958
        }
959
    }
960
961
    /**
962
     * Gets the course code from the course id. Returns null if course id was not found.
963
     *
964
     * @param int $id Course id
965
     *
966
     * @return string Course code
967
     * @assert ('') === false
968
     */
969
    public static function get_course_code_from_course_id($id)
970
    {
971
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
972
        $id = intval($id);
973
        $sql = "SELECT code FROM $table WHERE id = $id ";
974
        $res = Database::query($sql);
975
        $row = Database::fetch_object($res);
976
        if ($row) {
977
            return $row->code;
978
        } else {
979
            return null;
980
        }
981
    }
982
983
    /**
984
     * Add the user $userId visibility to the course $courseCode in the catalogue.
985
     *
986
     * @author David Nos (https://github.com/dnos)
987
     *
988
     * @param int    $userId     the id of the user
989
     * @param string $courseCode the course code
990
     * @param int    $visible    (optional) The course visibility in the catalogue to the user (1=visible, 0=invisible)
991
     *
992
     * @return bool true if added succesfully, false otherwise
993
     */
994
    public static function addUserVisibilityToCourseInCatalogue(
995
        $userId,
996
        $courseCode,
997
        $visible = 1
998
    ) {
999
        $debug = false;
1000
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1001
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
1002
        $visible = (int) $visible;
1003
        if (empty($userId) || empty($courseCode) || ($userId != strval(intval($userId)))) {
1004
            return false;
1005
        }
1006
1007
        $courseCode = Database::escape_string($courseCode);
1008
        $courseInfo = api_get_course_info($courseCode);
1009
        $courseId = $courseInfo['real_id'];
1010
1011
        // Check in advance whether the user has already been registered on the platform.
1012
        $sql = "SELECT status FROM ".$userTable." WHERE user_id = $userId ";
1013
        if (0 == Database::num_rows(Database::query($sql))) {
1014
            if ($debug) {
1015
                error_log('The user has not been registered to the platform');
1016
            }
1017
1018
            return false; // The user has not been registered to the platform.
1019
        }
1020
1021
        // Check whether the user has already been registered to the course visibility in the catalogue.
1022
        $sql = "SELECT * FROM $courseUserTable
1023
                WHERE
1024
                    user_id = $userId AND
1025
                    visible = $visible AND
1026
                    c_id = $courseId";
1027
        if (Database::num_rows(Database::query($sql)) > 0) {
1028
            if ($debug) {
1029
                error_log('The user has been already registered to the course visibility in the catalogue');
1030
            }
1031
1032
            return true; // The visibility of the user to the course in the catalogue does already exist.
1033
        }
1034
1035
        // Register the user visibility to course in catalogue.
1036
        $params = [
1037
            'user_id' => $userId,
1038
            'c_id' => $courseId,
1039
            'visible' => $visible,
1040
        ];
1041
1042
        return Database::insert($courseUserTable, $params);
1043
    }
1044
1045
    /**
1046
     * Remove the user $userId visibility to the course $courseCode in the catalogue.
1047
     *
1048
     * @author David Nos (https://github.com/dnos)
1049
     *
1050
     * @param int    $userId     the id of the user
1051
     * @param string $courseCode the course code
1052
     * @param int    $visible    (optional) The course visibility in the catalogue to the user (1=visible, 0=invisible)
1053
     *
1054
     * @return bool true if removed succesfully or register not found, false otherwise
1055
     */
1056
    public static function removeUserVisibilityToCourseInCatalogue(
1057
        $userId,
1058
        $courseCode,
1059
        $visible = 1
1060
    ) {
1061
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
1062
1063
        if (empty($userId) || empty($courseCode) || ($userId != strval(intval($userId)))) {
1064
            return false;
1065
        }
1066
1067
        $courseCode = Database::escape_string($courseCode);
1068
        $courseInfo = api_get_course_info($courseCode);
1069
        $courseId = $courseInfo['real_id'];
1070
1071
        // Check whether the user has already been registered to the course visibility in the catalogue.
1072
        $sql = "SELECT * FROM $courseUserTable
1073
                WHERE
1074
                    user_id = $userId AND
1075
                    visible = $visible AND
1076
                    c_id = $courseId";
1077
        if (Database::num_rows(Database::query($sql)) > 0) {
1078
            $cond = [
1079
                'user_id = ? AND c_id = ? AND visible = ? ' => [
1080
                    $userId,
1081
                    $courseId,
1082
                    $visible,
1083
                ],
1084
            ];
1085
1086
            return Database::delete($courseUserTable, $cond);
1087
        } else {
1088
            return true; // Register does not exist
1089
        }
1090
    }
1091
1092
    /**
1093
     * @param string $code
1094
     *
1095
     * @return bool if there already are one or more courses
1096
     *              with the same code OR visual_code (visualcode), false otherwise
1097
     */
1098
    public static function course_code_exists($code)
1099
    {
1100
        $code = Database::escape_string($code);
1101
        $sql = "SELECT COUNT(*) as number
1102
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
1103
                WHERE code = '$code' OR visual_code = '$code'";
1104
        $result = Database::fetch_array(Database::query($sql));
1105
1106
        return $result['number'] > 0;
1107
    }
1108
1109
    /**
1110
     * @param int    $userId
1111
     * @param string $keyword
1112
     *
1113
     * @return array an array with the course info of all the courses (real and virtual)
1114
     *               of which the current user is course admin
1115
     */
1116
    public static function get_course_list_of_user_as_course_admin($userId, $keyword = '')
1117
    {
1118
        $user = api_get_user_entity($userId);
1119
1120
        if (null === $user) {
1121
            return [];
1122
        }
1123
1124
        $url = api_get_url_entity();
1125
        $user = api_get_user_entity($userId);
1126
        $repo = Container::getUserRepository();
1127
1128
        return $repo->getCourses($user, $url, COURSEMANAGER, $keyword);
1129
    }
1130
1131
    /**
1132
     * @param int   $userId
1133
     * @param array $courseInfo
1134
     *
1135
     * @return bool|null
1136
     */
1137
    public static function isUserSubscribedInCourseAsDrh($userId, $courseInfo)
1138
    {
1139
        $userId = intval($userId);
1140
1141
        if (!api_is_drh()) {
1142
            return false;
1143
        }
1144
1145
        if (empty($courseInfo) || empty($userId)) {
1146
            return false;
1147
        }
1148
1149
        $courseId = intval($courseInfo['real_id']);
1150
        $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1151
1152
        $sql = "SELECT * FROM $table
1153
                WHERE
1154
                    user_id = $userId AND
1155
                    relation_type = ".COURSE_RELATION_TYPE_RRHH." AND
1156
                    c_id = $courseId";
1157
1158
        $result = Database::fetch_array(Database::query($sql));
1159
1160
        if (!empty($result)) {
1161
            // The user has been registered in this course.
1162
            return true;
1163
        }
1164
    }
1165
1166
    /**
1167
     * Check if user is subscribed inside a course.
1168
     *
1169
     * @param int    $userId
1170
     * @param string $course_code  , if this parameter is null, it'll check for all courses
1171
     * @param bool   $in_a_session True for checking inside sessions too, by default is not checked
1172
     * @param int    $session_id
1173
     *
1174
     * @return bool $session_id true if the user is registered in the course, false otherwise
1175
     */
1176
    public static function is_user_subscribed_in_course(
1177
        $userId,
1178
        $course_code = null,
1179
        $in_a_session = false,
1180
        $session_id = 0
1181
    ) {
1182
        $userId = (int) $userId;
1183
        $session_id = (int) $session_id;
1184
1185
        if (api_get_configuration_value('catalog_course_subscription_in_user_s_session')) {
1186
            // with this option activated, only check whether the course is in one of the users' sessions
1187
            $course = Container::getCourseRepository()->findOneBy([
1188
                'code' => $course_code,
1189
            ]);
1190
            if (is_null($course)) {
1191
                return false;
1192
            }
1193
1194
            $user = api_get_user_entity($userId);
1195
            if (is_null($user)) {
1196
                return false;
1197
            }
1198
            foreach ($user->getStudentSessions() as $session) {
1199
                if ($session->isRelatedToCourse($course)) {
1200
                    return true;
1201
                }
1202
            }
1203
1204
            return false;
1205
        }
1206
1207
        if (empty($session_id)) {
1208
            $session_id = api_get_session_id();
1209
        }
1210
1211
        $condition_course = '';
1212
        if (isset($course_code)) {
1213
            $courseInfo = api_get_course_info($course_code);
1214
            if (empty($courseInfo)) {
1215
                return false;
1216
            }
1217
            $courseId = $courseInfo['real_id'];
1218
            $condition_course = " AND c_id = $courseId";
1219
        }
1220
1221
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
1222
                WHERE
1223
                    user_id = $userId AND
1224
                    relation_type<>".COURSE_RELATION_TYPE_RRHH."
1225
                    $condition_course ";
1226
1227
        $result = Database::fetch_array(Database::query($sql));
1228
1229
        if (!empty($result)) {
1230
            // The user has been registered in this course.
1231
            return true;
1232
        }
1233
1234
        if (!$in_a_session) {
1235
            // The user has not been registered in this course.
1236
            return false;
1237
        }
1238
1239
        $tableSessionCourseUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1240
        $sql = "SELECT 1 FROM $tableSessionCourseUser
1241
                WHERE user_id = $userId AND session_id = $session_id $condition_course";
1242
1243
        if (Database::num_rows(Database::query($sql)) > 0) {
1244
            return true;
1245
        }
1246
1247
        $sql = "SELECT 1 FROM $tableSessionCourseUser
1248
                WHERE user_id = $userId AND session_id = $session_id AND status = 2 $condition_course";
1249
1250
        if (Database::num_rows(Database::query($sql)) > 0) {
1251
            return true;
1252
        }
1253
1254
        $sql = 'SELECT 1 FROM '.Database::get_main_table(TABLE_MAIN_SESSION).
1255
              " WHERE id = $session_id AND id_coach = $userId";
1256
1257
        if (Database::num_rows(Database::query($sql)) > 0) {
1258
            return true;
1259
        }
1260
1261
        return false;
1262
    }
1263
1264
    /**
1265
     * Is the user a teacher in the given course?
1266
     *
1267
     * @param int $userId
1268
     * @param int $courseId
1269
     *
1270
     * @return bool if the user is a teacher in the course, false otherwise
1271
     */
1272
    public static function isCourseTeacher($userId, $courseId)
1273
    {
1274
        $userId = (int) $userId;
1275
        $courseId = (int) $courseId;
1276
1277
        if (empty($courseId) || empty($userId)) {
1278
            return false;
1279
        }
1280
1281
        $sql = "SELECT status FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
1282
                WHERE c_id = $courseId AND user_id = $userId ";
1283
        $result = Database::query($sql);
1284
1285
        if (Database::num_rows($result) > 0) {
1286
            return 1 == Database::result($result, 0, 'status');
1287
        }
1288
1289
        return false;
1290
    }
1291
1292
    /**
1293
     * Return user info array of all users registered in a course
1294
     * This only returns the users that are registered in this actual course, not linked courses.
1295
     *
1296
     * @param string    $courseCode
1297
     * @param int       $sessionId
1298
     * @param string    $limit
1299
     * @param string    $order_by         the field to order the users by.
1300
     *                                    Valid values are 'lastname', 'firstname', 'username', 'email',
1301
     *                                    'official_code' OR a part of a SQL statement that starts with ORDER BY ...
1302
     * @param int|null  $filter_by_status if using the session_id: 0 or 2 (student, coach),
1303
     *                                    if using session_id = 0 STUDENT or COURSEMANAGER
1304
     * @param bool|null $return_count
1305
     * @param bool      $add_reports
1306
     * @param bool      $resumed_report
1307
     * @param array     $extra_field
1308
     * @param array     $courseCodeList
1309
     * @param array     $userIdList
1310
     * @param string    $filterByActive
1311
     * @param array     $sessionIdList
1312
     * @param string    $searchByKeyword
1313
     *
1314
     * @return array|int
1315
     */
1316
    public static function get_user_list_from_course_code(
1317
        $courseCode,
1318
        $sessionId = 0,
1319
        $limit = null,
1320
        $order_by = null,
1321
        $filter_by_status = null,
1322
        $return_count = null,
1323
        $add_reports = false,
1324
        $resumed_report = false,
1325
        $extra_field = [],
1326
        $courseCodeList = [],
1327
        $userIdList = [],
1328
        $filterByActive = null,
1329
        $sessionIdList = [],
1330
        $searchByKeyword = '',
1331
        $options = []
1332
    ) {
1333
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
1334
        $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
1335
1336
        $sessionId = (int) $sessionId;
1337
        $courseCode = Database::escape_string($courseCode);
1338
        $courseInfo = api_get_course_info($courseCode);
1339
        $courseId = 0;
1340
        if (!empty($courseInfo)) {
1341
            $courseId = $courseInfo['real_id'];
1342
        }
1343
        $session = null;
1344
        if (!empty($sessionId)) {
1345
            $session = api_get_session_entity($sessionId);
1346
        }
1347
        $course = api_get_course_entity($courseId);
1348
        $where = [];
1349
        if (empty($order_by)) {
1350
            $order_by = 'user.lastname, user.firstname';
1351
            if (api_is_western_name_order()) {
1352
                $order_by = 'user.firstname, user.lastname';
1353
            }
1354
        }
1355
1356
        // if the $order_by does not contain 'ORDER BY'
1357
        // we have to check if it is a valid field that can be sorted on
1358
        if (!strstr($order_by, 'ORDER BY')) {
1359
            if (!empty($order_by)) {
1360
                $order_by = "ORDER BY $order_by";
1361
            } else {
1362
                $order_by = '';
1363
            }
1364
        }
1365
1366
        $filter_by_status_condition = null;
1367
        $sqlInjectWhere = '';
1368
        $whereExtraField = '';
1369
        $injectExtraFields = ' , ';
1370
        $sqlInjectJoins = '';
1371
        if (!empty($options)) {
1372
            $extraFieldModel = new ExtraField('user');
1373
            $conditions = $extraFieldModel->parseConditions($options, 'user');
1374
            if (!empty($conditions)) {
1375
                $injectExtraFields = $conditions['inject_extra_fields'];
1376
1377
                if (!empty($injectExtraFields)) {
1378
                    $injectExtraFields = ', '.$injectExtraFields;
1379
                } else {
1380
                    $injectExtraFields = ' , ';
1381
                }
1382
                $sqlInjectJoins = $conditions['inject_joins'];
1383
                $whereExtraField = $conditions['where'];
1384
            }
1385
        }
1386
1387
        if (!empty($sessionId) || !empty($sessionIdList)) {
1388
            $sql = 'SELECT DISTINCT
1389
                        user.id as user_id,
1390
                        user.email,
1391
                        session_course_user.status as status_session,
1392
                        session_id,
1393
                        user.*,
1394
                        course.*,
1395
                        course.id AS c_id
1396
                         '.$injectExtraFields.'
1397
                        session.name as session_name
1398
                    ';
1399
            if ($return_count) {
1400
                $sql = ' SELECT COUNT(user.id) as count';
1401
            }
1402
1403
            $sessionCondition = " session_course_user.session_id = $sessionId";
1404
            if (!empty($sessionIdList)) {
1405
                $sessionIdListToString = implode("','", array_map('intval', $sessionIdList));
1406
                $sessionCondition = " session_course_user.session_id IN ('$sessionIdListToString') ";
1407
            }
1408
1409
            $courseCondition = " course.id = $courseId";
1410
            if (!empty($courseCodeList)) {
1411
                $courseCodeListForSession = array_map(['Database', 'escape_string'], $courseCodeList);
1412
                $courseCodeListForSession = implode("','", $courseCodeListForSession);
1413
                $courseCondition = " course.code IN ('$courseCodeListForSession')  ";
1414
            }
1415
1416
            $sql .= ' FROM '.Database::get_main_table(TABLE_MAIN_USER).' as user ';
1417
            $sql .= " LEFT JOIN ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." as session_course_user
1418
                      ON
1419
                        user.id = session_course_user.user_id AND
1420
                        $sessionCondition
1421
                        INNER JOIN $course_table course
1422
                        ON session_course_user.c_id = course.id AND
1423
                        $courseCondition
1424
                        INNER JOIN $sessionTable session
1425
                        ON session_course_user.session_id = session.id
1426
                    $sqlInjectJoins
1427
                   ";
1428
            $where[] = ' session_course_user.c_id IS NOT NULL ';
1429
1430
            // 2 = coach
1431
            // 0 = student
1432
            if (isset($filter_by_status)) {
1433
                $filter_by_status = (int) $filter_by_status;
1434
                $filter_by_status_condition = " session_course_user.status = $filter_by_status AND ";
1435
            }
1436
        } else {
1437
            if ($return_count) {
1438
                $sql = " SELECT COUNT(*) as count";
1439
            } else {
1440
                if (empty($courseCode)) {
1441
                    $sql = 'SELECT DISTINCT
1442
                                course.title,
1443
                                course.code,
1444
                                course.id AS c_id,
1445
                                course_rel_user.status as status_rel,
1446
                                user.id as user_id,
1447
                                user.email,
1448
                                course_rel_user.is_tutor
1449
                                '.$injectExtraFields.'
1450
                                user.*  ';
1451
                } else {
1452
                    $sql = 'SELECT DISTINCT
1453
                                course_rel_user.status as status_rel,
1454
                                user.id as user_id,
1455
                                user.email,
1456
                                course_rel_user.is_tutor
1457
                                '.$injectExtraFields.'
1458
                                user.*  ';
1459
                }
1460
            }
1461
1462
            $sql .= " FROM ".Database::get_main_table(TABLE_MAIN_USER)." as user
1463
                      LEFT JOIN ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." as course_rel_user
1464
                      ON
1465
                        user.id = course_rel_user.user_id AND
1466
                        course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
1467
                       INNER JOIN $course_table course
1468
                       ON (course_rel_user.c_id = course.id)
1469
                       $sqlInjectJoins
1470
                       ";
1471
1472
            if (!empty($courseId)) {
1473
                $sql .= " AND course_rel_user.c_id = $courseId";
1474
            }
1475
            $where[] = ' course_rel_user.c_id IS NOT NULL ';
1476
1477
            if (isset($filter_by_status) && is_numeric($filter_by_status)) {
1478
                $filter_by_status = (int) $filter_by_status;
1479
                $filter_by_status_condition = " course_rel_user.status = $filter_by_status AND ";
1480
            }
1481
        }
1482
1483
        $multiple_access_url = api_get_multiple_access_url();
1484
        if ($multiple_access_url) {
1485
            $sql .= ' LEFT JOIN '.Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER).' au
1486
                      ON (au.user_id = user.id) ';
1487
        }
1488
1489
        $extraFieldWasAdded = false;
1490
        if ($return_count && $resumed_report) {
1491
            foreach ($extra_field as $extraField) {
1492
                $extraFieldInfo = UserManager::get_extra_field_information_by_name($extraField);
1493
                if (!empty($extraFieldInfo)) {
1494
                    $fieldValuesTable = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1495
                    $sql .= " LEFT JOIN $fieldValuesTable as ufv
1496
                            ON (
1497
                                user.id = ufv.item_id AND
1498
                                (field_id = ".$extraFieldInfo['id']." OR field_id IS NULL)
1499
                            )";
1500
                    $extraFieldWasAdded = true;
1501
                }
1502
            }
1503
        }
1504
1505
        $sql .= " WHERE
1506
            $filter_by_status_condition
1507
            ".implode(' OR ', $where);
1508
1509
        if ($multiple_access_url) {
1510
            $current_access_url_id = api_get_current_access_url_id();
1511
            $sql .= " AND (access_url_id =  $current_access_url_id ) ";
1512
        }
1513
1514
        if ($return_count && $resumed_report && $extraFieldWasAdded) {
1515
            $sql .= ' AND field_id IS NOT NULL GROUP BY value ';
1516
        }
1517
1518
        if (!empty($courseCodeList)) {
1519
            $courseCodeList = array_map(['Database', 'escape_string'], $courseCodeList);
1520
            $courseCodeList = implode('","', $courseCodeList);
1521
            if (empty($sessionIdList)) {
1522
                $sql .= ' AND course.code IN ("'.$courseCodeList.'")';
1523
            }
1524
        }
1525
1526
        if (!empty($userIdList)) {
1527
            $userIdList = array_map('intval', $userIdList);
1528
            $userIdList = implode('","', $userIdList);
1529
            $sql .= ' AND user.id IN ("'.$userIdList.'")';
1530
        }
1531
1532
        if (isset($filterByActive)) {
1533
            $filterByActive = (int) $filterByActive;
1534
            $sql .= " AND user.active = $filterByActive";
1535
        }
1536
1537
        if (!empty($searchByKeyword)) {
1538
            $searchByKeyword = Database::escape_string($searchByKeyword);
1539
            $sql .= " AND (
1540
                        user.firstname LIKE '$searchByKeyword' OR
1541
                        user.username LIKE '$searchByKeyword' OR
1542
                        user.lastname LIKE '$searchByKeyword'
1543
                    ) ";
1544
        }
1545
1546
        $sql .= $whereExtraField;
1547
        $sql .= " $order_by $limit";
1548
1549
        $rs = Database::query($sql);
1550
        $users = [];
1551
1552
        $extra_fields = UserManager::get_extra_fields(
1553
            0,
1554
            100,
1555
            null,
1556
            null,
1557
            true,
1558
            true
1559
        );
1560
1561
        $counter = 1;
1562
        $count_rows = Database::num_rows($rs);
1563
1564
        if ($return_count && $resumed_report) {
1565
            return $count_rows;
1566
        }
1567
        $table_user_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1568
        $tableExtraField = Database::get_main_table(TABLE_EXTRA_FIELD);
1569
        if ($count_rows) {
1570
            while ($user = Database::fetch_array($rs)) {
1571
                if ($return_count) {
1572
                    return $user['count'];
1573
                }
1574
1575
                $report_info = [];
1576
                $user_info = $user;
1577
                $user_info['status'] = $user['status'];
1578
                if (isset($user['is_tutor'])) {
1579
                    $user_info['is_tutor'] = $user['is_tutor'];
1580
                }
1581
                if (!empty($sessionId)) {
1582
                    $user_info['status_session'] = $user['status_session'];
1583
                }
1584
1585
                $sessionId = isset($user['session_id']) ? $user['session_id'] : 0;
1586
                $sessionName = isset($user['session_name']) ? ' ('.$user['session_name'].') ' : '';
1587
1588
                if ($add_reports) {
1589
                    if ($resumed_report) {
1590
                        $extra = [];
1591
                        if (!empty($extra_fields)) {
1592
                            foreach ($extra_fields as $extra) {
1593
                                if (in_array($extra['1'], $extra_field)) {
1594
                                    $user_data = UserManager::get_extra_user_data_by_field(
1595
                                        $user['user_id'],
1596
                                        $extra['1']
1597
                                    );
1598
                                    break;
1599
                                }
1600
                            }
1601
                        }
1602
1603
                        $row_key = '-1';
1604
                        $name = '-';
1605
                        if (!empty($extra)) {
1606
                            if (!empty($user_data[$extra['1']])) {
1607
                                $row_key = $user_data[$extra['1']];
1608
                                $name = $user_data[$extra['1']];
1609
                                $users[$row_key]['extra_'.$extra['1']] = $name;
1610
                            }
1611
                        }
1612
1613
                        if (empty($users[$row_key])) {
1614
                            $users[$row_key] = [];
1615
                        }
1616
1617
                        if (!array_key_exists('training_hours', $users[$row_key])) {
1618
                            $users[$row_key]['training_hours'] = 0;
1619
                        }
1620
1621
                        $users[$row_key]['training_hours'] += Tracking::get_time_spent_on_the_course(
1622
                            $user['user_id'],
1623
                            $courseId,
1624
                            $sessionId
1625
                        );
1626
1627
                        if (!array_key_exists('count_users', $users[$row_key])) {
1628
                            $users[$row_key]['count_users'] = 0;
1629
                        }
1630
1631
                        $users[$row_key]['count_users'] += $counter;
1632
1633
                        $registered_users_with_extra_field = self::getCountRegisteredUsersWithCourseExtraField(
1634
                            $name,
1635
                            $tableExtraField,
1636
                            $table_user_field_value
1637
                        );
1638
1639
                        $users[$row_key]['count_users_registered'] = $registered_users_with_extra_field;
1640
                        $users[$row_key]['average_hours_per_user'] = $users[$row_key]['training_hours'] / $users[$row_key]['count_users'];
1641
1642
                        $category = Category:: load(
1643
                            null,
1644
                            null,
1645
                            $courseCode,
1646
                            null,
1647
                            null,
1648
                            $sessionId
1649
                        );
1650
1651
                        if (!isset($users[$row_key]['count_certificates'])) {
1652
                            $users[$row_key]['count_certificates'] = 0;
1653
                        }
1654
1655
                        if (isset($category[0]) && $category[0]->is_certificate_available($user['user_id'])) {
1656
                            $users[$row_key]['count_certificates']++;
1657
                        }
1658
1659
                        foreach ($extra_fields as $extra) {
1660
                            if ('ruc' === $extra['1']) {
1661
                                continue;
1662
                            }
1663
1664
                            if (!isset($users[$row_key][$extra['1']])) {
1665
                                $user_data = UserManager::get_extra_user_data_by_field($user['user_id'], $extra['1']);
1666
                                if (!empty($user_data[$extra['1']])) {
1667
                                    $users[$row_key][$extra['1']] = $user_data[$extra['1']];
1668
                                }
1669
                            }
1670
                        }
1671
                    } else {
1672
                        $report_info['course'] = $user['title'].$sessionName;
1673
                        $report_info['user'] = api_get_person_name($user['firstname'], $user['lastname']);
1674
                        $report_info['email'] = $user['email'];
1675
                        $report_info['time'] = api_time_to_hms(
1676
                            Tracking::get_time_spent_on_the_course(
1677
                                $user['user_id'],
1678
                                empty($user['c_id']) ? $courseId : $user['c_id'],
1679
                                $sessionId
1680
                            )
1681
                        );
1682
1683
                        $category = Category:: load(
1684
                            null,
1685
                            null,
1686
                            $courseCode,
1687
                            null,
1688
                            null,
1689
                            $sessionId
1690
                        );
1691
1692
                        $report_info['certificate'] = Display::label(get_lang('No'));
1693
                        if (isset($category[0]) && $category[0]->is_certificate_available($user['user_id'])) {
1694
                            $report_info['certificate'] = Display::label(get_lang('Yes'), 'success');
1695
                        }
1696
1697
                        $progress = (int) Tracking::get_avg_student_progress(
1698
                            $user['user_id'],
1699
                            $course,
1700
                            [],
1701
                            $session
1702
                        );
1703
1704
                        $report_info['progress_100'] = 100 == $progress ? Display::label(get_lang('Yes'), 'success') : Display::label(get_lang('No'));
1705
                        $report_info['progress'] = $progress."%";
1706
                        foreach ($extra_fields as $extra) {
1707
                            $user_data = UserManager::get_extra_user_data_by_field($user['user_id'], $extra['1']);
1708
                            $report_info[$extra['1']] = $user_data[$extra['1']];
1709
                        }
1710
                        $report_info['user_id'] = $user['user_id'];
1711
                        $users[] = $report_info;
1712
                    }
1713
                } else {
1714
                    $users[$user['user_id']] = $user_info;
1715
                }
1716
            }
1717
        }
1718
1719
        return $users;
1720
    }
1721
1722
    /**
1723
     * @param bool  $resumed_report
1724
     * @param array $extra_field
1725
     * @param array $courseCodeList
1726
     * @param array $userIdList
1727
     * @param array $sessionIdList
1728
     * @param array $options
1729
     *
1730
     * @return array|int
1731
     */
1732
    public static function get_count_user_list_from_course_code(
1733
        $resumed_report = false,
1734
        $extra_field = [],
1735
        $courseCodeList = [],
1736
        $userIdList = [],
1737
        $sessionIdList = [],
1738
        $options = []
1739
    ) {
1740
        return self::get_user_list_from_course_code(
1741
            null,
1742
            0,
1743
            null,
1744
            null,
1745
            null,
1746
            true,
1747
            false,
1748
            $resumed_report,
1749
            $extra_field,
1750
            $courseCodeList,
1751
            $userIdList,
1752
            null,
1753
            $sessionIdList,
1754
            null,
1755
            $options
1756
        );
1757
    }
1758
1759
    /**
1760
     * Gets subscribed users in a course or in a course/session.
1761
     *
1762
     * @param string $course_code
1763
     * @param int    $session_id
1764
     *
1765
     * @return int
1766
     */
1767
    public static function get_users_count_in_course(
1768
        $course_code,
1769
        $session_id = 0,
1770
        $status = null
1771
    ) {
1772
        // variable initialisation
1773
        $session_id = (int) $session_id;
1774
        $course_code = Database::escape_string($course_code);
1775
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
1776
        $tblSessionCourseUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1777
        $tblCourseUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1778
        $tblUrlUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1779
1780
        $courseInfo = api_get_course_info($course_code);
1781
        $courseId = $courseInfo['real_id'];
1782
1783
        $sql = "
1784
            SELECT DISTINCT count(user.id) as count
1785
            FROM $tblUser as user
1786
        ";
1787
        $where = [];
1788
        if (!empty($session_id)) {
1789
            $sql .= "
1790
                LEFT JOIN $tblSessionCourseUser as session_course_user
1791
                ON user.id = session_course_user.user_id
1792
                    AND session_course_user.c_id = $courseId
1793
                    AND session_course_user.session_id = $session_id
1794
            ";
1795
1796
            $where[] = ' session_course_user.c_id IS NOT NULL ';
1797
        } else {
1798
            $sql .= "
1799
                LEFT JOIN $tblCourseUser as course_rel_user
1800
                    ON user.id = course_rel_user.user_id
1801
                    AND course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
1802
                    AND course_rel_user.c_id = $courseId
1803
            ";
1804
            $where[] = ' course_rel_user.c_id IS NOT NULL ';
1805
        }
1806
1807
        $multiple_access_url = api_get_multiple_access_url();
1808
        if ($multiple_access_url) {
1809
            $sql .= " LEFT JOIN $tblUrlUser au ON (au.user_id = user.id) ";
1810
        }
1811
1812
        $sql .= ' WHERE '.implode(' OR ', $where);
1813
1814
        if ($multiple_access_url) {
1815
            $current_access_url_id = api_get_current_access_url_id();
1816
            $sql .= " AND (access_url_id =  $current_access_url_id ) ";
1817
        }
1818
        $rs = Database::query($sql);
1819
        $count = 0;
1820
        if (Database::num_rows($rs)) {
1821
            $user = Database::fetch_array($rs);
1822
            $count = $user['count'];
1823
        }
1824
1825
        return $count;
1826
    }
1827
1828
    /**
1829
     * Get a list of coaches of a course and a session.
1830
     *
1831
     * @param string $course_code
1832
     * @param int    $session_id
1833
     * @param bool   $addGeneralCoach
1834
     *
1835
     * @return array List of users
1836
     */
1837
    public static function get_coach_list_from_course_code(
1838
        $course_code,
1839
        $session_id,
1840
        $addGeneralCoach = true
1841
    ) {
1842
        if (empty($course_code) || empty($session_id)) {
1843
            return [];
1844
        }
1845
1846
        $course_code = Database::escape_string($course_code);
1847
        $courseInfo = api_get_course_info($course_code);
1848
        $courseId = $courseInfo['real_id'];
1849
        $session_id = (int) $session_id;
1850
        $users = [];
1851
1852
        // We get the coach for the given course in a given session.
1853
        $sql = 'SELECT user_id FROM '.Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER).
1854
               " WHERE session_id = $session_id AND c_id = $courseId AND status = 2";
1855
        $rs = Database::query($sql);
1856
        while ($user = Database::fetch_array($rs)) {
1857
            $userInfo = api_get_user_info($user['user_id']);
1858
            if ($userInfo) {
1859
                $users[$user['user_id']] = $userInfo;
1860
            }
1861
        }
1862
1863
        if ($addGeneralCoach) {
1864
            $table = Database::get_main_table(TABLE_MAIN_SESSION);
1865
            // We get the session coach.
1866
            $sql = "SELECT id_coach FROM $table WHERE id = $session_id";
1867
            $rs = Database::query($sql);
1868
            $session_id_coach = Database::result($rs, 0, 'id_coach');
1869
            if (is_int($session_id_coach)) {
1870
                $userInfo = api_get_user_info($session_id_coach);
1871
                if ($userInfo) {
1872
                    $users[$session_id_coach] = $userInfo;
1873
                }
1874
            }
1875
        }
1876
1877
        return $users;
1878
    }
1879
1880
    /**
1881
     *  Return user info array of all users registered in a course
1882
     *  This only returns the users that are registered in this actual course, not linked courses.
1883
     *
1884
     * @param string $course_code
1885
     * @param bool   $with_session
1886
     * @param int    $sessionId
1887
     * @param string $date_from
1888
     * @param string $date_to
1889
     * @param bool   $includeInvitedUsers Whether include the invited users
1890
     * @param int    $groupId
1891
     * @param bool   $getCount
1892
     * @param int    $start
1893
     * @param int    $limit
1894
     *
1895
     * @return array with user id
1896
     */
1897
    public static function get_student_list_from_course_code(
1898
        $course_code,
1899
        $with_session = false,
1900
        $sessionId = 0,
1901
        $date_from = null,
1902
        $date_to = null,
1903
        $includeInvitedUsers = true,
1904
        $groupId = 0,
1905
        $getCount = false,
1906
        $start = 0,
1907
        $limit = 0
1908
    ) {
1909
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1910
        $sessionId = (int) $sessionId;
1911
        $courseInfo = api_get_course_info($course_code);
1912
        if (empty($courseInfo)) {
1913
            return [];
1914
        }
1915
        $courseId = $courseInfo['real_id'];
1916
        $students = [];
1917
1918
        $limitCondition = '';
1919
        if (isset($start) && isset($limit) && !empty($limit)) {
1920
            $start = (int) $start;
1921
            $limit = (int) $limit;
1922
            $limitCondition = " LIMIT $start, $limit";
1923
        }
1924
1925
        $select = '*';
1926
        if ($getCount) {
1927
            $select = 'count(u.id) as count';
1928
        }
1929
1930
        if (empty($sessionId)) {
1931
            if (empty($groupId)) {
1932
                // students directly subscribed to the course
1933
                $sql = "SELECT $select
1934
                        FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
1935
                        INNER JOIN $userTable u
1936
                        ON cu.user_id = u.id
1937
                        WHERE c_id = $courseId AND cu.status = ".STUDENT;
1938
1939
                if (!$includeInvitedUsers) {
1940
                    $sql .= " AND u.status != ".INVITEE;
1941
                }
1942
                $sql .= $limitCondition;
1943
                $rs = Database::query($sql);
1944
1945
                if ($getCount) {
1946
                    $row = Database::fetch_array($rs);
1947
1948
                    return (int) $row['count'];
1949
                }
1950
1951
                while ($student = Database::fetch_array($rs)) {
1952
                    $students[$student['user_id']] = $student;
1953
                }
1954
            } else {
1955
                $students = GroupManager::get_users(
1956
                    $groupId,
1957
                    false,
1958
                    $start,
1959
                    $limit,
1960
                    $getCount,
1961
                    $courseInfo['real_id']
1962
                );
1963
                $students = array_flip($students);
1964
            }
1965
        }
1966
1967
        // students subscribed to the course through a session
1968
        if ($with_session) {
1969
            $joinSession = '';
1970
            //Session creation date
1971
            if (!empty($date_from) && !empty($date_to)) {
1972
                $joinSession = "INNER JOIN ".Database::get_main_table(TABLE_MAIN_SESSION)." s";
1973
            }
1974
1975
            $sql = "SELECT $select
1976
                      FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." scu
1977
                      $joinSession
1978
                      INNER JOIN $userTable u
1979
                      ON scu.user_id = u.id
1980
                      WHERE scu.c_id = $courseId AND scu.status <> 2";
1981
1982
            if (!empty($date_from) && !empty($date_to)) {
1983
                $date_from = Database::escape_string($date_from);
1984
                $date_to = Database::escape_string($date_to);
1985
                $sql .= " AND s.access_start_date >= '$date_from' AND s.access_end_date <= '$date_to'";
1986
            }
1987
1988
            if (0 != $sessionId) {
1989
                $sql .= " AND scu.session_id = $sessionId";
1990
            }
1991
1992
            if (!$includeInvitedUsers) {
1993
                $sql .= " AND u.status != ".INVITEE;
1994
            }
1995
            $sql .= $limitCondition;
1996
1997
            $rs = Database::query($sql);
1998
1999
            if ($getCount) {
2000
                $row = Database::fetch_array($rs);
2001
2002
                return (int) $row['count'];
2003
            }
2004
2005
            while ($student = Database::fetch_array($rs)) {
2006
                $students[$student['user_id']] = $student;
2007
            }
2008
        }
2009
2010
        return $students;
2011
    }
2012
2013
    /**
2014
     * Return user info array of all teacher-users registered in a course
2015
     * This only returns the users that are registered in this actual course, not linked courses.
2016
     *
2017
     * @param string $course_code
2018
     *
2019
     * @return array with user id
2020
     */
2021
    public static function get_teacher_list_from_course_code($course_code)
2022
    {
2023
        $courseInfo = api_get_course_info($course_code);
2024
        $courseId = $courseInfo['real_id'];
2025
        if (empty($courseId)) {
2026
            return false;
2027
        }
2028
2029
        $sql = "SELECT DISTINCT
2030
                    u.id as user_id,
2031
                    u.lastname,
2032
                    u.firstname,
2033
                    u.email,
2034
                    u.username,
2035
                    u.status
2036
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
2037
                INNER JOIN ".Database::get_main_table(TABLE_MAIN_USER)." u
2038
                ON (cu.user_id = u.id)
2039
                WHERE
2040
                    cu.c_id = $courseId AND
2041
                    cu.status = 1 ";
2042
        $rs = Database::query($sql);
2043
        $teachers = [];
2044
        while ($teacher = Database::fetch_array($rs)) {
2045
            $teachers[$teacher['user_id']] = $teacher;
2046
        }
2047
2048
        return $teachers;
2049
    }
2050
2051
    /**
2052
     * Return user info array of all teacher-users registered in a course
2053
     * This only returns the users that are registered in this actual course, not linked courses.
2054
     *
2055
     * @param int  $courseId
2056
     * @param bool $loadAvatars
2057
     *
2058
     * @return array with user id
2059
     */
2060
    public static function getTeachersFromCourse($courseId, $loadAvatars = true)
2061
    {
2062
        $courseId = (int) $courseId;
2063
2064
        if (empty($courseId)) {
2065
            return false;
2066
        }
2067
2068
        $sql = "SELECT DISTINCT
2069
                    u.id as user_id,
2070
                    u.lastname,
2071
                    u.firstname,
2072
                    u.email,
2073
                    u.username,
2074
                    u.status
2075
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
2076
                INNER JOIN ".Database::get_main_table(TABLE_MAIN_USER)." u
2077
                ON (cu.user_id = u.id)
2078
                WHERE
2079
                    cu.c_id = $courseId AND
2080
                    cu.status = 1 ";
2081
        $rs = Database::query($sql);
2082
        $listTeachers = [];
2083
        $teachers = [];
2084
        $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&course_id='.$courseId;
2085
        while ($teacher = Database::fetch_array($rs)) {
2086
            $teachers['id'] = $teacher['user_id'];
2087
            $teachers['lastname'] = $teacher['lastname'];
2088
            $teachers['firstname'] = $teacher['firstname'];
2089
            $teachers['email'] = $teacher['email'];
2090
            $teachers['username'] = $teacher['username'];
2091
            $teachers['status'] = $teacher['status'];
2092
            $teachers['fullname'] = api_get_person_name($teacher['firstname'], $teacher['lastname']);
2093
            $teachers['avatar'] = '';
2094
            /*if ($loadAvatars) {
2095
                $userPicture = UserManager::getUserPicture($teacher['user_id'], USER_IMAGE_SIZE_SMALL);
2096
                $teachers['avatar'] = $userPicture;
2097
            }*/
2098
            $teachers['url'] = $url.'&user_id='.$teacher['user_id'];
2099
            $listTeachers[] = $teachers;
2100
        }
2101
2102
        return $listTeachers;
2103
    }
2104
2105
    /**
2106
     * Returns a string list of teachers assigned to the given course.
2107
     *
2108
     * @param string $course_code
2109
     * @param string $separator           between teachers names
2110
     * @param bool   $add_link_to_profile Whether to add a link to the teacher's profile
2111
     * @param bool   $orderList
2112
     *
2113
     * @return string List of teachers teaching the course
2114
     */
2115
    public static function getTeacherListFromCourseCodeToString(
2116
        $course_code,
2117
        $separator = self::USER_SEPARATOR,
2118
        $add_link_to_profile = false,
2119
        $orderList = false
2120
    ) {
2121
        $teacher_list = self::get_teacher_list_from_course_code($course_code);
2122
        $html = '';
2123
        $list = [];
2124
        if (!empty($teacher_list)) {
2125
            foreach ($teacher_list as $teacher) {
2126
                $teacher_name = api_get_person_name(
2127
                    $teacher['firstname'],
2128
                    $teacher['lastname']
2129
                );
2130
                if ($add_link_to_profile) {
2131
                    $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$teacher['user_id'];
2132
                    $teacher_name = Display::url(
2133
                        $teacher_name,
2134
                        $url,
2135
                        [
2136
                            'class' => 'ajax',
2137
                            'data-title' => $teacher_name,
2138
                        ]
2139
                    );
2140
                }
2141
                $list[] = $teacher_name;
2142
            }
2143
2144
            if (!empty($list)) {
2145
                if (true === $orderList) {
2146
                    $html .= '<ul class="user-teacher">';
2147
                    foreach ($list as $teacher) {
2148
                        $html .= '<li>';
2149
                        $html .= Display::return_icon('teacher.png', '', null, ICON_SIZE_TINY);
2150
                        $html .= ' '.$teacher;
2151
                        $html .= '</li>';
2152
                    }
2153
                    $html .= '</ul>';
2154
                } else {
2155
                    $html .= array_to_string($list, $separator);
2156
                }
2157
            }
2158
        }
2159
2160
        return $html;
2161
    }
2162
2163
    /**
2164
     * This function returns information about coachs from a course in session.
2165
     *
2166
     * @param int $session_id
2167
     * @param int $courseId
2168
     *
2169
     * @return array containing user_id, lastname, firstname, username
2170
     */
2171
    public static function get_coachs_from_course($session_id = 0, $courseId = 0)
2172
    {
2173
        if (!empty($session_id)) {
2174
            $session_id = intval($session_id);
2175
        } else {
2176
            $session_id = api_get_session_id();
2177
        }
2178
2179
        if (!empty($courseId)) {
2180
            $courseId = intval($courseId);
2181
        } else {
2182
            $courseId = api_get_course_int_id();
2183
        }
2184
2185
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
2186
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2187
2188
        $sql = "SELECT DISTINCT
2189
                    u.id as user_id,
2190
                    u.lastname,
2191
                    u.firstname,
2192
                    u.username
2193
                FROM $tbl_user u
2194
                INNER JOIN $tbl_session_course_user scu
2195
                ON (u.id = scu.user_id)
2196
                WHERE
2197
                    scu.session_id = $session_id AND
2198
                    scu.c_id = $courseId AND
2199
                    scu.status = 2";
2200
        $rs = Database::query($sql);
2201
2202
        $coaches = [];
2203
        if (Database::num_rows($rs) > 0) {
2204
            while ($row = Database::fetch_array($rs)) {
2205
                $completeName = api_get_person_name($row['firstname'], $row['lastname']);
2206
                $coaches[] = $row + ['full_name' => $completeName];
2207
            }
2208
        }
2209
2210
        return $coaches;
2211
    }
2212
2213
    /**
2214
     * @param int    $session_id
2215
     * @param int    $courseId
2216
     * @param string $separator
2217
     * @param bool   $add_link_to_profile
2218
     * @param bool   $orderList
2219
     *
2220
     * @return string
2221
     */
2222
    public static function get_coachs_from_course_to_string(
2223
        $session_id = 0,
2224
        $courseId = 0,
2225
        $separator = self::USER_SEPARATOR,
2226
        $add_link_to_profile = false,
2227
        $orderList = false
2228
    ) {
2229
        $coachList = self::get_coachs_from_course($session_id, $courseId);
2230
        $course_coachs = [];
2231
        if (!empty($coachList)) {
2232
            foreach ($coachList as $coach_course) {
2233
                $coach_name = $coach_course['full_name'];
2234
                if ($add_link_to_profile) {
2235
                    $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$coach_course['user_id'].'&course_id='.$courseId.'&session_id='.$session_id;
2236
                    $coach_name = Display::url(
2237
                        $coach_name,
2238
                        $url,
2239
                        [
2240
                            'class' => 'ajax',
2241
                            'data-title' => $coach_name,
2242
                        ]
2243
                    );
2244
                }
2245
                $course_coachs[] = $coach_name;
2246
            }
2247
        }
2248
2249
        $html = '';
2250
        if (!empty($course_coachs)) {
2251
            if (true === $orderList) {
2252
                $html .= '<ul class="user-coachs">';
2253
                foreach ($course_coachs as $coachs) {
2254
                    $html .= Display::tag(
2255
                        'li',
2256
                        Display::return_icon(
2257
                            'teacher.png',
2258
                            get_lang('Coach'),
2259
                            null,
2260
                            ICON_SIZE_TINY
2261
                        ).' '.$coachs
2262
                    );
2263
                }
2264
                $html .= '</ul>';
2265
            } else {
2266
                $html = array_to_string($course_coachs, $separator);
2267
            }
2268
        }
2269
2270
        return $html;
2271
    }
2272
2273
    /**
2274
     * Get the list of groups from the course.
2275
     *
2276
     * @param string $course_code
2277
     * @param int    $session_id     Session ID (optional)
2278
     * @param int    $getEmptyGroups get empty groups (optional)
2279
     *
2280
     * @return CGroup[]
2281
     */
2282
    public static function get_group_list_of_course(
2283
        $course_code,
2284
        $session_id = 0,
2285
        $getEmptyGroups = 0
2286
    ) {
2287
        $course_info = api_get_course_info($course_code);
2288
2289
        if (empty($course_info)) {
2290
            return [];
2291
        }
2292
        $course_id = $course_info['real_id'];
2293
2294
        if (empty($course_id)) {
2295
            return [];
2296
        }
2297
2298
        $repo = Container::getGroupRepository();
2299
2300
        $course = api_get_course_entity($course_info['real_id']);
2301
        $session = api_get_session_entity($session_id);
2302
        $qb = $repo->getResourcesByCourse($course, $session);
2303
        $groups = $qb->getQuery()->getResult();
2304
        $groupList = [];
2305
        /** @var CGroup $group */
2306
        foreach ($groups as $group) {
2307
            if (0 === $getEmptyGroups) {
2308
                if (!$group->hasMembers()) {
2309
                    continue;
2310
                }
2311
            }
2312
            $groupList[$group->getIid()] = $group;
2313
        }
2314
2315
        /* 0 != $session_id ? $session_condition = ' WHERE g.session_id IN(1,'.intval($session_id).')' : $session_condition = ' WHERE g.session_id = 0';
2316
         if (0 == $in_get_empty_group) {
2317
             // get only groups that are not empty
2318
             $sql = "SELECT DISTINCT g.iid, g.name
2319
                     FROM ".Database::get_course_table(TABLE_GROUP)." AS g
2320
                     INNER JOIN ".Database::get_course_table(TABLE_GROUP_USER)." gu
2321
                     ON (g.iid = gu.group_id)
2322
                     $session_condition
2323
                     ORDER BY g.name";
2324
         } else {
2325
             // get all groups even if they are empty
2326
             $sql = "SELECT g.iid, g.name
2327
                     FROM ".Database::get_course_table(TABLE_GROUP)." AS g
2328
                     $session_condition
2329
                     AND c_id = $course_id";
2330
         }
2331
2332
         $result = Database::query($sql);
2333
         $groupList = [];
2334
         while ($groupData = Database::fetch_array($result)) {
2335
             $groupData['userNb'] = GroupManager::number_of_students($groupData['iid'], $course_id);
2336
             $groupList[$groupData['iid']] = $groupData;
2337
         }*/
2338
2339
        return $groupList;
2340
    }
2341
2342
    /**
2343
     * Delete a course
2344
     * This function deletes a whole course-area from the platform. When the
2345
     * given course is a virtual course, the database and directory will not be
2346
     * deleted.
2347
     * When the given course is a real course, also all virtual courses refering
2348
     * to the given course will be deleted.
2349
     * Considering the fact that we remove all traces of the course in the main
2350
     * database, it makes sense to remove all tracking as well (if stats databases exist)
2351
     * so that a new course created with this code would not use the remains of an older
2352
     * course.
2353
     *
2354
     * @param string $code The code of the course to delete
2355
     */
2356
    public static function delete_course($code)
2357
    {
2358
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2359
        $table_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
2360
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2361
2362
        $table_stats_hotpots = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES);
2363
        $table_stats_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
2364
        $table_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2365
        $table_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
2366
        $table_stats_lastaccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
2367
        $table_stats_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2368
        $table_stats_online = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
2369
        $table_stats_downloads = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
2370
        $table_stats_links = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
2371
        $table_stats_uploads = Database::get_main_table(TABLE_STATISTIC_TRACK_E_UPLOADS);
2372
2373
        if (empty($code)) {
2374
            return false;
2375
        }
2376
2377
        $course = api_get_course_info($code);
2378
2379
        if (empty($course)) {
2380
            return false;
2381
        }
2382
2383
        $courseId = $course['real_id'];
2384
        $courseEntity = api_get_course_entity($courseId);
2385
2386
        if (null === $courseEntity) {
2387
            return false;
2388
        }
2389
2390
        /** @var SequenceResourceRepository $repo */
2391
        $repo = Database::getManager()->getRepository(SequenceResource::class);
2392
        $sequenceResource = $repo->findRequirementForResource(
2393
            $courseId,
2394
            SequenceResource::COURSE_TYPE
2395
        );
2396
2397
        if ($sequenceResource) {
2398
            Display::addFlash(
2399
                Display::return_message(
2400
                    get_lang('ThereIsASequenceResourceLinkedToThisCourseYouNeedToDeleteItFirst'),
2401
                    'error'
2402
                )
2403
            );
2404
2405
            return false;
2406
        }
2407
2408
        $count = 0;
2409
        if (api_is_multiple_url_enabled()) {
2410
            $url_id = 1;
2411
            if (-1 != api_get_current_access_url_id()) {
2412
                $url_id = api_get_current_access_url_id();
2413
            }
2414
            UrlManager::delete_url_rel_course($courseId, $url_id);
2415
            $count = UrlManager::getCountUrlRelCourse($courseId);
2416
        }
2417
2418
        if (0 === $count) {
2419
            //self::create_database_dump($code);
2420
2421
            // Cleaning group categories
2422
            $groupCategories = GroupManager::get_categories($courseEntity);
2423
            if (!empty($groupCategories)) {
2424
                foreach ($groupCategories as $category) {
2425
                    GroupManager::delete_category($category['iid'], $course['code']);
2426
                }
2427
            }
2428
            // Cleaning groups
2429
            // @todo should be cleaned by the resource.
2430
            /*$groups = GroupManager::get_groups($courseId);
2431
            if (!empty($groups)) {
2432
                foreach ($groups as $group) {
2433
                    GroupManager::deleteGroup($group, $course['code']);
2434
                }
2435
            }*/
2436
2437
            $course_tables = AddCourse::get_course_tables();
2438
            // Cleaning c_x tables
2439
            if (!empty($courseId)) {
2440
                foreach ($course_tables as $table) {
2441
                    if ('document' === $table) {
2442
                        // Table document will be deleted by Doctrine.
2443
                        continue;
2444
                    }
2445
                    $table = Database::get_course_table($table);
2446
                    //$sql = "DELETE FROM $table WHERE c_id = $courseId ";
2447
                    //Database::query($sql);
2448
                }
2449
            }
2450
2451
            // Unsubscribe all users from the course
2452
            $sql = "DELETE FROM $table_course_user WHERE c_id = $courseId";
2453
            Database::query($sql);
2454
            // Delete the course from the sessions tables
2455
            $sql = "DELETE FROM $table_session_course WHERE c_id = $courseId";
2456
            Database::query($sql);
2457
            $sql = "DELETE FROM $table_session_course_user WHERE c_id = $courseId";
2458
            Database::query($sql);
2459
2460
            // Delete from Course - URL
2461
            // Already deleted because of entities.
2462
            //$sql = "DELETE FROM $table_course_rel_url WHERE c_id = $courseId";
2463
            //Database::query($sql);
2464
2465
            // Delete the course from the stats tables
2466
            $sql = "DELETE FROM $table_stats_hotpots WHERE c_id = $courseId";
2467
            Database::query($sql);
2468
            $sql = "DELETE FROM $table_stats_attempt WHERE c_id = $courseId";
2469
            Database::query($sql);
2470
            $sql = "DELETE FROM $table_stats_exercises WHERE c_id = $courseId";
2471
            Database::query($sql);
2472
            $sql = "DELETE FROM $table_stats_access WHERE c_id = $courseId";
2473
            Database::query($sql);
2474
            $sql = "DELETE FROM $table_stats_lastaccess WHERE c_id = $courseId";
2475
            Database::query($sql);
2476
            $sql = "DELETE FROM $table_stats_course_access WHERE c_id = $courseId";
2477
            Database::query($sql);
2478
            $sql = "DELETE FROM $table_stats_online WHERE c_id = $courseId";
2479
            Database::query($sql);
2480
            // Do not delete rows from track_e_default as these include course
2481
            // creation and other important things that do not take much space
2482
            // but give information on the course history
2483
            //$sql = "DELETE FROM $table_stats_default WHERE c_id = $courseId";
2484
            //Database::query($sql);
2485
            $sql = "DELETE FROM $table_stats_downloads WHERE c_id = $courseId";
2486
            Database::query($sql);
2487
            $sql = "DELETE FROM $table_stats_links WHERE c_id = $courseId";
2488
            Database::query($sql);
2489
            $sql = "DELETE FROM $table_stats_uploads WHERE c_id = $courseId";
2490
            Database::query($sql);
2491
2492
            // Update ticket
2493
            $table = Database::get_main_table(TABLE_TICKET_TICKET);
2494
            $sql = "UPDATE $table SET course_id = NULL WHERE course_id = $courseId";
2495
            Database::query($sql);
2496
2497
            $repo->deleteSequenceResource(
2498
                $courseId,
2499
                SequenceResource::COURSE_TYPE
2500
            );
2501
2502
            // Class
2503
            $table = Database::get_main_table(TABLE_USERGROUP_REL_COURSE);
2504
            $sql = "DELETE FROM $table
2505
                    WHERE course_id = $courseId";
2506
            Database::query($sql);
2507
2508
            // Skills
2509
            $table = Database::get_main_table(TABLE_MAIN_SKILL_REL_USER);
2510
            $argumentation = Database::escape_string(sprintf(get_lang('This skill was obtained through course %s which has been removed since then.'), $course['code']));
2511
            $sql = "UPDATE $table SET course_id = NULL, session_id = NULL, argumentation = '$argumentation'
2512
                    WHERE course_id = $courseId";
2513
            Database::query($sql);
2514
2515
            // Should be deleted by doctrine
2516
            //$sql = "DELETE FROM skill_rel_course WHERE c_id = $courseId";
2517
            //Database::query($sql);
2518
2519
            // Deletes all groups, group-users, group-tutors information
2520
            // To prevent fK mix up on some tables
2521
            //GroupManager::deleteAllGroupsFromCourse($courseId);
2522
2523
            $appPlugin = new AppPlugin();
2524
            $appPlugin->performActionsWhenDeletingItem('course', $courseId);
2525
2526
            //$repo = Container::getQuizRepository();
2527
            //$repo->deleteAllByCourse($courseEntity);
2528
2529
            // Delete the course from the database
2530
            $repo = Container::getCourseRepository();
2531
            $repo->deleteCourse($courseEntity);
2532
2533
            // delete extra course fields
2534
            $extraFieldValues = new ExtraFieldValue('course');
2535
            $extraFieldValues->deleteValuesByItem($courseId);
2536
2537
            // Add event to system log
2538
            Event::addEvent(
2539
                LOG_COURSE_DELETE,
2540
                LOG_COURSE_CODE,
2541
                $code,
2542
                api_get_utc_datetime(),
2543
                api_get_user_id(),
2544
                $courseId
2545
            );
2546
2547
            return true;
2548
        }
2549
    }
2550
2551
    /**
2552
     * Creates a file called mysql_dump.sql in the course folder.
2553
     *
2554
     * @param string $course_code The code of the course
2555
     *
2556
     * @todo Implementation for single database
2557
     */
2558
    public static function create_database_dump($course_code)
2559
    {
2560
        return false;
2561
        $sql_dump = '';
0 ignored issues
show
Unused Code introduced by
$sql_dump = '' is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
2562
        $course_code = Database::escape_string($course_code);
2563
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
2564
        $sql = "SELECT * FROM $table_course WHERE code = '$course_code'";
2565
        $res = Database::query($sql);
2566
        $course = Database::fetch_array($res);
2567
2568
        $course_tables = AddCourse::get_course_tables();
2569
2570
        if (!empty($course['id'])) {
2571
            //Cleaning c_x tables
2572
            foreach ($course_tables as $table) {
2573
                $table = Database::get_course_table($table);
2574
                $sql = "SELECT * FROM $table WHERE c_id = {$course['id']} ";
2575
                $res_table = Database::query($sql);
2576
2577
                while ($row = Database::fetch_array($res_table, 'ASSOC')) {
2578
                    $row_to_save = [];
2579
                    foreach ($row as $key => $value) {
2580
                        $row_to_save[$key] = $key."='".Database::escape_string($row[$key])."'";
2581
                    }
2582
                    $sql_dump .= "\nINSERT INTO $table SET ".implode(', ', $row_to_save).';';
2583
                }
2584
            }
2585
        }
2586
2587
        if (is_dir(api_get_path(SYS_COURSE_PATH).$course['directory'])) {
2588
            $file_name = api_get_path(SYS_COURSE_PATH).$course['directory'].'/mysql_dump.sql';
2589
            $handle = fopen($file_name, 'a+');
2590
            if (false !== $handle) {
2591
                fwrite($handle, $sql_dump);
2592
                fclose($handle);
2593
            } else {
2594
                //TODO trigger exception in a try-catch
2595
            }
2596
        }
2597
    }
2598
2599
    /**
2600
     * Sort courses for a specific user ??
2601
     *
2602
     * @param int    $user_id     User ID
2603
     * @param string $course_code Course code
2604
     *
2605
     * @return int Minimum course order
2606
     *
2607
     * @todo Review documentation
2608
     */
2609
    public static function userCourseSort($user_id, $course_code)
2610
    {
2611
        $user_id = (int) $user_id;
2612
2613
        if (empty($user_id) || empty($course_code)) {
2614
            return 0;
2615
        }
2616
2617
        $course_code = Database::escape_string($course_code);
2618
        $TABLECOURSE = Database::get_main_table(TABLE_MAIN_COURSE);
2619
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2620
2621
        $course_title = Database::result(
2622
            Database::query(
2623
                "SELECT title FROM $TABLECOURSE WHERE code = '$course_code'"
2624
            ),
2625
            0,
2626
            0
2627
        );
2628
        if (false === $course_title) {
2629
            $course_title = '';
2630
        }
2631
2632
        $sql = "SELECT course.code as code, course.title as title, cu.sort as sort
2633
                FROM $TABLECOURSUSER as cu, $TABLECOURSE as course
2634
                WHERE   course.id = cu.c_id AND user_id = $user_id AND
2635
                        cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
2636
                        user_course_cat = 0
2637
                ORDER BY cu.sort";
2638
        $result = Database::query($sql);
2639
2640
        $course_title_precedent = '';
2641
        $counter = 0;
2642
        $course_found = false;
2643
        $course_sort = 1;
2644
2645
        if (Database::num_rows($result) > 0) {
2646
            while ($courses = Database::fetch_array($result)) {
2647
                if ('' == $course_title_precedent) {
2648
                    $course_title_precedent = $courses['title'];
2649
                }
2650
                if (api_strcasecmp($course_title_precedent, $course_title) < 0) {
2651
                    $course_found = true;
2652
                    if (!empty($courses['sort'])) {
2653
                        $course_sort = $courses['sort'];
2654
                    }
2655
                    if (0 == $counter) {
2656
                        $sql = "UPDATE $TABLECOURSUSER
2657
                                SET sort = sort+1
2658
                                WHERE
2659
                                    user_id= $user_id AND
2660
                                    relation_type <> ".COURSE_RELATION_TYPE_RRHH."
2661
                                    AND user_course_cat = 0
2662
                                    AND sort > $course_sort";
2663
                        $course_sort++;
2664
                    } else {
2665
                        $sql = "UPDATE $TABLECOURSUSER SET sort = sort+1
2666
                                WHERE
2667
                                    user_id= $user_id AND
2668
                                    relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
2669
                                    user_course_cat = 0 AND
2670
                                    sort >= $course_sort";
2671
                    }
2672
                    Database::query($sql);
2673
                    break;
2674
                } else {
2675
                    $course_title_precedent = $courses['title'];
2676
                }
2677
                $counter++;
2678
            }
2679
2680
            // We must register the course in the beginning of the list
2681
            if (!$course_found) {
2682
                $course_sort = Database::result(
2683
                    Database::query(
2684
                        'SELECT min(sort) as min_sort FROM '.$TABLECOURSUSER.' WHERE user_id = "'.$user_id.'" AND user_course_cat="0"'
2685
                    ),
2686
                    0,
2687
                    0
2688
                );
2689
                Database::query("UPDATE $TABLECOURSUSER SET sort = sort+1 WHERE user_id = $user_id AND user_course_cat = 0");
2690
            }
2691
        }
2692
2693
        return (int) $course_sort;
2694
    }
2695
2696
    /**
2697
     * check if course exists.
2698
     *
2699
     * @param string $courseCode
2700
     *
2701
     * @return int if exists, false else
2702
     */
2703
    public static function course_exists($courseCode)
2704
    {
2705
        $courseCode = Database::escape_string($courseCode);
2706
        $sql = "SELECT 1 FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
2707
                WHERE code = '$courseCode'";
2708
2709
        return Database::num_rows(Database::query($sql));
2710
    }
2711
2712
    /**
2713
     * Send an email to tutor after the auth-suscription of a student in your course.
2714
     *
2715
     * @author Carlos Vargas <[email protected]>, Dokeos Latino
2716
     *
2717
     * @param int    $user_id            the id of the user
2718
     * @param string $courseId           the course code
2719
     * @param bool   $send_to_tutor_also
2720
     *
2721
     * @return false|null we return the message that is displayed when the action is successful
2722
     */
2723
    public static function email_to_tutor($user_id, $courseId, $send_to_tutor_also = false)
2724
    {
2725
        $user_id = (int) $user_id;
2726
        $courseId = (int) $courseId;
2727
        $information = api_get_course_info_by_id($courseId);
2728
        $course_code = $information['code'];
2729
        $student = api_get_user_info($user_id);
2730
2731
        $name_course = $information['title'];
2732
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
2733
                WHERE c_id = $courseId";
2734
2735
        // TODO: Ivan: This is a mistake, please, have a look at it. Intention here is diffcult to be guessed.
2736
        //if ($send_to_tutor_also = true)
2737
        // Proposed change:
2738
        if ($send_to_tutor_also) {
2739
            $sql .= ' AND is_tutor = 1';
2740
        } else {
2741
            $sql .= ' AND status = 1';
2742
        }
2743
2744
        $result = Database::query($sql);
2745
        while ($row = Database::fetch_array($result)) {
2746
            $tutor = api_get_user_info($row['user_id']);
2747
            $emailto = $tutor['email'];
2748
            $emailsubject = get_lang('New user in the course').': '.$name_course;
2749
            $emailbody = get_lang('Dear').': '.api_get_person_name($tutor['firstname'], $tutor['lastname'])."\n";
2750
            $emailbody .= get_lang('MessageNew user in the course').': '.$name_course."\n";
2751
            $emailbody .= get_lang('Username').': '.$student['username']."\n";
2752
            if (api_is_western_name_order()) {
2753
                $emailbody .= get_lang('First name').': '.$student['firstname']."\n";
2754
                $emailbody .= get_lang('Last name').': '.$student['lastname']."\n";
2755
            } else {
2756
                $emailbody .= get_lang('Last name').': '.$student['lastname']."\n";
2757
                $emailbody .= get_lang('First name').': '.$student['firstname']."\n";
2758
            }
2759
            $emailbody .= get_lang('e-mail').': <a href="mailto:'.$student['email'].'">'.$student['email']."</a>\n\n";
2760
            $recipient_name = api_get_person_name(
2761
                $tutor['firstname'],
2762
                $tutor['lastname'],
2763
                null,
2764
                PERSON_NAME_EMAIL_ADDRESS
2765
            );
2766
            $sender_name = api_get_person_name(
2767
                api_get_setting('administratorName'),
2768
                api_get_setting('administratorSurname'),
2769
                null,
2770
                PERSON_NAME_EMAIL_ADDRESS
2771
            );
2772
            $email_admin = api_get_setting('emailAdministrator');
2773
2774
            $additionalParameters = [
2775
                'smsType' => SmsPlugin::NEW_USER_SUBSCRIBED_COURSE,
2776
                'userId' => $tutor['user_id'],
2777
                'userUsername' => $student['username'],
2778
                'courseCode' => $course_code,
2779
            ];
2780
            api_mail_html(
2781
                $recipient_name,
2782
                $emailto,
2783
                $emailsubject,
2784
                $emailbody,
2785
                $sender_name,
2786
                $email_admin,
2787
                null,
2788
                null,
2789
                null,
2790
                $additionalParameters
2791
            );
2792
        }
2793
    }
2794
2795
    /**
2796
     * @return array
2797
     */
2798
    public static function get_special_course_list()
2799
    {
2800
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
2801
        $tbl_course_field = Database::get_main_table(TABLE_EXTRA_FIELD);
2802
        $tbl_course_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2803
        $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2804
2805
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
2806
2807
        $courseList = [];
2808
        // get course list auto-register
2809
2810
        $sql = "SELECT id FROM $tbl_course_field
2811
                WHERE extra_field_type = $extraFieldType AND
2812
                variable = 'special_course'";
2813
        $result = Database::query($sql);
2814
        $courseList = [];
2815
2816
        if (Database::num_rows($result) > 0) {
2817
            $row = Database::fetch_assoc($result);
2818
            // Get list of special courses (appear to all)
2819
            // Note: The value is better indexed as string, so
2820
            // using '1' instead of integer is more efficient
2821
            $sql = "SELECT DISTINCT(item_id) as cid
2822
                FROM $tbl_course_field_value
2823
                WHERE field_id = ".$row['id']." AND value = '1'";
2824
            $result = Database::query($sql);
2825
            while ($row = Database::fetch_assoc($result)) {
2826
                $courseList[] = $row['cid'];
2827
            }
2828
            if (count($courseList) < 1) {
2829
                return $courseList;
2830
            }
2831
            if (api_get_multiple_access_url()) {
2832
                //we filter the courses by the active URL
2833
                $coursesSelect = '';
2834
                if (1 == count($courseList)) {
2835
                    $coursesSelect = $courseList[0];
2836
                } else {
2837
                    $coursesSelect = implode(',', $courseList);
2838
                }
2839
                $access_url_id = api_get_current_access_url_id();
2840
                if (-1 != $access_url_id) {
2841
                    $sql = "SELECT c_id FROM $tbl_url_course
2842
                            WHERE access_url_id = $access_url_id
2843
                            AND c_id IN ($coursesSelect)";
2844
                    $result = Database::query($sql);
2845
                    while ($row = Database::fetch_assoc($result)) {
2846
                        $courseList[] = $row['c_id'];
2847
                    }
2848
                }
2849
            }
2850
        }
2851
2852
        return $courseList;
2853
    }
2854
2855
    /**
2856
     * Get the course codes that have been restricted in the catalogue, and if byUserId is set
2857
     * then the courses that the user is allowed or not to see in catalogue.
2858
     *
2859
     * @param bool $allowed  Either if the courses have some users that are or are not allowed to see in catalogue
2860
     * @param int  $byUserId if the courses are or are not allowed to see to the user
2861
     *
2862
     * @return array Course codes allowed or not to see in catalogue by some user or the user
2863
     */
2864
    public static function getCatalogCourseList($allowed = true, $byUserId = -1)
2865
    {
2866
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
2867
        $tblCourseRelUserCatalogue = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
2868
        $visibility = $allowed ? 1 : 0;
2869
2870
        // Restriction by user id
2871
        $currentUserRestriction = '';
2872
2873
        $byUserId = (int) $byUserId;
2874
        if ($byUserId > 0) {
2875
            $currentUserRestriction = " AND tcruc.user_id = $byUserId ";
2876
        }
2877
2878
        //we filter the courses from the URL
2879
        $joinAccessUrl = '';
2880
        $whereAccessUrl = '';
2881
        if (api_get_multiple_access_url()) {
2882
            $accessUrlId = api_get_current_access_url_id();
2883
            if (-1 != $accessUrlId) {
2884
                $tblUrlCourse = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2885
                $joinAccessUrl = "LEFT JOIN $tblUrlCourse url_rel_course
2886
                                  ON url_rel_course.c_id = c.id ";
2887
                $whereAccessUrl = " AND access_url_id = $accessUrlId ";
2888
            }
2889
        }
2890
2891
        // get course list auto-register
2892
        $sql = "SELECT DISTINCT(c.code)
2893
                FROM $tblCourseRelUserCatalogue tcruc
2894
                INNER JOIN $courseTable c
2895
                ON (c.id = tcruc.c_id) $joinAccessUrl
2896
                WHERE tcruc.visible = $visibility $currentUserRestriction $whereAccessUrl";
2897
2898
        $result = Database::query($sql);
2899
        $courseList = [];
2900
2901
        if (Database::num_rows($result) > 0) {
2902
            while ($resultRow = Database::fetch_array($result)) {
2903
                $courseList[] = $resultRow['code'];
2904
            }
2905
        }
2906
2907
        return $courseList;
2908
    }
2909
2910
    /**
2911
     * Get list of courses for a given user.
2912
     *
2913
     * @param int   $user_id
2914
     * @param bool  $include_sessions                   Whether to include courses from session or not
2915
     * @param bool  $adminGetsAllCourses                If the user is platform admin,
2916
     *                                                  whether he gets all the courses or just his. Note: This does
2917
     *                                                  *not* include all sessions
2918
     * @param bool  $loadSpecialCourses
2919
     * @param array $skipCourseList                     List of course ids to skip
2920
     * @param bool  $useUserLanguageFilterIfAvailable
2921
     * @param bool  $showCoursesSessionWithDifferentKey
2922
     *
2923
     * @return array List of codes and db name
2924
     *
2925
     * @author isaac flores paz
2926
     */
2927
    public static function get_courses_list_by_user_id(
2928
        $user_id,
2929
        $include_sessions = false,
2930
        $adminGetsAllCourses = false,
2931
        $loadSpecialCourses = true,
2932
        $skipCourseList = [],
2933
        $useUserLanguageFilterIfAvailable = true,
2934
        $showCoursesSessionWithDifferentKey = false
2935
    ) {
2936
        $user_id = intval($user_id);
2937
        $urlId = api_get_current_access_url_id();
2938
        $course_list = [];
2939
        $codes = [];
2940
2941
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2942
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2943
        $tableCourseUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2944
        $tblCourseCategory = Database::get_main_table(TABLE_MAIN_CATEGORY);
2945
2946
        $languageCondition = '';
2947
        $onlyInUserLanguage = api_get_configuration_value('my_courses_show_courses_in_user_language_only');
2948
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
2949
            $userInfo = api_get_user_info(api_get_user_id());
2950
            if (!empty($userInfo['language'])) {
2951
                $languageCondition = " AND course.course_language = '".$userInfo['language']."' ";
2952
            }
2953
        }
2954
2955
        if ($adminGetsAllCourses && UserManager::is_admin($user_id)) {
2956
            // get the whole courses list
2957
            $sql = "SELECT DISTINCT(course.code), course.id as real_id, course.title
2958
                    FROM $tbl_course course
2959
                    INNER JOIN $tableCourseUrl url
2960
                    ON (course.id = url.c_id)
2961
                    WHERE
2962
                        url.access_url_id = $urlId
2963
                        $languageCondition
2964
                ";
2965
        } else {
2966
            $withSpecialCourses = $withoutSpecialCourses = '';
2967
2968
            if ($loadSpecialCourses) {
2969
                $specialCourseList = self::get_special_course_list();
2970
2971
                if (!empty($specialCourseList)) {
2972
                    $specialCourseToString = '"'.implode('","', $specialCourseList).'"';
2973
                    $withSpecialCourses = ' AND course.id IN ('.$specialCourseToString.')';
2974
                    $withoutSpecialCourses = ' AND course.id NOT IN ('.$specialCourseToString.')';
2975
                }
2976
2977
                if (!empty($withSpecialCourses)) {
2978
                    $sql = "SELECT DISTINCT (course.code),
2979
                            course.id as real_id,
2980
                            course_category.code AS category,
2981
                            course.title
2982
                            FROM $tbl_course_user course_rel_user
2983
                            LEFT JOIN $tbl_course course
2984
                            ON course.id = course_rel_user.c_id
2985
                            LEFT JOIN $tblCourseCategory ON course_category.id = course.category_id
2986
                            INNER JOIN $tableCourseUrl url
2987
                            ON (course.id = url.c_id)
2988
                            WHERE url.access_url_id = $urlId
2989
                            $withSpecialCourses
2990
                            $languageCondition
2991
                            GROUP BY course.code
2992
                            ORDER BY course.title, course_rel_user.sort ASC
2993
                    ";
2994
                    $result = Database::query($sql);
2995
                    if (Database::num_rows($result) > 0) {
2996
                        while ($result_row = Database::fetch_array($result, 'ASSOC')) {
2997
                            $result_row['special_course'] = 1;
2998
                            $course_list[] = $result_row;
2999
                            $codes[] = $result_row['real_id'];
3000
                        }
3001
                    }
3002
                }
3003
            }
3004
3005
            // get course list not auto-register. Use Distinct to avoid multiple
3006
            // entries when a course is assigned to a HRD (DRH) as watcher
3007
            $sql = "SELECT
3008
                        DISTINCT(course.code),
3009
                        course.id as real_id,
3010
                        course.title
3011
                    FROM $tbl_course course
3012
                    INNER JOIN $tbl_course_user cru
3013
                    ON (course.id = cru.c_id)
3014
                    INNER JOIN $tableCourseUrl url
3015
                    ON (course.id = url.c_id)
3016
                    WHERE
3017
                        url.access_url_id = $urlId AND
3018
                        cru.user_id = $user_id
3019
                        $withoutSpecialCourses
3020
                        $languageCondition
3021
                    ORDER BY course.title
3022
                    ";
3023
        }
3024
        $result = Database::query($sql);
3025
3026
        if (Database::num_rows($result)) {
3027
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3028
                if (!empty($skipCourseList)) {
3029
                    if (in_array($row['real_id'], $skipCourseList)) {
3030
                        continue;
3031
                    }
3032
                }
3033
                $course_list[] = $row;
3034
                $codes[] = $row['real_id'];
3035
            }
3036
        }
3037
3038
        if (true === $include_sessions) {
3039
            $sql = "SELECT DISTINCT (c.code),
3040
                        c.id as real_id,
3041
                        s.id as session_id,
3042
                        s.name as session_name
3043
                    FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." scu
3044
                    INNER JOIN $tbl_course c
3045
                    ON (scu.c_id = c.id)
3046
                    INNER JOIN ".Database::get_main_table(TABLE_MAIN_SESSION)." s
3047
                    ON (s.id = scu.session_id)
3048
                    WHERE user_id = $user_id ";
3049
            $r = Database::query($sql);
3050
            while ($row = Database::fetch_array($r, 'ASSOC')) {
3051
                if (!empty($skipCourseList)) {
3052
                    if (in_array($row['real_id'], $skipCourseList)) {
3053
                        continue;
3054
                    }
3055
                }
3056
3057
                if ($showCoursesSessionWithDifferentKey) {
3058
                    $course_list[] = $row;
3059
                } else {
3060
                    if (!in_array($row['real_id'], $codes)) {
3061
                        $course_list[] = $row;
3062
                    }
3063
                }
3064
            }
3065
        }
3066
3067
        return $course_list;
3068
    }
3069
3070
    /**
3071
     * Get course ID from a given course directory name.
3072
     *
3073
     * @param string $path Course directory (without any slash)
3074
     *
3075
     * @return string Course code, or false if not found
3076
     */
3077
    public static function getCourseCodeFromDirectory($path)
3078
    {
3079
        $path = Database::escape_string(str_replace('.', '', str_replace('/', '', $path)));
3080
        $res = Database::query("SELECT code FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
3081
                WHERE directory LIKE BINARY '$path'");
3082
        if (false === $res) {
3083
            return false;
3084
        }
3085
        if (1 != Database::num_rows($res)) {
3086
            return false;
3087
        }
3088
        $row = Database::fetch_array($res);
3089
3090
        return $row['code'];
3091
    }
3092
3093
    /**
3094
     * Get course code(s) from visual code.
3095
     *
3096
     * @param   string  Visual code
3097
     *
3098
     * @return array List of codes for the given visual code
3099
     */
3100
    public static function get_courses_info_from_visual_code($code)
3101
    {
3102
        $result = [];
3103
        $sql_result = Database::query("SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
3104
                WHERE visual_code = '".Database::escape_string($code)."'");
3105
        while ($virtual_course = Database::fetch_array($sql_result)) {
3106
            $result[] = $virtual_course;
3107
        }
3108
3109
        return $result;
3110
    }
3111
3112
    /**
3113
     * Creates a new extra field for a given course.
3114
     *
3115
     * @param string $variable    Field's internal variable name
3116
     * @param int    $fieldType   Field's type
3117
     * @param string $displayText Field's language var name
3118
     * @param string $default     Optional. The default value
3119
     *
3120
     * @return int New extra field ID
3121
     */
3122
    public static function create_course_extra_field($variable, $fieldType, $displayText, $default = '')
3123
    {
3124
        $extraField = new ExtraField('course');
3125
        $params = [
3126
            'variable' => $variable,
3127
            'field_type' => $fieldType,
3128
            'display_text' => $displayText,
3129
            'default_value' => $default,
3130
        ];
3131
3132
        return $extraField->save($params);
3133
    }
3134
3135
    /**
3136
     * Update course attributes. Will only update attributes with a non-empty value.
3137
     * Note that you NEED to check that your attributes are valid before using this function.
3138
     *
3139
     * @param int Course id
3140
     * @param array Associative array with field names as keys and field values as values
3141
     *
3142
     * @return Doctrine\DBAL\Driver\Statement|null True if update was successful, false otherwise
3143
     */
3144
    public static function update_attributes($id, $attributes)
3145
    {
3146
        $id = (int) $id;
3147
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
3148
        $sql = "UPDATE $table SET ";
3149
        $i = 0;
3150
        foreach ($attributes as $name => $value) {
3151
            if ('' != $value) {
3152
                if ($i > 0) {
3153
                    $sql .= ", ";
3154
                }
3155
                $sql .= " $name = '".Database::escape_string($value)."'";
3156
                $i++;
3157
            }
3158
        }
3159
        $sql .= " WHERE id = $id";
3160
3161
        return Database::query($sql);
3162
    }
3163
3164
    /**
3165
     * Update an extra field value for a given course.
3166
     *
3167
     * @param string $course_code Course code
3168
     * @param string $variable    Field variable name
3169
     * @param string $value       Optional. Default field value
3170
     *
3171
     * @return bool|int An integer when register a new extra field. And boolean when update the extrafield
3172
     */
3173
    public static function update_course_extra_field_value($course_code, $variable, $value = '')
3174
    {
3175
        $courseInfo = api_get_course_info($course_code);
3176
        $courseId = $courseInfo['real_id'];
3177
3178
        $extraFieldValues = new ExtraFieldValue('course');
3179
        $params = [
3180
            'item_id' => $courseId,
3181
            'variable' => $variable,
3182
            'value' => $value,
3183
        ];
3184
3185
        return $extraFieldValues->save($params);
3186
    }
3187
3188
    /**
3189
     * @param int $sessionId
3190
     *
3191
     * @return mixed
3192
     */
3193
    public static function get_session_category_id_by_session_id($sessionId)
3194
    {
3195
        if (empty($sessionId)) {
3196
            return [];
3197
        }
3198
        $sessionId = intval($sessionId);
3199
        $sql = 'SELECT sc.id session_category
3200
                FROM '.Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY).' sc
3201
                INNER JOIN '.Database::get_main_table(TABLE_MAIN_SESSION).' s
3202
                ON sc.id = s.session_category_id
3203
                WHERE s.id = '.$sessionId;
3204
3205
        return Database::result(
3206
            Database::query($sql),
3207
            0,
3208
            'session_category'
3209
        );
3210
    }
3211
3212
    /**
3213
     * Gets the value of a course extra field. Returns null if it was not found.
3214
     *
3215
     * @param string $variable Name of the extra field
3216
     * @param string $code     Course code
3217
     *
3218
     * @return string Value
3219
     */
3220
    public static function get_course_extra_field_value($variable, $code)
3221
    {
3222
        $courseInfo = api_get_course_info($code);
3223
        $courseId = $courseInfo['real_id'];
3224
3225
        $extraFieldValues = new ExtraFieldValue('course');
3226
        $result = $extraFieldValues->get_values_by_handler_and_field_variable($courseId, $variable);
3227
        if (!empty($result['value'])) {
3228
            return $result['value'];
3229
        }
3230
3231
        return null;
3232
    }
3233
3234
    /**
3235
     * Gets extra field value data and formatted values of a course
3236
     * for extra fields listed in configuration.php in my_course_course_extrafields_to_be_presented
3237
     * (array of variables as value of key 'fields').
3238
     *
3239
     * @param $courseId  int The numeric identifier of the course
3240
     *
3241
     * @return array of data and formatted values as returned by ExtraField::getDataAndFormattedValues
3242
     */
3243
    public static function getExtraFieldsToBePresented($courseId)
3244
    {
3245
        $extraFields = [];
3246
        $fields = api_get_configuration_sub_value('my_course_course_extrafields_to_be_presented/fields');
3247
        if (!empty($fields) && is_array($fields)) {
3248
            $extraFieldManager = new ExtraField('course');
3249
            $dataAndFormattedValues = $extraFieldManager->getDataAndFormattedValues($courseId);
3250
            foreach ($fields as $variable) {
3251
                foreach ($dataAndFormattedValues as $value) {
3252
                    if ($value['variable'] === $variable && !empty($value['value'])) {
3253
                        $extraFields[] = $value;
3254
                    }
3255
                }
3256
            }
3257
        }
3258
3259
        return $extraFields;
3260
    }
3261
3262
    /**
3263
     * Lists details of the course description.
3264
     *
3265
     * @param array        The course description
3266
     * @param string    The encoding
3267
     * @param bool        If true is displayed if false is hidden
3268
     *
3269
     * @return string The course description in html
3270
     */
3271
    public static function get_details_course_description_html(
3272
        $descriptions,
3273
        $charset,
3274
        $action_show = true
3275
    ) {
3276
        $data = null;
3277
        if (isset($descriptions) && count($descriptions) > 0) {
3278
            foreach ($descriptions as $description) {
3279
                $data .= '<div class="sectiontitle">';
3280
                if (api_is_allowed_to_edit() && $action_show) {
3281
                    //delete
3282
                    $data .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=delete&description_id='.$description->id.'" onclick="javascript:if(!confirm(\''.addslashes(api_htmlentities(
3283
                        get_lang('Please confirm your choice'),
3284
                                ENT_QUOTES,
3285
                        $charset
3286
                    )).'\')) return false;">';
3287
                    $data .= Display::return_icon(
3288
                        'delete.gif',
3289
                        get_lang('Delete'),
3290
                        ['style' => 'vertical-align:middle;float:right;']
3291
                    );
3292
                    $data .= '</a> ';
3293
                    //edit
3294
                    $data .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&description_id='.$description->id.'">';
3295
                    $data .= Display::return_icon(
3296
                        'edit.png',
3297
                        get_lang('Edit'),
3298
                        ['style' => 'vertical-align:middle;float:right; padding-right:4px;'],
3299
                        ICON_SIZE_SMALL
3300
                    );
3301
                    $data .= '</a> ';
3302
                }
3303
                $data .= $description->title;
3304
                $data .= '</div>';
3305
                $data .= '<div class="sectioncomment">';
3306
                $data .= Security::remove_XSS($description->content);
3307
                $data .= '</div>';
3308
            }
3309
        } else {
3310
            $data .= '<em>'.get_lang('There is no course description so far.').'</em>';
3311
        }
3312
3313
        return $data;
3314
    }
3315
3316
    /**
3317
     * Returns the details of a course category.
3318
     *
3319
     * @param string $code Category code
3320
     *
3321
     * @return array Course category
3322
     */
3323
    public static function get_course_category($code)
3324
    {
3325
        $table = Database::get_main_table(TABLE_MAIN_CATEGORY);
3326
        $code = Database::escape_string($code);
3327
        $sql = "SELECT * FROM $table WHERE code = '$code'";
3328
3329
        return Database::fetch_array(Database::query($sql));
3330
    }
3331
3332
    /**
3333
     * Subscribes courses to human resource manager (Dashboard feature).
3334
     *
3335
     * @param int   $hr_manager_id Human Resource Manager id
3336
     * @param array $courses_list  Courses code
3337
     *
3338
     * @return int
3339
     */
3340
    public static function subscribeCoursesToDrhManager($hr_manager_id, $courses_list)
3341
    {
3342
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3343
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3344
3345
        $hr_manager_id = intval($hr_manager_id);
3346
        $affected_rows = 0;
3347
3348
        //Deleting assigned courses to hrm_id
3349
        if (api_is_multiple_url_enabled()) {
3350
            $sql = "SELECT s.c_id FROM $tbl_course_rel_user s
3351
                    INNER JOIN $tbl_course_rel_access_url a
3352
                    ON (a.c_id = s.c_id)
3353
                    WHERE
3354
                        user_id = $hr_manager_id AND
3355
                        relation_type = ".COURSE_RELATION_TYPE_RRHH." AND
3356
                        access_url_id = ".api_get_current_access_url_id();
3357
        } else {
3358
            $sql = "SELECT c_id FROM $tbl_course_rel_user
3359
                    WHERE user_id = $hr_manager_id AND relation_type = ".COURSE_RELATION_TYPE_RRHH;
3360
        }
3361
        $result = Database::query($sql);
3362
        if (Database::num_rows($result) > 0) {
3363
            while ($row = Database::fetch_array($result)) {
3364
                $sql = "DELETE FROM $tbl_course_rel_user
3365
                        WHERE
3366
                            c_id = {$row['c_id']} AND
3367
                            user_id = $hr_manager_id AND
3368
                            relation_type = ".COURSE_RELATION_TYPE_RRHH;
3369
                Database::query($sql);
3370
            }
3371
        }
3372
3373
        // inserting new courses list
3374
        if (is_array($courses_list)) {
3375
            foreach ($courses_list as $course_code) {
3376
                $courseInfo = api_get_course_info($course_code);
3377
                $courseId = $courseInfo['real_id'];
3378
                $sql = "INSERT IGNORE INTO $tbl_course_rel_user(c_id, user_id, status, relation_type)
3379
                        VALUES($courseId, $hr_manager_id, ".DRH.", ".COURSE_RELATION_TYPE_RRHH.")";
3380
                $result = Database::query($sql);
3381
                if (Database::affected_rows($result)) {
3382
                    $affected_rows++;
3383
                }
3384
            }
3385
        }
3386
3387
        return $affected_rows;
3388
    }
3389
3390
    /**
3391
     * get courses followed by human resources manager.
3392
     *
3393
     * @param int    $user_id
3394
     * @param int    $status
3395
     * @param int    $from
3396
     * @param int    $limit
3397
     * @param string $column
3398
     * @param string $direction
3399
     * @param bool   $getCount
3400
     *
3401
     * @return array courses
3402
     */
3403
    public static function get_courses_followed_by_drh(
3404
        $user_id,
3405
        $status = DRH,
3406
        $from = null,
3407
        $limit = null,
3408
        $column = null,
3409
        $direction = null,
3410
        $getCount = false
3411
    ) {
3412
        return self::getCoursesFollowedByUser(
3413
            $user_id,
3414
            $status,
3415
            $from,
3416
            $limit,
3417
            $column,
3418
            $direction,
3419
            $getCount
3420
        );
3421
    }
3422
3423
    /**
3424
     * get courses followed by user.
3425
     *
3426
     * @param int    $user_id
3427
     * @param int    $status
3428
     * @param int    $from
3429
     * @param int    $limit
3430
     * @param string $column
3431
     * @param string $direction
3432
     * @param bool   $getCount
3433
     * @param string $keyword
3434
     * @param int    $sessionId
3435
     * @param bool   $showAllAssignedCourses
3436
     *
3437
     * @return array courses
3438
     */
3439
    public static function getCoursesFollowedByUser(
3440
        $user_id,
3441
        $status = null,
3442
        $from = null,
3443
        $limit = null,
3444
        $column = null,
3445
        $direction = null,
3446
        $getCount = false,
3447
        $keyword = null,
3448
        $sessionId = 0,
3449
        $showAllAssignedCourses = false
3450
    ) {
3451
        // Database Table Definitions
3452
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3453
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3454
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3455
        $sessionId = (int) $sessionId;
3456
        $user_id = (int) $user_id;
3457
        $select = "SELECT DISTINCT c.*, c.id as real_id ";
3458
3459
        if ($getCount) {
3460
            $select = "SELECT COUNT(DISTINCT c.id) as count";
3461
        }
3462
3463
        $whereConditions = '';
3464
        switch ($status) {
3465
            case COURSEMANAGER:
3466
                $whereConditions .= " AND cru.user_id = $user_id";
3467
                if (!$showAllAssignedCourses) {
3468
                    $whereConditions .= " AND cru.status = ".COURSEMANAGER;
3469
                } else {
3470
                    $whereConditions .= " AND relation_type = ".COURSE_RELATION_TYPE_COURSE_MANAGER;
3471
                }
3472
                break;
3473
            case DRH:
3474
                $whereConditions .= " AND
3475
                    cru.user_id = $user_id AND
3476
                    cru.status = ".DRH." AND
3477
                    relation_type = '".COURSE_RELATION_TYPE_RRHH."'
3478
                ";
3479
                break;
3480
        }
3481
3482
        $keywordCondition = null;
3483
        if (!empty($keyword)) {
3484
            $keyword = Database::escape_string($keyword);
3485
            $keywordCondition = " AND (c.code LIKE '%$keyword%' OR c.title LIKE '%$keyword%' ) ";
3486
        }
3487
3488
        $orderBy = null;
3489
        $extraInnerJoin = null;
3490
3491
        if (!empty($sessionId)) {
3492
            if (COURSEMANAGER == $status) {
3493
                // Teacher of course or teacher inside session
3494
                $whereConditions = " AND (cru.status = ".COURSEMANAGER." OR srcru.status = 2) ";
3495
            }
3496
            $courseList = SessionManager::get_course_list_by_session_id($sessionId);
3497
            if (!empty($courseList)) {
3498
                $courseListToString = implode("','", array_keys($courseList));
3499
                $whereConditions .= " AND c.id IN ('".$courseListToString."')";
3500
            }
3501
            $tableSessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3502
            $tableSessionRelCourseRelUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3503
            $orderBy = ' ORDER BY position';
3504
            $extraInnerJoin = " INNER JOIN $tableSessionRelCourse src
3505
                                ON (c.id = src.c_id AND src.session_id = $sessionId)
3506
                                INNER JOIN $tableSessionRelCourseRelUser srcru
3507
                                ON (src.session_id = srcru.session_id AND srcru.c_id = src.c_id)
3508
                            ";
3509
        }
3510
3511
        $whereConditions .= $keywordCondition;
3512
        $sql = "$select
3513
                FROM $tbl_course c
3514
                INNER JOIN $tbl_course_rel_user cru
3515
                ON (cru.c_id = c.id)
3516
                INNER JOIN $tbl_course_rel_access_url a
3517
                ON (a.c_id = c.id)
3518
                $extraInnerJoin
3519
                WHERE
3520
                    access_url_id = ".api_get_current_access_url_id()."
3521
                    $whereConditions
3522
                $orderBy
3523
                ";
3524
        if (isset($from) && isset($limit)) {
3525
            $from = intval($from);
3526
            $limit = intval($limit);
3527
            $sql .= " LIMIT $from, $limit";
3528
        }
3529
3530
        $result = Database::query($sql);
3531
3532
        if ($getCount) {
3533
            $row = Database::fetch_array($result);
3534
3535
            return $row['count'];
3536
        }
3537
3538
        $courses = [];
3539
        if (Database::num_rows($result) > 0) {
3540
            while ($row = Database::fetch_array($result)) {
3541
                $courses[$row['code']] = $row;
3542
            }
3543
        }
3544
3545
        return $courses;
3546
    }
3547
3548
    /**
3549
     * check if a course is special (autoregister).
3550
     *
3551
     * @param int $courseId
3552
     *
3553
     * @return bool
3554
     */
3555
    public static function isSpecialCourse($courseId)
3556
    {
3557
        $extraFieldValue = new ExtraFieldValue('course');
3558
        $result = $extraFieldValue->get_values_by_handler_and_field_variable(
3559
            $courseId,
3560
            'special_course'
3561
        );
3562
3563
        if (!empty($result)) {
3564
            if (1 == $result['value']) {
3565
                return true;
3566
            }
3567
        }
3568
3569
        return false;
3570
    }
3571
3572
    /**
3573
     * Display special courses (and only these) as several HTML divs of class userportal-course-item.
3574
     *
3575
     * Special courses are courses that stick on top of the list and are "auto-registerable"
3576
     * in the sense that any user clicking them is registered as a student
3577
     *
3578
     * @param int  $user_id                          User id
3579
     * @param bool $load_dirs                        Whether to show the document quick-loader or not
3580
     * @param bool $useUserLanguageFilterIfAvailable
3581
     *
3582
     * @return array
3583
     */
3584
    public static function returnSpecialCourses(
3585
        $user_id,
3586
        $load_dirs = false,
3587
        $useUserLanguageFilterIfAvailable = true
3588
    ) {
3589
        $user_id = (int) $user_id;
3590
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
3591
        $specialCourseList = self::get_special_course_list();
3592
3593
        if (empty($specialCourseList)) {
3594
            return [];
3595
        }
3596
3597
        // Filter by language
3598
        $languageCondition = '';
3599
        $onlyInUserLanguage = api_get_configuration_value('my_courses_show_courses_in_user_language_only');
3600
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
3601
            $userInfo = api_get_user_info(api_get_user_id());
3602
            if (!empty($userInfo['language'])) {
3603
                $languageCondition = " AND course_language = '".$userInfo['language']."' ";
3604
            }
3605
        }
3606
3607
        $sql = "SELECT
3608
                    id,
3609
                    code,
3610
                    subscribe subscr,
3611
                    unsubscribe unsubscr
3612
                FROM $table
3613
                WHERE
3614
                    id IN ('".implode("','", $specialCourseList)."')
3615
                    $languageCondition
3616
                GROUP BY code";
3617
3618
        $rs_special_course = Database::query($sql);
3619
        $number_of_courses = Database::num_rows($rs_special_course);
3620
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
3621
3622
        $courseList = [];
3623
        if ($number_of_courses > 0) {
3624
            while ($course = Database::fetch_array($rs_special_course)) {
3625
                $course_info = api_get_course_info($course['code']);
3626
                $courseId = $course_info['real_id'];
3627
                if (COURSE_VISIBILITY_HIDDEN == $course_info['visibility']) {
3628
                    continue;
3629
                }
3630
3631
                $params = [];
3632
                //Param (course_code) needed to get the student info in page "My courses"
3633
                $params['course_code'] = $course['code'];
3634
                $params['code'] = $course['code'];
3635
                // Get notifications.
3636
                $course_info['id_session'] = null;
3637
                $courseUserInfo = self::getUserCourseInfo($user_id, $courseId);
3638
3639
                if (empty($courseUserInfo)) {
3640
                    $course_info['status'] = STUDENT;
3641
                } else {
3642
                    $course_info['status'] = $courseUserInfo['status'];
3643
                }
3644
                $show_notification = !api_get_configuration_value('hide_course_notification')
3645
                    ? Display::show_notification($course_info)
3646
                    : '';
3647
                $params['edit_actions'] = '';
3648
                $params['document'] = '';
3649
                if (api_is_platform_admin()) {
3650
                    $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'];
3651
                    if ($load_dirs) {
3652
                        $params['document'] = '<a id="document_preview_'.$courseId.'_0" class="document_preview btn btn-outline-secondary btn-sm" href="javascript:void(0);">'
3653
                           .Display::returnFontAwesomeIcon('folder-open').'</a>';
3654
                        $params['document'] .= Display::div('', ['id' => 'document_result_'.$courseId.'_0', 'class' => 'document_preview_container']);
3655
                    }
3656
                } else {
3657
                    if (COURSE_VISIBILITY_CLOSED != $course_info['visibility'] && $load_dirs) {
3658
                        $params['document'] = '<a id="document_preview_'.$courseId.'_0" class="document_preview btn btn-outline-secondary btn-sm" href="javascript:void(0);">'
3659
                           .Display::returnFontAwesomeIcon('folder-open').'</a>';
3660
                        $params['document'] .= Display::div('', ['id' => 'document_result_'.$courseId.'_0', 'class' => 'document_preview_container']);
3661
                    }
3662
                }
3663
3664
                $params['visibility'] = $course_info['visibility'];
3665
                $params['status'] = $course_info['status'];
3666
                $params['category'] = $course_info['categoryName'];
3667
                $params['category_code'] = $course_info['categoryCode'];
3668
                $params['icon'] = Display::return_icon(
3669
                    'drawing-pin.png',
3670
                    null,
3671
                    null,
3672
                    ICON_SIZE_LARGE,
3673
                    null
3674
                );
3675
3676
                if ('true' == api_get_setting('display_coursecode_in_courselist')) {
3677
                    $params['code_course'] = '('.$course_info['visual_code'].')';
3678
                }
3679
3680
                $params['title'] = $course_info['title'];
3681
                $params['title_cut'] = $course_info['title'];
3682
                $params['link'] = $course_info['course_public_url'].'?sid=0&autoreg=1';
3683
                if ('true' === api_get_setting('display_teacher_in_courselist')) {
3684
                    $params['teachers'] = self::getTeachersFromCourse(
3685
                        $courseId,
3686
                        true
3687
                    );
3688
                }
3689
3690
                $params['extrafields'] = CourseManager::getExtraFieldsToBePresented($course_info['real_id']);
3691
3692
                if ('true' === $showCustomIcon) {
3693
                    $params['thumbnails'] = $course_info['course_image'];
3694
                    $params['image'] = $course_info['course_image_large'];
3695
                }
3696
3697
                if (COURSE_VISIBILITY_CLOSED != $course_info['visibility']) {
3698
                    $params['notifications'] = $show_notification;
3699
                }
3700
3701
                $params['is_special_course'] = true;
3702
                $courseList[] = $params;
3703
            }
3704
        }
3705
3706
        return $courseList;
3707
    }
3708
3709
    /**
3710
     *  Display courses inside a category (without special courses) as HTML dics of
3711
     *  class userportal-course-item.
3712
     *
3713
     * @param int  $user_category_id                 User category id
3714
     * @param bool $load_dirs                        Whether to show the document quick-loader or not
3715
     * @param int  $user_id
3716
     * @param bool $useUserLanguageFilterIfAvailable
3717
     *
3718
     * @return array
3719
     */
3720
    public static function returnCoursesCategories(
3721
        $user_category_id,
3722
        $load_dirs = false,
3723
        $user_id = 0,
3724
        $useUserLanguageFilterIfAvailable = true
3725
    ) {
3726
        $user_id = $user_id ? (int) $user_id : api_get_user_id();
3727
        $user_category_id = (int) $user_category_id;
3728
3729
        // Table definitions
3730
        $TABLECOURS = Database::get_main_table(TABLE_MAIN_COURSE);
3731
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3732
        $TABLE_ACCESS_URL_REL_COURSE = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3733
        $current_url_id = api_get_current_access_url_id();
3734
3735
        // Get course list auto-register
3736
        $special_course_list = self::get_special_course_list();
3737
        $without_special_courses = '';
3738
        if (!empty($special_course_list)) {
3739
            $without_special_courses = ' AND course.id NOT IN ("'.implode('","', $special_course_list).'")';
3740
        }
3741
3742
        $userCategoryCondition = " (course_rel_user.user_course_cat = $user_category_id) ";
3743
        if (empty($user_category_id)) {
3744
            $userCategoryCondition = ' (course_rel_user.user_course_cat = 0 OR course_rel_user.user_course_cat IS NULL) ';
3745
        }
3746
3747
        $languageCondition = '';
3748
        $onlyInUserLanguage = api_get_configuration_value('my_courses_show_courses_in_user_language_only');
3749
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
3750
            $userInfo = api_get_user_info(api_get_user_id());
3751
            if (!empty($userInfo['language'])) {
3752
                $languageCondition = " AND course.course_language = '".$userInfo['language']."' ";
3753
            }
3754
        }
3755
3756
        $sql = "SELECT DISTINCT
3757
                    course.id,
3758
                    course_rel_user.status status,
3759
                    course.code as course_code,
3760
                    user_course_cat,
3761
                    course_rel_user.sort
3762
                FROM $TABLECOURS course
3763
                INNER JOIN $TABLECOURSUSER course_rel_user
3764
                ON (course.id = course_rel_user.c_id)
3765
                INNER JOIN $TABLE_ACCESS_URL_REL_COURSE url
3766
                ON (url.c_id = course.id)
3767
                WHERE
3768
                    course_rel_user.user_id = $user_id AND
3769
                    $userCategoryCondition
3770
                    $without_special_courses
3771
                    $languageCondition
3772
                ";
3773
        // If multiple URL access mode is enabled, only fetch courses
3774
        // corresponding to the current URL.
3775
        if (api_get_multiple_access_url() && -1 != $current_url_id) {
3776
            $sql .= " AND access_url_id = $current_url_id";
3777
        }
3778
        // Use user's classification for courses (if any).
3779
        $sql .= ' ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC';
3780
        $result = Database::query($sql);
3781
3782
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
3783
        // Browse through all courses.
3784
        $courseAdded = [];
3785
        $courseList = [];
3786
3787
        while ($row = Database::fetch_array($result)) {
3788
            $course_info = api_get_course_info_by_id($row['id']);
3789
            if (empty($course_info)) {
3790
                continue;
3791
            }
3792
3793
            if (isset($course_info['visibility']) &&
3794
                COURSE_VISIBILITY_HIDDEN == $course_info['visibility']
3795
            ) {
3796
                continue;
3797
            }
3798
3799
            // Skip if already in list
3800
            if (in_array($course_info['real_id'], $courseAdded)) {
3801
                continue;
3802
            }
3803
            $course_info['id_session'] = null;
3804
            $course_info['status'] = $row['status'];
3805
            // For each course, get if there is any notification icon to show
3806
            // (something that would have changed since the user's last visit).
3807
            $showNotification = !api_get_configuration_value('hide_course_notification')
3808
                ? Display::show_notification($course_info)
3809
                : '';
3810
            $iconName = basename($course_info['course_image']);
3811
3812
            $params = [];
3813
            //Param (course_code) needed to get the student process
3814
            $params['course_code'] = $row['course_code'];
3815
            $params['code'] = $row['course_code'];
3816
3817
            if ('true' === $showCustomIcon && 'course.png' != $iconName) {
3818
                $params['thumbnails'] = $course_info['course_image'];
3819
                $params['image'] = $course_info['course_image_large'];
3820
            }
3821
3822
            $thumbnails = null;
3823
            $image = null;
3824
            if ('true' === $showCustomIcon && 'course.png' != $iconName) {
3825
                $thumbnails = $course_info['course_image'];
3826
                $image = $course_info['course_image_large'];
3827
            } else {
3828
                $image = Display::return_icon(
3829
                    'session_default.png',
3830
                    null,
3831
                    null,
3832
                    null,
3833
                    null,
3834
                    true
3835
                );
3836
            }
3837
3838
            $params['course_id'] = $course_info['real_id'];
3839
            $params['edit_actions'] = '';
3840
            $params['document'] = '';
3841
            if (api_is_platform_admin()) {
3842
                $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course_info['real_id'];
3843
                if ($load_dirs) {
3844
                    $params['document'] = '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview btn btn-default btn-sm" href="javascript:void(0);">'
3845
                               .Display::returnFontAwesomeIcon('folder-open').'</a>';
3846
                    $params['document'] .= Display::div(
3847
                        '',
3848
                        [
3849
                            'id' => 'document_result_'.$course_info['real_id'].'_0',
3850
                            'class' => 'document_preview_container',
3851
                        ]
3852
                    );
3853
                }
3854
            }
3855
            if ($load_dirs) {
3856
                $params['document'] = '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview btn btn-default btn-sm" href="javascript:void(0);">'
3857
                    .Display::returnFontAwesomeIcon('folder-open').'</a>';
3858
                $params['document'] .= Display::div(
3859
                    '',
3860
                    [
3861
                        'id' => 'document_result_'.$course_info['real_id'].'_0',
3862
                        'class' => 'document_preview_container',
3863
                    ]
3864
                );
3865
            }
3866
3867
            $courseUrl = $course_info['course_public_url'].'?sid=0';
3868
            $teachers = [];
3869
            if ('true' === api_get_setting('display_teacher_in_courselist')) {
3870
                $teachers = self::getTeachersFromCourse(
3871
                    $course_info['real_id'],
3872
                    true
3873
                );
3874
            }
3875
3876
            $params['status'] = $row['status'];
3877
            if ('true' === api_get_setting('display_coursecode_in_courselist')) {
3878
                $params['code_course'] = '('.$course_info['visual_code'].') ';
3879
            }
3880
3881
            $params['current_user_is_teacher'] = false;
3882
            /** @var array $teacher */
3883
            foreach ($teachers as $teacher) {
3884
                if ($teacher['id'] != $user_id) {
3885
                    continue;
3886
                }
3887
                $params['current_user_is_teacher'] = true;
3888
            }
3889
3890
            $params['visibility'] = $course_info['visibility'];
3891
            $params['link'] = $courseUrl;
3892
            $params['thumbnails'] = $thumbnails;
3893
            $params['image'] = $image;
3894
            $params['title'] = $course_info['title'];
3895
            $params['title_cut'] = $params['title'];
3896
            $params['category'] = $course_info['categoryName'];
3897
            $params['category_code'] = $course_info['categoryCode'];
3898
            $params['teachers'] = $teachers;
3899
            $params['extrafields'] = CourseManager::getExtraFieldsToBePresented($course_info['real_id']);
3900
            $params['real_id'] = $course_info['real_id'];
3901
3902
            if (api_get_configuration_value('enable_unsubscribe_button_on_my_course_page')
3903
                && '1' === $course_info['unsubscribe']
3904
            ) {
3905
                $params['unregister_button'] = CoursesAndSessionsCatalog::return_unregister_button(
3906
                    $course_info,
3907
                    Security::get_existing_token(),
3908
                    '',
3909
                    ''
3910
                );
3911
            }
3912
3913
            if (COURSE_VISIBILITY_CLOSED != $course_info['visibility']) {
3914
                $params['notifications'] = $showNotification;
3915
            }
3916
            $courseAdded[] = $course_info['real_id'];
3917
            $courseList[] = $params;
3918
        }
3919
3920
        return $courseList;
3921
    }
3922
3923
    /**
3924
     * Get the course id based on the original id and field name in the extra fields.
3925
     * Returns 0 if course was not found.
3926
     *
3927
     * @param string $value    Original course code
3928
     * @param string $variable Original field name
3929
     *
3930
     * @return array
3931
     */
3932
    public static function getCourseInfoFromOriginalId($value, $variable)
3933
    {
3934
        $extraFieldValue = new ExtraFieldValue('course');
3935
        $result = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
3936
            $variable,
3937
            $value
3938
        );
3939
3940
        if (!empty($result)) {
3941
            return api_get_course_info_by_id($result['item_id']);
3942
        }
3943
3944
        return [];
3945
    }
3946
3947
    /**
3948
     * Display code for one specific course a logged in user is subscribed to.
3949
     * Shows a link to the course, what's new icons...
3950
     *
3951
     * $my_course['d'] - course directory
3952
     * $my_course['i'] - course title
3953
     * $my_course['c'] - visual course code
3954
     * $my_course['k']  - system course code
3955
     *
3956
     * @param   array       Course details
3957
     * @param   int     Session ID
3958
     * @param   string      CSS class to apply to course entry
3959
     * @param   bool     Whether the session is supposedly accessible now
3960
     * (not in the case it has passed and is in invisible/unaccessible mode)
3961
     * @param bool      Whether to show the document quick-loader or not
3962
     *
3963
     * @return string The HTML to be printed for the course entry
3964
     *
3965
     * @version 1.0.3
3966
     *
3967
     * @todo refactor into different functions for database calls | logic | display
3968
     * @todo replace single-character $my_course['d'] indices
3969
     * @todo move code for what's new icons to a separate function to clear things up
3970
     * @todo add a parameter user_id so that it is possible to show the
3971
     * courselist of other users (=generalisation).
3972
     * This will prevent having to write a new function for this.
3973
     */
3974
    public static function get_logged_user_course_html(
3975
        $course,
3976
        $session_id = 0,
3977
        $class = 'courses',
3978
        $session_accessible = true,
3979
        $load_dirs = false
3980
    ) {
3981
        $now = date('Y-m-d h:i:s');
3982
        $user_id = api_get_user_id();
3983
        $course_info = api_get_course_info_by_id($course['real_id']);
3984
        $course_visibility = (int) $course_info['visibility'];
3985
        $allowUnsubscribe = api_get_configuration_value('enable_unsubscribe_button_on_my_course_page');
3986
3987
        if (COURSE_VISIBILITY_HIDDEN === $course_visibility) {
3988
            return '';
3989
        }
3990
3991
        $sessionInfo = [];
3992
        if (!empty($session_id)) {
3993
            $sessionInfo = api_get_session_info($session_id);
3994
        }
3995
        $userInCourseStatus = self::getUserInCourseStatus($user_id, $course_info['real_id']);
3996
        $course_info['status'] = empty($session_id) ? $userInCourseStatus : STUDENT;
3997
        $course_info['id_session'] = $session_id;
3998
3999
        $is_coach = api_is_coach($session_id, $course_info['real_id']);
4000
        $isAdmin = api_is_platform_admin();
4001
4002
        // Display course entry.
4003
        // Show a hyperlink to the course, unless the course is closed and user is not course admin.
4004
        $session_url = '';
4005
        $params = [];
4006
        $params['icon'] = Display::return_icon(
4007
            'session.png',
4008
            null,
4009
            [],
4010
            ICON_SIZE_LARGE,
4011
            null,
4012
            true
4013
        );
4014
        $params['real_id'] = $course_info['real_id'];
4015
        $params['visibility'] = $course_info['visibility'];
4016
4017
        // Display the "what's new" icons
4018
        $notifications = '';
4019
        if (
4020
            (COURSE_VISIBILITY_CLOSED != $course_visibility && COURSE_VISIBILITY_HIDDEN != $course_visibility) ||
4021
            !api_get_configuration_value('hide_course_notification')
4022
        ) {
4023
            $notifications .= Display::show_notification($course_info);
4024
        }
4025
4026
        $sessionCourseAvailable = false;
4027
        if ($session_accessible) {
4028
            if (COURSE_VISIBILITY_CLOSED != $course_visibility ||
4029
                COURSEMANAGER == $userInCourseStatus
4030
            ) {
4031
                if (empty($course_info['id_session'])) {
4032
                    $course_info['id_session'] = 0;
4033
                }
4034
4035
                $sessionCourseStatus = api_get_session_visibility($session_id, $course_info['real_id']);
4036
4037
                if (in_array(
4038
                    $sessionCourseStatus,
4039
                    [SESSION_VISIBLE_READ_ONLY, SESSION_VISIBLE, SESSION_AVAILABLE]
4040
                )) {
4041
                    $sessionCourseAvailable = true;
4042
                }
4043
4044
                if (COURSEMANAGER === $userInCourseStatus || $sessionCourseAvailable) {
4045
                    $session_url = $course_info['course_public_url'].'?sid='.$course_info['id_session'];
4046
                    $session_title = '<a title="'.$course_info['name'].'" href="'.$session_url.'">'.
4047
                        $course_info['name'].'</a>'.$notifications;
4048
                } else {
4049
                    $session_title = $course_info['name'];
4050
                }
4051
            } else {
4052
                $session_title =
4053
                    $course_info['name'].' '.
4054
                    Display::tag('span', get_lang('(the course is currently closed)'), ['class' => 'item_closed']);
4055
            }
4056
        } else {
4057
            $session_title = $course_info['name'];
4058
        }
4059
4060
        $thumbnails = null;
4061
        $image = null;
4062
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
4063
        $iconName = basename($course_info['course_image']);
4064
4065
        if ('true' === $showCustomIcon && 'course.png' != $iconName) {
4066
            $thumbnails = $course_info['course_image'];
4067
            $image = $course_info['course_image_large'];
4068
        } else {
4069
            $image = Display::return_icon(
4070
                'session_default.png',
4071
                null,
4072
                null,
4073
                null,
4074
                null,
4075
                true
4076
            );
4077
        }
4078
        $params['thumbnails'] = $thumbnails;
4079
        $params['image'] = $image;
4080
        $params['html_image'] = '';
4081
        if (!empty($thumbnails)) {
4082
            $params['html_image'] = Display::img($thumbnails, $course_info['name'], ['class' => 'img-responsive']);
4083
        } else {
4084
            $params['html_image'] = Display::return_icon(
4085
                'session.png',
4086
                $course_info['name'],
4087
                ['class' => 'img-responsive'],
4088
                ICON_SIZE_LARGE,
4089
                $course_info['name']
4090
            );
4091
        }
4092
        $params['link'] = $session_url;
4093
        $entityManager = Database::getManager();
4094
        /** @var SequenceResourceRepository $repo */
4095
        $repo = $entityManager->getRepository(SequenceResource::class);
4096
4097
        $sequences = $repo->getRequirements($course_info['real_id'], SequenceResource::COURSE_TYPE);
4098
        $sequenceList = $repo->checkRequirementsForUser(
4099
            $sequences,
4100
            SequenceResource::COURSE_TYPE,
4101
            $user_id,
4102
            $session_id
4103
        );
4104
        $completed = $repo->checkSequenceAreCompleted($sequenceList);
4105
        //var_dump($course_info['real_id'], $completed);
4106
        $params['completed'] = $completed;
4107
        $params['requirements'] = '';
4108
4109
        if ($isAdmin ||
4110
            COURSEMANAGER === $userInCourseStatus ||
4111
            $is_coach ||
4112
            $user_id == $sessionInfo['session_admin_id']
4113
        ) {
4114
            $params['completed'] = true;
4115
            $params['requirements'] = '';
4116
        } else {
4117
            if ($sequences && false === $completed) {
4118
                $hasRequirements = false;
4119
                foreach ($sequences as $sequence) {
4120
                    if (!empty($sequence['requirements'])) {
4121
                        $hasRequirements = true;
4122
                        break;
4123
                    }
4124
                }
4125
                if ($hasRequirements) {
4126
                    $params['requirements'] = CoursesAndSessionsCatalog::getRequirements(
4127
                    $course_info['real_id'],
4128
                    SequenceResource::COURSE_TYPE,
4129
                    false,
4130
                        false,
4131
                        $session_id
4132
                );
4133
                }
4134
            }
4135
        }
4136
4137
        $params['title'] = $session_title;
4138
        $params['name'] = $course_info['name'];
4139
        $params['edit_actions'] = '';
4140
        $params['document'] = '';
4141
        $params['category'] = $course_info['categoryName'];
4142
        if (COURSE_VISIBILITY_CLOSED != $course_visibility &&
4143
            false === $is_coach && $allowUnsubscribe && '1' === $course_info['unsubscribe']) {
4144
            $params['unregister_button'] =
4145
                CoursesAndSessionsCatalog::return_unregister_button(
4146
                    ['code' => $course_info['code']],
4147
                    Security::get_existing_token(),
4148
                    '',
4149
                    '',
4150
                    $session_id
4151
                );
4152
        }
4153
4154
        if (COURSE_VISIBILITY_CLOSED != $course_visibility &&
4155
            COURSE_VISIBILITY_HIDDEN != $course_visibility
4156
        ) {
4157
            if ($isAdmin) {
4158
                $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course_info['code'];
4159
                if ($load_dirs) {
4160
                    $params['document'] .= '<a
4161
                        id="document_preview_'.$course_info['real_id'].'_'.$session_id.'"
4162
                        class="document_preview btn btn-default btn-sm"
4163
                        href="javascript:void(0);">'.
4164
                        Display::returnFontAwesomeIcon('folder-open').'</a>';
4165
                    $params['document'] .= Display::div('', [
4166
                        'id' => 'document_result_'.$course_info['real_id'].'_'.$session_id,
4167
                        'class' => 'document_preview_container',
4168
                    ]);
4169
                }
4170
            }
4171
        }
4172
        if ('true' === api_get_setting('display_teacher_in_courselist')) {
4173
            $teacher_list = self::getTeachersFromCourse($course_info['real_id'], true);
4174
            $course_coachs = self::get_coachs_from_course(
4175
                $session_id,
4176
                $course_info['real_id'],
4177
                true
4178
            );
4179
            $params['teachers'] = $teacher_list;
4180
4181
            if ((STUDENT == $course_info['status'] && !empty($session_id)) ||
4182
                ($is_coach && COURSEMANAGER != $course_info['status'])
4183
            ) {
4184
                $params['coaches'] = $course_coachs;
4185
            }
4186
        }
4187
        $special = isset($course['special_course']) ? true : false;
4188
        $params['title'] = $session_title;
4189
        $params['special'] = $special;
4190
        if ('true' === api_get_setting('display_coursecode_in_courselist')) {
4191
            $params['visual_code'] = '('.$course_info['visual_code'].')';
4192
        }
4193
        $params['extra'] = '';
4194
        $html = $params;
4195
4196
        $session_category_id = null;
4197
        $active = false;
4198
        if (!empty($session_id)) {
4199
            $sessionCoachName = '';
4200
            if (!empty($sessionInfo['id_coach'])) {
4201
                $coachInfo = api_get_user_info($sessionInfo['id_coach']);
4202
                $sessionCoachName = $coachInfo['complete_name'];
4203
            }
4204
4205
            $session_category_id = self::get_session_category_id_by_session_id($course_info['id_session']);
4206
4207
            if (
4208
                '0000-00-00 00:00:00' === $sessionInfo['access_start_date'] ||
4209
                empty($sessionInfo['access_start_date']) ||
4210
                '0000-00-00' === $sessionInfo['access_start_date']
4211
                ) {
4212
                $sessionInfo['dates'] = '';
4213
                if ('true' === api_get_setting('show_session_coach')) {
4214
                    $sessionInfo['coach'] = get_lang('GeneralCoach').': '.$sessionCoachName;
4215
                }
4216
                $active = true;
4217
            } else {
4218
                $sessionInfo['dates'] = ' - '.
4219
                    get_lang('From').' '.$sessionInfo['access_start_date'].' '.
4220
                    get_lang('To').' '.$sessionInfo['access_end_date'];
4221
                if ('true' === api_get_setting('show_session_coach')) {
4222
                    $sessionInfo['coach'] = get_lang('GeneralCoach').': '.$sessionCoachName;
4223
                }
4224
                $date_start = $sessionInfo['access_start_date'];
4225
                $date_end = $sessionInfo['access_end_date'];
4226
                $active = !$date_end ? ($date_start <= $now) : ($date_start <= $now && $date_end >= $now);
4227
            }
4228
        }
4229
        $user_course_category = '';
4230
        if (isset($course_info['user_course_cat'])) {
4231
            $user_course_category = $course_info['user_course_cat'];
4232
        }
4233
        $output = [
4234
                $user_course_category,
4235
                $html,
4236
                $course_info['id_session'],
4237
                $sessionInfo,
4238
                'active' => $active,
4239
                'session_category_id' => $session_category_id,
4240
            ];
4241
4242
        if (SkillModel::isAllowed($user_id, false)) {
4243
            $em = Database::getManager();
4244
            $objUser = api_get_user_entity($user_id);
4245
            $objCourse = api_get_course_entity($course['real_id']);
4246
            $objSession = api_get_session_entity($session_id);
4247
            $skill = $em->getRepository(\Chamilo\CoreBundle\Entity\Skill::class)->getLastByUser($objUser, $objCourse, $objSession);
4248
4249
            $output['skill'] = null;
4250
            if ($skill) {
4251
                $output['skill']['name'] = $skill->getName();
4252
                $output['skill']['icon'] = $skill->getIcon();
4253
            }
4254
        }
4255
4256
        return $output;
4257
    }
4258
4259
    /**
4260
     * @param string $source_course_code
4261
     * @param int    $source_session_id
4262
     * @param string $destination_course_code
4263
     * @param int    $destination_session_id
4264
     * @param array  $params
4265
     *
4266
     * @return bool
4267
     */
4268
    public static function copy_course(
4269
        $source_course_code,
4270
        $source_session_id,
4271
        $destination_course_code,
4272
        $destination_session_id,
4273
        $params = [],
4274
        $withBaseContent = true
4275
    ) {
4276
        $course_info = api_get_course_info($source_course_code);
4277
4278
        if (!empty($course_info)) {
4279
            $cb = new CourseBuilder('', $course_info);
4280
            $course = $cb->build($source_session_id, $source_course_code, $withBaseContent);
4281
            $restorer = new CourseRestorer($course);
4282
            $restorer->skip_content = $params;
4283
            $restorer->restore(
4284
                $destination_course_code,
4285
                $destination_session_id,
4286
                true,
4287
                $withBaseContent
4288
            );
4289
4290
            return true;
4291
        }
4292
4293
        return false;
4294
    }
4295
4296
    /**
4297
     * A simpler version of the copy_course, the function creates an empty course with an autogenerated course code.
4298
     *
4299
     * @param string $new_title new course title
4300
     * @param string source course code
4301
     * @param int source session id
4302
     * @param int destination session id
4303
     * @param array $params
4304
     * @param bool  $copySessionContent
4305
     *
4306
     * @return array
4307
     */
4308
    public static function copy_course_simple(
4309
        $new_title,
4310
        $source_course_code,
4311
        $source_session_id = 0,
4312
        $destination_session_id = 0,
4313
        $params = [],
4314
        $copySessionContent = false
4315
    ) {
4316
        $source_course_info = api_get_course_info($source_course_code);
4317
        if (!empty($source_course_info)) {
4318
            $new_course_code = self::generate_nice_next_course_code($source_course_code);
4319
            if ($new_course_code) {
4320
                $new_course_info = self::create_course(
4321
                    $new_title,
4322
                    $new_course_code,
4323
                    false
4324
                );
4325
                if (!empty($new_course_info['code'])) {
4326
                    $result = self::copy_course(
4327
                        $source_course_code,
4328
                        $source_session_id,
4329
                        $new_course_info['code'],
4330
                        $destination_session_id,
4331
                        $params,
4332
                        true
4333
                    );
4334
                    if ($result) {
4335
                        return $new_course_info;
4336
                    }
4337
                }
4338
            }
4339
        }
4340
4341
        return false;
4342
    }
4343
4344
    /**
4345
     * Creates a new course code based in a given code.
4346
     *
4347
     * @param string    wanted code
4348
     * <code>    $wanted_code = 'curse' if there are in the DB codes like curse1 curse2 the function will return:
4349
     * course3</code> if the course code doest not exist in the DB the same course code will be returned
4350
     *
4351
     * @return string wanted unused code
4352
     */
4353
    public static function generate_nice_next_course_code($wanted_code)
4354
    {
4355
        $course_code_ok = !self::course_code_exists($wanted_code);
4356
        if (!$course_code_ok) {
4357
            $wanted_code = self::generate_course_code($wanted_code);
4358
            $table = Database::get_main_table(TABLE_MAIN_COURSE);
4359
            $wanted_code = Database::escape_string($wanted_code);
4360
            $sql = "SELECT count(id) as count
4361
                    FROM $table
4362
                    WHERE code LIKE '$wanted_code%'";
4363
            $result = Database::query($sql);
4364
            if (Database::num_rows($result) > 0) {
4365
                $row = Database::fetch_array($result);
4366
                $count = $row['count'] + 1;
4367
                $wanted_code = $wanted_code.'_'.$count;
4368
                $result = api_get_course_info($wanted_code);
4369
                if (empty($result)) {
4370
                    return $wanted_code;
4371
                }
4372
            }
4373
4374
            return false;
4375
        }
4376
4377
        return $wanted_code;
4378
    }
4379
4380
    /**
4381
     * Gets the status of the users agreement in a course course-session.
4382
     *
4383
     * @param int    $user_id
4384
     * @param string $course_code
4385
     * @param int    $session_id
4386
     *
4387
     * @return bool
4388
     */
4389
    public static function is_user_accepted_legal($user_id, $course_code, $session_id = 0)
4390
    {
4391
        $user_id = (int) $user_id;
4392
        $session_id = (int) $session_id;
4393
        $course_code = Database::escape_string($course_code);
4394
4395
        $courseInfo = api_get_course_info($course_code);
4396
        $courseId = $courseInfo['real_id'];
4397
4398
        // Course legal
4399
        $enabled = api_get_plugin_setting('courselegal', 'tool_enable');
4400
4401
        if ('true' == $enabled) {
4402
            require_once api_get_path(SYS_PLUGIN_PATH).'courselegal/config.php';
4403
            $plugin = CourseLegalPlugin::create();
4404
4405
            return $plugin->isUserAcceptedLegal($user_id, $course_code, $session_id);
4406
        }
4407
4408
        if (empty($session_id)) {
4409
            $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4410
            $sql = "SELECT legal_agreement FROM $table
4411
                    WHERE user_id = $user_id AND c_id = $courseId ";
4412
            $result = Database::query($sql);
4413
            if (Database::num_rows($result) > 0) {
4414
                $result = Database::fetch_array($result);
4415
                if (1 == $result['legal_agreement']) {
4416
                    return true;
4417
                }
4418
            }
4419
4420
            return false;
4421
        } else {
4422
            $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4423
            $sql = "SELECT legal_agreement FROM $table
4424
                    WHERE user_id = $user_id AND c_id = $courseId AND session_id = $session_id";
4425
            $result = Database::query($sql);
4426
            if (Database::num_rows($result) > 0) {
4427
                $result = Database::fetch_array($result);
4428
                if (1 == $result['legal_agreement']) {
4429
                    return true;
4430
                }
4431
            }
4432
4433
            return false;
4434
        }
4435
    }
4436
4437
    /**
4438
     * Saves the user-course legal agreement.
4439
     *
4440
     * @param   int user id
4441
     * @param   string course code
4442
     * @param   int session id
4443
     *
4444
     * @return bool
4445
     */
4446
    public static function save_user_legal($user_id, $courseInfo, $session_id = 0)
4447
    {
4448
        if (empty($courseInfo)) {
4449
            return false;
4450
        }
4451
        $course_code = $courseInfo['code'];
4452
4453
        // Course plugin legal
4454
        $enabled = api_get_plugin_setting('courselegal', 'tool_enable');
4455
        if ('true' == $enabled) {
4456
            require_once api_get_path(SYS_PLUGIN_PATH).'courselegal/config.php';
4457
            $plugin = CourseLegalPlugin::create();
4458
4459
            return $plugin->saveUserLegal($user_id, $course_code, $session_id);
4460
        }
4461
4462
        $user_id = (int) $user_id;
4463
        $session_id = (int) $session_id;
4464
        $courseId = $courseInfo['real_id'];
4465
4466
        if (empty($session_id)) {
4467
            $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4468
            $sql = "UPDATE $table SET legal_agreement = '1'
4469
                    WHERE user_id = $user_id AND c_id  = $courseId ";
4470
            Database::query($sql);
4471
        } else {
4472
            $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4473
            $sql = "UPDATE  $table SET legal_agreement = '1'
4474
                    WHERE user_id = $user_id AND c_id = $courseId AND session_id = $session_id";
4475
            Database::query($sql);
4476
        }
4477
4478
        return true;
4479
    }
4480
4481
    /**
4482
     * @param int $user_id
4483
     * @param int $course_id
4484
     * @param int $session_id
4485
     * @param int $url_id
4486
     *
4487
     * @return bool
4488
     */
4489
    public static function get_user_course_vote($user_id, $course_id, $session_id = 0, $url_id = 0)
4490
    {
4491
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4492
        $session_id = !isset($session_id) ? api_get_session_id() : intval($session_id);
4493
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4494
        $user_id = intval($user_id);
4495
4496
        if (empty($user_id)) {
4497
            return false;
4498
        }
4499
4500
        $params = [
4501
            'user_id' => $user_id,
4502
            'c_id' => $course_id,
4503
            'session_id' => $session_id,
4504
            'url_id' => $url_id,
4505
        ];
4506
4507
        $result = Database::select(
4508
            'vote',
4509
            $table_user_course_vote,
4510
            [
4511
                'where' => [
4512
                    'user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params,
4513
                ],
4514
            ],
4515
            'first'
4516
        );
4517
        if (!empty($result)) {
4518
            return $result['vote'];
4519
        }
4520
4521
        return false;
4522
    }
4523
4524
    /**
4525
     * @param int $course_id
4526
     * @param int $session_id
4527
     * @param int $url_id
4528
     *
4529
     * @return array
4530
     */
4531
    public static function get_course_ranking(
4532
        $course_id,
4533
        $session_id = 0,
4534
        $url_id = 0
4535
    ) {
4536
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4537
4538
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4539
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4540
        $now = api_get_utc_datetime();
4541
4542
        $params = [
4543
            'c_id' => $course_id,
4544
            'session_id' => $session_id,
4545
            'url_id' => $url_id,
4546
            'creation_date' => $now,
4547
        ];
4548
4549
        $result = Database::select(
4550
            'c_id, accesses, total_score, users',
4551
            $table_course_ranking,
4552
            ['where' => ['c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4553
            'first'
4554
        );
4555
4556
        $point_average_in_percentage = 0;
4557
        $point_average_in_star = 0;
4558
        $users_who_voted = 0;
4559
4560
        if (!empty($result['users'])) {
4561
            $users_who_voted = $result['users'];
4562
            $point_average_in_percentage = round($result['total_score'] / $result['users'] * 100 / 5, 2);
4563
            $point_average_in_star = round($result['total_score'] / $result['users'], 1);
4564
        }
4565
4566
        $result['user_vote'] = false;
4567
        if (!api_is_anonymous()) {
4568
            $result['user_vote'] = self::get_user_course_vote(api_get_user_id(), $course_id, $session_id, $url_id);
4569
        }
4570
4571
        $result['point_average'] = $point_average_in_percentage;
4572
        $result['point_average_star'] = $point_average_in_star;
4573
        $result['users_who_voted'] = $users_who_voted;
4574
4575
        return $result;
4576
    }
4577
4578
    /**
4579
     * Updates the course ranking.
4580
     *
4581
     * @param int   course id
4582
     * @param int $session_id
4583
     * @param int    url id
4584
     * @param $points_to_add
4585
     * @param bool $add_access
4586
     * @param bool $add_user
4587
     *
4588
     * @return array
4589
     */
4590
    public static function update_course_ranking(
4591
        $course_id = 0,
4592
        $session_id = 0,
4593
        $url_id = 0,
4594
        $points_to_add = null,
4595
        $add_access = true,
4596
        $add_user = true
4597
    ) {
4598
        // Course catalog stats modifications see #4191
4599
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4600
        $now = api_get_utc_datetime();
4601
        $course_id = empty($course_id) ? api_get_course_int_id() : intval($course_id);
4602
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4603
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4604
4605
        $params = [
4606
            'c_id' => $course_id,
4607
            'session_id' => $session_id,
4608
            'url_id' => $url_id,
4609
            'creation_date' => $now,
4610
            'total_score' => 0,
4611
            'users' => 0,
4612
        ];
4613
4614
        $result = Database::select(
4615
            'id, accesses, total_score, users',
4616
            $table_course_ranking,
4617
            ['where' => ['c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4618
            'first'
4619
        );
4620
4621
        // Problem here every time we load the courses/XXXX/index.php course home page we update the access
4622
        if (empty($result)) {
4623
            if ($add_access) {
4624
                $params['accesses'] = 1;
4625
            }
4626
            //The votes and users are empty
4627
            if (isset($points_to_add) && !empty($points_to_add)) {
4628
                $params['total_score'] = intval($points_to_add);
4629
            }
4630
            if ($add_user) {
4631
                $params['users'] = 1;
4632
            }
4633
            $result = Database::insert($table_course_ranking, $params);
4634
        } else {
4635
            $my_params = [];
4636
4637
            if ($add_access) {
4638
                $my_params['accesses'] = intval($result['accesses']) + 1;
4639
            }
4640
            if (isset($points_to_add) && !empty($points_to_add)) {
4641
                $my_params['total_score'] = $result['total_score'] + $points_to_add;
4642
            }
4643
            if ($add_user) {
4644
                $my_params['users'] = $result['users'] + 1;
4645
            }
4646
4647
            if (!empty($my_params)) {
4648
                $result = Database::update(
4649
                    $table_course_ranking,
4650
                    $my_params,
4651
                    ['c_id = ? AND session_id = ? AND url_id = ?' => $params]
4652
                );
4653
            }
4654
        }
4655
4656
        return $result;
4657
    }
4658
4659
    /**
4660
     * Add user vote to a course.
4661
     *
4662
     * @param   int user id
4663
     * @param   int vote [1..5]
4664
     * @param   int course id
4665
     * @param   int session id
4666
     * @param   int url id (access_url_id)
4667
     *
4668
     * @return false|string 'added', 'updated' or 'nothing'
4669
     */
4670
    public static function add_course_vote(
4671
        $user_id,
4672
        $vote,
4673
        $course_id,
4674
        $session_id = 0,
4675
        $url_id = 0
4676
    ) {
4677
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4678
        $course_id = empty($course_id) ? api_get_course_int_id() : intval($course_id);
4679
4680
        if (empty($course_id) || empty($user_id)) {
4681
            return false;
4682
        }
4683
4684
        if (!in_array($vote, [1, 2, 3, 4, 5])) {
4685
            return false;
4686
        }
4687
4688
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4689
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4690
        $vote = intval($vote);
4691
4692
        $params = [
4693
            'user_id' => intval($user_id),
4694
            'c_id' => $course_id,
4695
            'session_id' => $session_id,
4696
            'url_id' => $url_id,
4697
            'vote' => $vote,
4698
        ];
4699
4700
        $action_done = 'nothing';
4701
        $result = Database::select(
4702
            'id, vote',
4703
            $table_user_course_vote,
4704
            ['where' => ['user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4705
            'first'
4706
        );
4707
4708
        if (empty($result)) {
4709
            Database::insert($table_user_course_vote, $params);
4710
            $points_to_add = $vote;
4711
            $add_user = true;
4712
            $action_done = 'added';
4713
        } else {
4714
            $my_params = ['vote' => $vote];
4715
            $points_to_add = $vote - $result['vote'];
4716
            $add_user = false;
4717
4718
            Database::update(
4719
                $table_user_course_vote,
4720
                $my_params,
4721
                ['user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params]
4722
            );
4723
            $action_done = 'updated';
4724
        }
4725
4726
        // Current points
4727
        if (!empty($points_to_add)) {
4728
            self::update_course_ranking(
4729
                $course_id,
4730
                $session_id,
4731
                $url_id,
4732
                $points_to_add,
4733
                false,
4734
                $add_user
4735
            );
4736
        }
4737
4738
        return $action_done;
4739
    }
4740
4741
    /**
4742
     * Remove course ranking + user votes.
4743
     *
4744
     * @param int $course_id
4745
     * @param int $session_id
4746
     * @param int $url_id
4747
     */
4748
    public static function remove_course_ranking($course_id, $session_id, $url_id = null)
4749
    {
4750
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4751
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4752
4753
        if (!empty($course_id) && isset($session_id)) {
4754
            $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4755
            $params = [
4756
                'c_id' => $course_id,
4757
                'session_id' => $session_id,
4758
                'url_id' => $url_id,
4759
            ];
4760
            Database::delete($table_course_ranking, ['c_id = ? AND session_id = ? AND url_id = ?' => $params]);
4761
            Database::delete($table_user_course_vote, ['c_id = ? AND session_id = ? AND url_id = ?' => $params]);
4762
        }
4763
    }
4764
4765
    /**
4766
     * Returns an array with the hottest courses.
4767
     *
4768
     * @param int $days  number of days
4769
     * @param int $limit number of hottest courses
4770
     *
4771
     * @return array
4772
     */
4773
    public static function return_hot_courses($days = 30, $limit = 6)
4774
    {
4775
        if (api_is_invitee()) {
4776
            return [];
4777
        }
4778
4779
        $limit = (int) $limit;
4780
        $userId = api_get_user_id();
4781
4782
        // Getting my courses
4783
        $my_course_list = self::get_courses_list_by_user_id($userId);
4784
4785
        $codeList = [];
4786
        foreach ($my_course_list as $course) {
4787
            $codeList[$course['real_id']] = $course['real_id'];
4788
        }
4789
4790
        if (api_is_drh()) {
4791
            $courses = self::get_courses_followed_by_drh($userId);
4792
            foreach ($courses as $course) {
4793
                $codeList[$course['real_id']] = $course['real_id'];
4794
            }
4795
        }
4796
4797
        $table_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
4798
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
4799
        $table_course_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4800
        $urlId = api_get_current_access_url_id();
4801
        //$table_course_access table uses the now() and interval ...
4802
        $now = api_get_utc_datetime();
4803
        $sql = "SELECT COUNT(course_access_id) course_count, a.c_id, visibility
4804
                FROM $table_course c
4805
                INNER JOIN $table_course_access a
4806
                ON (c.id = a.c_id)
4807
                INNER JOIN $table_course_url u
4808
                ON u.c_id = c.id
4809
                WHERE
4810
                    u.access_url_id = $urlId AND
4811
                    login_course_date <= '$now' AND
4812
                    login_course_date > DATE_SUB('$now', INTERVAL $days DAY) AND
4813
                    visibility <> ".COURSE_VISIBILITY_CLOSED." AND
4814
                    visibility <> ".COURSE_VISIBILITY_HIDDEN."
4815
                GROUP BY a.c_id
4816
                ORDER BY course_count DESC
4817
                LIMIT $limit
4818
            ";
4819
4820
        $result = Database::query($sql);
4821
        $courses = [];
4822
        if (Database::num_rows($result)) {
4823
            $courses = Database::store_result($result, 'ASSOC');
4824
            $courses = self::processHotCourseItem($courses, $codeList);
4825
        }
4826
4827
        return $courses;
4828
    }
4829
4830
    /**
4831
     * Returns an array with the "hand picked" popular courses.
4832
     * Courses only appear in this list if their extra field 'popular_courses'
4833
     * has been selected in the admin page of the course.
4834
     *
4835
     * @return array
4836
     */
4837
    public static function returnPopularCoursesHandPicked()
4838
    {
4839
        if (api_is_invitee()) {
4840
            return [];
4841
        }
4842
4843
        $userId = api_get_user_id();
4844
4845
        // Getting my courses
4846
        $my_course_list = self::get_courses_list_by_user_id($userId);
4847
4848
        $codeList = [];
4849
        foreach ($my_course_list as $course) {
4850
            $codeList[$course['real_id']] = $course['real_id'];
4851
        }
4852
4853
        if (api_is_drh()) {
4854
            $courses = self::get_courses_followed_by_drh($userId);
4855
            foreach ($courses as $course) {
4856
                $codeList[$course['real_id']] = $course['real_id'];
4857
            }
4858
        }
4859
4860
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
4861
        $tbl_course_field = Database::get_main_table(TABLE_EXTRA_FIELD);
4862
        $tbl_course_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
4863
4864
        //we filter the courses from the URL
4865
        $join_access_url = $where_access_url = '';
4866
        if (api_get_multiple_access_url()) {
4867
            $access_url_id = api_get_current_access_url_id();
4868
            if (-1 != $access_url_id) {
4869
                $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4870
                $join_access_url = "LEFT JOIN $tbl_url_course url_rel_course
4871
                ON url_rel_course.c_id = tcfv.item_id ";
4872
                $where_access_url = " AND access_url_id = $access_url_id ";
4873
            }
4874
        }
4875
4876
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
4877
4878
        // get course list auto-register
4879
        $sql = "SELECT DISTINCT(c.id) AS c_id
4880
                FROM $tbl_course_field_value tcfv
4881
                INNER JOIN $tbl_course_field tcf
4882
                ON tcfv.field_id =  tcf.id $join_access_url
4883
                INNER JOIN $courseTable c
4884
                ON (c.id = tcfv.item_id)
4885
                WHERE
4886
                    tcf.extra_field_type = $extraFieldType AND
4887
                    tcf.variable = 'popular_courses' AND
4888
                    tcfv.value = 1 AND
4889
                    visibility <> ".COURSE_VISIBILITY_CLOSED." AND
4890
                    visibility <> ".COURSE_VISIBILITY_HIDDEN." $where_access_url";
4891
4892
        $result = Database::query($sql);
4893
        $courses = [];
4894
        if (Database::num_rows($result)) {
4895
            $courses = Database::store_result($result, 'ASSOC');
4896
            $courses = self::processHotCourseItem($courses, $codeList);
4897
        }
4898
4899
        return $courses;
4900
    }
4901
4902
    /**
4903
     * @param array $courses
4904
     * @param array $codeList
4905
     *
4906
     * @return mixed
4907
     */
4908
    public static function processHotCourseItem($courses, $codeList = [])
4909
    {
4910
        $hotCourses = [];
4911
        $ajax_url = api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=add_course_vote';
4912
        $stok = Security::get_existing_token();
4913
        $user_id = api_get_user_id();
4914
4915
        foreach ($courses as $courseId) {
4916
            $course_info = api_get_course_info_by_id($courseId['c_id']);
4917
            $courseCode = $course_info['code'];
4918
            $categoryCode = !empty($course_info['categoryCode']) ? $course_info['categoryCode'] : "";
4919
            $my_course = $course_info;
4920
            $my_course['go_to_course_button'] = '';
4921
            $my_course['register_button'] = '';
4922
4923
            $access_link = self::get_access_link_by_user(
4924
                $user_id,
4925
                $course_info,
4926
                $codeList
4927
            );
4928
4929
            $userRegisteredInCourse = self::is_user_subscribed_in_course($user_id, $course_info['code']);
4930
            $userRegisteredInCourseAsTeacher = self::isCourseTeacher($user_id, $courseId['c_id']);
4931
            $userRegistered = $userRegisteredInCourse && $userRegisteredInCourseAsTeacher;
4932
            $my_course['is_course_student'] = $userRegisteredInCourse;
4933
            $my_course['is_course_teacher'] = $userRegisteredInCourseAsTeacher;
4934
            $my_course['is_registered'] = $userRegistered;
4935
            $my_course['title_cut'] = cut($course_info['title'], 45);
4936
4937
            // Course visibility
4938
            if ($access_link && in_array('register', $access_link)) {
4939
                $my_course['register_button'] = Display::url(
4940
                    get_lang('Subscribe').' '.
4941
                    Display::returnFontAwesomeIcon('sign-in'),
4942
                    api_get_path(WEB_COURSE_PATH).$course_info['path'].
4943
                     '/index.php?action=subscribe&sec_token='.$stok,
4944
                    [
4945
                        'class' => 'btn btn-success btn-sm',
4946
                        'title' => get_lang('Subscribe'),
4947
                        'aria-label' => get_lang('Subscribe'),
4948
                    ]
4949
                );
4950
            }
4951
4952
            if ($access_link && in_array('enter', $access_link) ||
4953
                Course::OPEN_WORLD == $course_info['visibility']
4954
            ) {
4955
                $my_course['go_to_course_button'] = Display::url(
4956
                    get_lang('Go to the course').' '.
4957
                    Display::returnFontAwesomeIcon('share'),
4958
                    api_get_path(WEB_COURSE_PATH).$course_info['path'].'/index.php',
4959
                    [
4960
                        'class' => 'btn btn-default btn-sm',
4961
                        'title' => get_lang('Go to the course'),
4962
                        'aria-label' => get_lang('Go to the course'),
4963
                    ]
4964
                );
4965
            }
4966
4967
            if ($access_link && in_array('unsubscribe', $access_link)) {
4968
                $my_course['unsubscribe_button'] = Display::url(
4969
                    get_lang('Unsubscribe').' '.
4970
                    Display::returnFontAwesomeIcon('sign-out'),
4971
                    api_get_path(WEB_CODE_PATH).'auth/courses.php?action=unsubscribe&unsubscribe='.$courseCode
4972
                    .'&sec_token='.$stok.'&category_code='.$categoryCode,
4973
                    [
4974
                        'class' => 'btn btn-danger btn-sm',
4975
                        'title' => get_lang('Unsubscribe'),
4976
                        'aria-label' => get_lang('Unsubscribe'),
4977
                    ]
4978
                );
4979
            }
4980
4981
            // start buycourse validation
4982
            // display the course price and buy button if the buycourses plugin is enabled and this course is configured
4983
            $plugin = BuyCoursesPlugin::create();
4984
            $isThisCourseInSale = $plugin->buyCoursesForGridCatalogValidator(
4985
                $course_info['real_id'],
4986
                BuyCoursesPlugin::PRODUCT_TYPE_COURSE
4987
            );
4988
            if ($isThisCourseInSale) {
4989
                // set the price label
4990
                $my_course['price'] = $isThisCourseInSale['html'];
4991
                // set the Buy button instead register.
4992
                if ($isThisCourseInSale['verificator'] && !empty($my_course['register_button'])) {
4993
                    $my_course['register_button'] = $plugin->returnBuyCourseButton(
4994
                        $course_info['real_id'],
4995
                        BuyCoursesPlugin::PRODUCT_TYPE_COURSE
4996
                    );
4997
                }
4998
            }
4999
            // end buycourse validation
5000
5001
            // Description
5002
            $my_course['description_button'] = self::returnDescriptionButton($course_info);
5003
            $my_course['teachers'] = self::getTeachersFromCourse($course_info['real_id'], true);
5004
            $point_info = self::get_course_ranking($course_info['real_id'], 0);
5005
            $my_course['rating_html'] = '';
5006
            if (false === api_get_configuration_value('hide_course_rating')) {
5007
                $my_course['rating_html'] = Display::return_rating_system(
5008
                    'star_'.$course_info['real_id'],
5009
                    $ajax_url.'&course_id='.$course_info['real_id'],
5010
                    $point_info
5011
                );
5012
            }
5013
            $hotCourses[] = $my_course;
5014
        }
5015
5016
        return $hotCourses;
5017
    }
5018
5019
    public function totalSubscribedUsersInCourses($urlId)
5020
    {
5021
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
5022
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5023
        $courseUsers = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5024
5025
        $urlId = (int) $urlId;
5026
5027
        $sql = "SELECT count(cu.user_id) count
5028
                FROM $courseUsers cu
5029
                INNER JOIN $table_course_rel_access_url u
5030
                ON cu.c_id = u.c_id
5031
                WHERE
5032
                    relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
5033
                    u.access_url_id = $urlId AND
5034
                    visibility <> ".COURSE_VISIBILITY_CLOSED." AND
5035
                    visibility <> ".COURSE_VISIBILITY_HIDDEN."
5036
                     ";
5037
5038
        $res = Database::query($sql);
5039
        $row = Database::fetch_array($res);
5040
5041
        return $row['count'];
5042
    }
5043
5044
    /**
5045
     * Get courses count.
5046
     *
5047
     * @param int $access_url_id Access URL ID (optional)
5048
     * @param int $visibility
5049
     *
5050
     * @return int Number of courses
5051
     */
5052
    public static function count_courses($access_url_id = null, $visibility = null)
5053
    {
5054
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
5055
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5056
        $sql = "SELECT count(c.id) FROM $table_course c";
5057
        if (!empty($access_url_id) && $access_url_id == intval($access_url_id)) {
5058
            $sql .= ", $table_course_rel_access_url u
5059
                    WHERE c.id = u.c_id AND u.access_url_id = $access_url_id";
5060
            if (!empty($visibility)) {
5061
                $visibility = intval($visibility);
5062
                $sql .= " AND visibility = $visibility ";
5063
            }
5064
        } else {
5065
            if (!empty($visibility)) {
5066
                $visibility = intval($visibility);
5067
                $sql .= " WHERE visibility = $visibility ";
5068
            }
5069
        }
5070
5071
        $res = Database::query($sql);
5072
        $row = Database::fetch_row($res);
5073
5074
        return $row[0];
5075
    }
5076
5077
    /**
5078
     * Get active courses count.
5079
     * Active = all courses except the ones with hidden visibility.
5080
     *
5081
     * @param int $urlId Access URL ID (optional)
5082
     *
5083
     * @return int Number of courses
5084
     */
5085
    public static function countActiveCourses($urlId = null)
5086
    {
5087
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
5088
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5089
        $sql = "SELECT count(c.id) FROM $table_course c";
5090
        if (!empty($urlId)) {
5091
            $urlId = (int) $urlId;
5092
            $sql .= ", $table_course_rel_access_url u
5093
                    WHERE
5094
                        c.id = u.c_id AND
5095
                        u.access_url_id = $urlId AND
5096
                        visibility <> ".COURSE_VISIBILITY_HIDDEN;
5097
        } else {
5098
            $sql .= " WHERE visibility <> ".COURSE_VISIBILITY_HIDDEN;
5099
        }
5100
        $res = Database::query($sql);
5101
        $row = Database::fetch_row($res);
5102
5103
        return $row[0];
5104
    }
5105
5106
    /**
5107
     * Returns the SQL conditions to filter course only visible by the user in the catalogue.
5108
     *
5109
     * @param string $courseTableAlias Alias of the course table
5110
     * @param bool   $hideClosed       Whether to hide closed and hidden courses
5111
     * @param bool   $checkHidePrivate
5112
     *
5113
     * @return string SQL conditions
5114
     */
5115
    public static function getCourseVisibilitySQLCondition($courseTableAlias, $hideClosed = false, $checkHidePrivate = true)
5116
    {
5117
        $visibilityCondition = '';
5118
        if ($checkHidePrivate) {
5119
            $hidePrivateSetting = api_get_setting('course_catalog_hide_private');
5120
            if ('true' === $hidePrivateSetting) {
5121
                $visibilityCondition .= " AND $courseTableAlias.visibility <> ".Course::REGISTERED;
5122
            }
5123
        }
5124
        if ($hideClosed) {
5125
            $visibilityCondition .= " AND $courseTableAlias.visibility NOT IN (".COURSE_VISIBILITY_CLOSED.','.COURSE_VISIBILITY_HIDDEN.')';
5126
        }
5127
5128
        // Check if course have users allowed to see it in the catalogue, then show only if current user is allowed to see it
5129
        $currentUserId = api_get_user_id();
5130
        $restrictedCourses = self::getCatalogCourseList(true);
5131
        $allowedCoursesToCurrentUser = self::getCatalogCourseList(true, $currentUserId);
5132
        if (!empty($restrictedCourses)) {
5133
            $visibilityCondition .= ' AND ('.$courseTableAlias.'.code NOT IN ("'.implode('","', $restrictedCourses).'")';
5134
            $visibilityCondition .= ' OR '.$courseTableAlias.'.code IN ("'.implode('","', $allowedCoursesToCurrentUser).'"))';
5135
        }
5136
5137
        // Check if course have users denied to see it in the catalogue, then show only if current user is not denied to see it
5138
        $restrictedCourses = self::getCatalogCourseList(false);
5139
        $notAllowedCoursesToCurrentUser = self::getCatalogCourseList(false, $currentUserId);
5140
        if (!empty($restrictedCourses)) {
5141
            $visibilityCondition .= ' AND ('.$courseTableAlias.'.code NOT IN ("'.implode('","', $restrictedCourses).'")';
5142
            $visibilityCondition .= ' OR '.$courseTableAlias.'.code NOT IN ("'.implode('","', $notAllowedCoursesToCurrentUser).'"))';
5143
        }
5144
5145
        return $visibilityCondition;
5146
    }
5147
5148
    /**
5149
     * Return a link to go to the course, validating the visibility of the
5150
     * course and the user status.
5151
     *
5152
     * @param int $uid User ID
5153
     * @param array Course details array
5154
     * @param array  List of courses to which the user is subscribed (if not provided, will be generated)
5155
     *
5156
     * @return mixed 'enter' for a link to go to the course or 'register' for a link to subscribe, or false if no access
5157
     */
5158
    public static function get_access_link_by_user($uid, $course, $user_courses = [])
5159
    {
5160
        if (empty($uid) || empty($course)) {
5161
            return false;
5162
        }
5163
5164
        if (empty($user_courses)) {
5165
            // get the array of courses to which the user is subscribed
5166
            $user_courses = self::get_courses_list_by_user_id($uid);
5167
            foreach ($user_courses as $k => $v) {
5168
                $user_courses[$k] = $v['real_id'];
5169
            }
5170
        }
5171
5172
        if (!isset($course['real_id']) && empty($course['real_id'])) {
5173
            $course = api_get_course_info($course['code']);
5174
        }
5175
5176
        if (COURSE_VISIBILITY_HIDDEN == $course['visibility']) {
5177
            return [];
5178
        }
5179
5180
        $is_admin = api_is_platform_admin_by_id($uid);
5181
        $options = [];
5182
        // Register button
5183
        if (!api_is_anonymous($uid) &&
5184
            (
5185
            (Course::OPEN_WORLD == $course['visibility'] || Course::OPEN_PLATFORM == $course['visibility'])
5186
                //$course['visibility'] == Course::REGISTERED && $course['subscribe'] == SUBSCRIBE_ALLOWED
5187
            ) &&
5188
            SUBSCRIBE_ALLOWED == $course['subscribe'] &&
5189
            (!in_array($course['real_id'], $user_courses) || empty($user_courses))
5190
        ) {
5191
            $options[] = 'register';
5192
        }
5193
5194
        $isLogin = !api_is_anonymous();
5195
5196
        // Go To Course button (only if admin, if course public or if student already subscribed)
5197
        if ($is_admin ||
5198
            Course::OPEN_WORLD == $course['visibility'] && empty($course['registration_code']) ||
5199
            ($isLogin && Course::OPEN_PLATFORM == $course['visibility'] && empty($course['registration_code'])) ||
5200
            (in_array($course['real_id'], $user_courses) && COURSE_VISIBILITY_CLOSED != $course['visibility'])
5201
        ) {
5202
            $options[] = 'enter';
5203
        }
5204
5205
        if ($is_admin ||
5206
            Course::OPEN_WORLD == $course['visibility'] && empty($course['registration_code']) ||
5207
            ($isLogin && Course::OPEN_PLATFORM == $course['visibility'] && empty($course['registration_code'])) ||
5208
            (in_array($course['real_id'], $user_courses) && COURSE_VISIBILITY_CLOSED != $course['visibility'])
5209
        ) {
5210
            $options[] = 'enter';
5211
        }
5212
5213
        if (COURSE_VISIBILITY_HIDDEN != $course['visibility'] &&
5214
            empty($course['registration_code']) &&
5215
            UNSUBSCRIBE_ALLOWED == $course['unsubscribe'] &&
5216
            $isLogin &&
5217
            in_array($course['real_id'], $user_courses)
5218
        ) {
5219
            $options[] = 'unsubscribe';
5220
        }
5221
5222
        return $options;
5223
    }
5224
5225
    /**
5226
     * @param array          $courseInfo
5227
     * @param array          $teachers
5228
     * @param bool           $deleteTeachersNotInList
5229
     * @param bool           $editTeacherInSessions
5230
     * @param bool           $deleteSessionTeacherNotInList
5231
     * @param array          $teacherBackup
5232
     * @param Monolog\Logger $logger
5233
     *
5234
     * @return false|null
5235
     */
5236
    public static function updateTeachers(
5237
        $courseInfo,
5238
        $teachers,
5239
        $deleteTeachersNotInList = true,
5240
        $editTeacherInSessions = false,
5241
        $deleteSessionTeacherNotInList = false,
5242
        $teacherBackup = [],
5243
        $logger = null
5244
    ) {
5245
        if (!is_array($teachers)) {
5246
            $teachers = [$teachers];
5247
        }
5248
5249
        if (empty($courseInfo) || !isset($courseInfo['real_id'])) {
5250
            return false;
5251
        }
5252
5253
        $teachers = array_filter($teachers);
5254
        $courseId = $courseInfo['real_id'];
5255
        $course_code = $courseInfo['code'];
5256
5257
        $course_user_table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5258
        $alreadyAddedTeachers = self::get_teacher_list_from_course_code($course_code);
5259
5260
        if ($deleteTeachersNotInList) {
5261
            // Delete only teacher relations that doesn't match the selected teachers
5262
            $cond = null;
5263
            if (count($teachers) > 0) {
5264
                foreach ($teachers as $key) {
5265
                    $key = Database::escape_string($key);
5266
                    $cond .= " AND user_id <> '".$key."'";
5267
                }
5268
            }
5269
5270
            // Recover user categories
5271
            $sql = "SELECT * FROM $course_user_table
5272
                    WHERE c_id = $courseId AND status = 1 AND relation_type = 0 ".$cond;
5273
            $result = Database::query($sql);
5274
            if (Database::num_rows($result)) {
5275
                $teachersToDelete = Database::store_result($result, 'ASSOC');
5276
                foreach ($teachersToDelete as $data) {
5277
                    $userId = $data['user_id'];
5278
                    $teacherBackup[$userId][$course_code] = $data;
5279
                }
5280
            }
5281
5282
            $sql = "DELETE FROM $course_user_table
5283
                    WHERE c_id = $courseId AND status = 1 AND relation_type = 0 ".$cond;
5284
5285
            Database::query($sql);
5286
        }
5287
5288
        if (count($teachers) > 0) {
5289
            foreach ($teachers as $userId) {
5290
                $userId = intval($userId);
5291
                // We check if the teacher is already subscribed in this course
5292
                $sql = "SELECT 1 FROM $course_user_table
5293
                        WHERE user_id = $userId AND c_id = $courseId";
5294
                $result = Database::query($sql);
5295
                if (Database::num_rows($result)) {
5296
                    $sql = "UPDATE $course_user_table
5297
                            SET status = 1
5298
                            WHERE c_id = $courseId AND user_id = $userId ";
5299
                } else {
5300
                    $userCourseCategory = '0';
5301
                    if (isset($teacherBackup[$userId]) &&
5302
                        isset($teacherBackup[$userId][$course_code])
5303
                    ) {
5304
                        $courseUserData = $teacherBackup[$userId][$course_code];
5305
                        $userCourseCategory = $courseUserData['user_course_cat'];
5306
                        if ($logger) {
5307
                            $logger->debug("Recovering user_course_cat: $userCourseCategory");
5308
                        }
5309
                    }
5310
5311
                    $sql = "INSERT INTO $course_user_table SET
5312
                            c_id = $courseId,
5313
                            user_id = $userId,
5314
                            status = 1,
5315
                            is_tutor = 0,
5316
                            sort = 0,
5317
                            relation_type = 0,
5318
                            user_course_cat = $userCourseCategory
5319
                    ";
5320
                }
5321
                Database::query($sql);
5322
            }
5323
        }
5324
5325
        if ($editTeacherInSessions) {
5326
            $sessions = SessionManager::get_session_by_course($courseId);
5327
            if (!empty($sessions)) {
5328
                if ($logger) {
5329
                    $logger->debug("Edit teachers in sessions");
5330
                }
5331
                foreach ($sessions as $session) {
5332
                    $sessionId = $session['id'];
5333
                    // Remove old and add new
5334
                    if ($deleteSessionTeacherNotInList) {
5335
                        foreach ($teachers as $userId) {
5336
                            if ($logger) {
5337
                                $logger->debug("Set coach #$userId in session #$sessionId of course #$courseId ");
5338
                            }
5339
                            SessionManager::set_coach_to_course_session(
5340
                                $userId,
5341
                                $sessionId,
5342
                                $courseId
5343
                            );
5344
                        }
5345
5346
                        $teachersToDelete = [];
5347
                        if (!empty($alreadyAddedTeachers)) {
5348
                            $teachersToDelete = array_diff(array_keys($alreadyAddedTeachers), $teachers);
5349
                        }
5350
5351
                        if (!empty($teachersToDelete)) {
5352
                            foreach ($teachersToDelete as $userId) {
5353
                                if ($logger) {
5354
                                    $logger->debug("Delete coach #$userId in session #$sessionId of course #$courseId ");
5355
                                }
5356
                                SessionManager::set_coach_to_course_session(
5357
                                    $userId,
5358
                                    $sessionId,
5359
                                    $courseId,
5360
                                    true
5361
                                );
5362
                            }
5363
                        }
5364
                    } else {
5365
                        // Add new teachers only
5366
                        foreach ($teachers as $userId) {
5367
                            if ($logger) {
5368
                                $logger->debug("Add coach #$userId in session #$sessionId of course #$courseId ");
5369
                            }
5370
                            SessionManager::set_coach_to_course_session(
5371
                                $userId,
5372
                                $sessionId,
5373
                                $courseId
5374
                            );
5375
                        }
5376
                    }
5377
                }
5378
            }
5379
        }
5380
    }
5381
5382
    /**
5383
     * Course available settings variables see c_course_setting table.
5384
     *
5385
     * @return array
5386
     */
5387
    public static function getCourseSettingVariables(AppPlugin $appPlugin)
5388
    {
5389
        $pluginCourseSettings = $appPlugin->getAllPluginCourseSettings();
5390
        $courseSettings = [
5391
            // Get allow_learning_path_theme from table
5392
            'allow_learning_path_theme',
5393
            // Get allow_open_chat_window from table
5394
            'allow_open_chat_window',
5395
            'allow_public_certificates',
5396
            // Get allow_user_edit_agenda from table
5397
            'allow_user_edit_agenda',
5398
            // Get allow_user_edit_announcement from table
5399
            'allow_user_edit_announcement',
5400
            // Get allow_user_image_forum from table
5401
            'allow_user_image_forum',
5402
            //Get allow show user list
5403
            'allow_user_view_user_list',
5404
            // Get course_theme from table
5405
            'course_theme',
5406
            //Get allow show user list
5407
            'display_info_advance_inside_homecourse',
5408
            'documents_default_visibility',
5409
            // Get send_mail_setting (work)from table
5410
            'email_alert_manager_on_new_doc',
5411
            // Get send_mail_setting (work)from table
5412
            'email_alert_manager_on_new_quiz',
5413
            // Get send_mail_setting (dropbox) from table
5414
            'email_alert_on_new_doc_dropbox',
5415
            'email_alert_students_on_new_homework',
5416
            // Get send_mail_setting (auth)from table
5417
            'email_alert_to_teacher_on_new_user_in_course',
5418
            'enable_lp_auto_launch',
5419
            'enable_exercise_auto_launch',
5420
            'enable_document_auto_launch',
5421
            'pdf_export_watermark_text',
5422
            'show_system_folders',
5423
            'exercise_invisible_in_session',
5424
            'enable_forum_auto_launch',
5425
            'show_course_in_user_language',
5426
            'email_to_teachers_on_new_work_feedback',
5427
            'student_delete_own_publication',
5428
            'hide_forum_notifications',
5429
            'quiz_question_limit_per_day',
5430
            'subscribe_users_to_forum_notifications',
5431
        ];
5432
5433
        $courseModels = ExerciseLib::getScoreModels();
5434
        if (!empty($courseModels)) {
5435
            $courseSettings[] = 'score_model_id';
5436
        }
5437
5438
        $allowLPReturnLink = api_get_setting('allow_lp_return_link');
5439
        if ('true' === $allowLPReturnLink) {
5440
            $courseSettings[] = 'lp_return_link';
5441
        }
5442
5443
        if (!empty($pluginCourseSettings)) {
5444
            $courseSettings = array_merge(
5445
                $courseSettings,
5446
                $pluginCourseSettings
5447
            );
5448
        }
5449
5450
        return $courseSettings;
5451
    }
5452
5453
    /**
5454
     * @param string       $variable
5455
     * @param string|array $value
5456
     * @param int          $courseId
5457
     *
5458
     * @return bool
5459
     */
5460
    public static function saveCourseConfigurationSetting(AppPlugin $appPlugin, $variable, $value, $courseId)
5461
    {
5462
        $settingList = self::getCourseSettingVariables($appPlugin);
5463
5464
        if (!in_array($variable, $settingList)) {
5465
            return false;
5466
        }
5467
5468
        $courseSettingTable = Database::get_course_table(TABLE_COURSE_SETTING);
5469
5470
        if (is_array($value)) {
5471
            $value = implode(',', $value);
5472
        }
5473
5474
        $settingFromDatabase = self::getCourseSetting($variable, $courseId);
5475
5476
        if (!empty($settingFromDatabase)) {
5477
            // Update
5478
            Database::update(
5479
                $courseSettingTable,
5480
                ['value' => $value],
5481
                ['variable = ? AND c_id = ?' => [$variable, $courseId]]
5482
            );
5483
5484
            if ($settingFromDatabase['value'] != $value) {
5485
                Event::addEvent(
5486
                    LOG_COURSE_SETTINGS_CHANGED,
5487
                    $variable,
5488
                    $settingFromDatabase['value']." -> $value"
5489
                );
5490
            }
5491
        } else {
5492
            // Create
5493
            Database::insert(
5494
                $courseSettingTable,
5495
                [
5496
                    'title' => $variable,
5497
                    'value' => $value,
5498
                    'c_id' => $courseId,
5499
                    'variable' => $variable,
5500
                ]
5501
            );
5502
5503
            Event::addEvent(
5504
                LOG_COURSE_SETTINGS_CHANGED,
5505
                $variable,
5506
                $value
5507
            );
5508
        }
5509
5510
        return true;
5511
    }
5512
5513
    /**
5514
     * Get course setting.
5515
     *
5516
     * @param string $variable
5517
     * @param int    $courseId
5518
     *
5519
     * @return array
5520
     */
5521
    public static function getCourseSetting($variable, $courseId)
5522
    {
5523
        $courseSetting = Database::get_course_table(TABLE_COURSE_SETTING);
5524
        $courseId = (int) $courseId;
5525
        $variable = Database::escape_string($variable);
5526
        $sql = "SELECT variable, value FROM $courseSetting
5527
                WHERE c_id = $courseId AND variable = '$variable'";
5528
        $result = Database::query($sql);
5529
5530
        return Database::fetch_array($result);
5531
    }
5532
5533
    public static function saveSettingChanges($courseInfo, $params)
5534
    {
5535
        if (empty($courseInfo) || empty($params)) {
5536
            return false;
5537
        }
5538
5539
        $userId = api_get_user_id();
5540
        $now = api_get_utc_datetime();
5541
5542
        foreach ($params as $name => $value) {
5543
            $emptyValue = ' - ';
5544
            if (isset($courseInfo[$name]) && $courseInfo[$name] != $value) {
5545
                if ('' !== $courseInfo[$name]) {
5546
                    $emptyValue = $courseInfo[$name];
5547
                }
5548
5549
                $changedTo = $emptyValue.' -> '.$value;
5550
5551
                Event::addEvent(
5552
                    LOG_COURSE_SETTINGS_CHANGED,
5553
                    $name,
5554
                    $changedTo,
5555
                    $now,
5556
                    $userId,
5557
                    $courseInfo['real_id']
5558
                );
5559
            }
5560
        }
5561
5562
        return true;
5563
    }
5564
5565
    /**
5566
     * Get information from the track_e_course_access table.
5567
     *
5568
     * @param int    $courseId
5569
     * @param int    $sessionId
5570
     * @param string $startDate
5571
     * @param string $endDate
5572
     *
5573
     * @return array
5574
     */
5575
    public static function getCourseAccessPerCourseAndSession(
5576
        $courseId,
5577
        $sessionId,
5578
        $startDate,
5579
        $endDate
5580
    ) {
5581
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5582
        $courseId = (int) $courseId;
5583
        $sessionId = (int) $sessionId;
5584
        $startDate = Database::escape_string($startDate);
5585
        $endDate = Database::escape_string($endDate);
5586
5587
        $sql = "SELECT * FROM $table
5588
                WHERE
5589
                    c_id = $courseId AND
5590
                    session_id = $sessionId AND
5591
                    login_course_date BETWEEN '$startDate' AND '$endDate'
5592
                ";
5593
5594
        $result = Database::query($sql);
5595
5596
        return Database::store_result($result);
5597
    }
5598
5599
    /**
5600
     * Get login information from the track_e_course_access table, for any
5601
     * course in the given session.
5602
     *
5603
     * @param int $sessionId
5604
     * @param int $userId
5605
     *
5606
     * @return array
5607
     */
5608
    public static function getFirstCourseAccessPerSessionAndUser($sessionId, $userId)
5609
    {
5610
        $sessionId = (int) $sessionId;
5611
        $userId = (int) $userId;
5612
5613
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5614
        $sql = "SELECT * FROM $table
5615
                WHERE session_id = $sessionId AND user_id = $userId
5616
                ORDER BY login_course_date ASC
5617
                LIMIT 1";
5618
5619
        $result = Database::query($sql);
5620
        $courseAccess = [];
5621
        if (Database::num_rows($result)) {
5622
            $courseAccess = Database::fetch_array($result, 'ASSOC');
5623
        }
5624
5625
        return $courseAccess;
5626
    }
5627
5628
    /**
5629
     * @param int  $courseId
5630
     * @param int  $sessionId
5631
     * @param bool $getAllSessions
5632
     *
5633
     * @return mixed
5634
     */
5635
    public static function getCountForum(
5636
        $courseId,
5637
        $sessionId = 0,
5638
        $getAllSessions = false
5639
    ) {
5640
        $forum = Database::get_course_table(TABLE_FORUM);
5641
        if ($getAllSessions) {
5642
            $sql = "SELECT count(*) as count
5643
                    FROM $forum f
5644
                    WHERE f.c_id = %s";
5645
        } else {
5646
            $sql = "SELECT count(*) as count
5647
                    FROM $forum f
5648
                    WHERE f.c_id = %s and f.session_id = %s";
5649
        }
5650
5651
        $sql = sprintf($sql, intval($courseId), intval($sessionId));
5652
        $result = Database::query($sql);
5653
        $row = Database::fetch_array($result);
5654
5655
        return $row['count'];
5656
    }
5657
5658
    /**
5659
     * @param int $userId
5660
     * @param int $courseId
5661
     * @param int $sessionId
5662
     *
5663
     * @return mixed
5664
     */
5665
    public static function getCountPostInForumPerUser(
5666
        $userId,
5667
        $courseId,
5668
        $sessionId = 0
5669
    ) {
5670
        $forum = Database::get_course_table(TABLE_FORUM);
5671
        $forum_post = Database::get_course_table(TABLE_FORUM_POST);
5672
5673
        $sql = "SELECT count(distinct post_id) as count
5674
                FROM $forum_post p
5675
                INNER JOIN $forum f
5676
                ON f.forum_id = p.forum_id AND f.c_id = p.c_id
5677
                WHERE p.poster_id = %s and f.session_id = %s and p.c_id = %s";
5678
5679
        $sql = sprintf(
5680
            $sql,
5681
            intval($userId),
5682
            intval($sessionId),
5683
            intval($courseId)
5684
        );
5685
5686
        $result = Database::query($sql);
5687
        $row = Database::fetch_array($result);
5688
5689
        return $row['count'];
5690
    }
5691
5692
    /**
5693
     * @param int $userId
5694
     * @param int $courseId
5695
     * @param int $sessionId
5696
     *
5697
     * @return mixed
5698
     */
5699
    public static function getCountForumPerUser(
5700
        $userId,
5701
        $courseId,
5702
        $sessionId = 0
5703
    ) {
5704
        $forum = Database::get_course_table(TABLE_FORUM);
5705
        $forum_post = Database::get_course_table(TABLE_FORUM_POST);
5706
5707
        $sql = "SELECT count(distinct f.forum_id) as count
5708
                FROM $forum_post p
5709
                INNER JOIN $forum f
5710
                ON f.forum_id = p.forum_id AND f.c_id = p.c_id
5711
                WHERE p.poster_id = %s and f.session_id = %s and p.c_id = %s";
5712
5713
        $sql = sprintf(
5714
            $sql,
5715
            intval($userId),
5716
            intval($sessionId),
5717
            intval($courseId)
5718
        );
5719
5720
        $result = Database::query($sql);
5721
        $row = Database::fetch_array($result);
5722
5723
        return $row['count'];
5724
    }
5725
5726
    /**
5727
     * Returns the course name from a given code.
5728
     *
5729
     * @param string $code
5730
     *
5731
     * @return string
5732
     */
5733
    public static function getCourseNameFromCode($code)
5734
    {
5735
        $tbl_main_categories = Database::get_main_table(TABLE_MAIN_COURSE);
5736
        $code = Database::escape_string($code);
5737
        $sql = "SELECT title
5738
                FROM $tbl_main_categories
5739
                WHERE code = '$code'";
5740
        $result = Database::query($sql);
5741
        if ($col = Database::fetch_array($result)) {
5742
            return $col['title'];
5743
        }
5744
    }
5745
5746
    /**
5747
     * Generates a course code from a course title.
5748
     *
5749
     * @todo Such a function might be useful in other places too. It might be moved in the CourseManager class.
5750
     * @todo the function might be upgraded for avoiding code duplications (currently,
5751
     * it might suggest a code that is already in use)
5752
     *
5753
     * @param string $title A course title
5754
     *
5755
     * @return string A proposed course code
5756
     *                +
5757
     * @assert (null,null) === false
5758
     * @assert ('ABC_DEF', null) === 'ABCDEF'
5759
     * @assert ('ABC09*^[%A', null) === 'ABC09A'
5760
     */
5761
    public static function generate_course_code($title)
5762
    {
5763
        return substr(
5764
            preg_replace('/[^A-Z0-9]/', '', strtoupper(api_replace_dangerous_char($title))),
5765
            0,
5766
            self::MAX_COURSE_LENGTH_CODE
5767
        );
5768
    }
5769
5770
    /**
5771
     * this function gets all the users of the course,
5772
     * including users from linked courses.
5773
     *
5774
     * @param $filterByActive
5775
     *
5776
     * @return array
5777
     */
5778
    public static function getCourseUsers($filterByActive = null)
5779
    {
5780
        // This would return only the users from real courses:
5781
        return self::get_user_list_from_course_code(
5782
            api_get_course_id(),
5783
            api_get_session_id(),
5784
            null,
5785
            null,
5786
            null,
5787
            null,
5788
            false,
5789
            false,
5790
            [],
5791
            [],
5792
            [],
5793
            $filterByActive
5794
        );
5795
    }
5796
5797
    /**
5798
     * this function gets all the groups of the course,
5799
     * not including linked courses.
5800
     *
5801
     * @return CGroup[]
5802
     */
5803
    public static function getCourseGroups()
5804
    {
5805
        $sessionId = api_get_session_id();
5806
        $courseCode = api_get_course_id();
5807
        if (0 != $sessionId) {
5808
            $groupList = self::get_group_list_of_course(
5809
                $courseCode,
5810
                $sessionId,
5811
                1
5812
            );
5813
        } else {
5814
            $groupList = self::get_group_list_of_course(
5815
                $courseCode,
5816
                0,
5817
                1
5818
            );
5819
        }
5820
5821
        return $groupList;
5822
    }
5823
5824
    /**
5825
     * @param FormValidator $form
5826
     * @param array         $alreadySelected
5827
     *
5828
     * @return HTML_QuickForm_element
5829
     */
5830
    public static function addUserGroupMultiSelect(&$form, $alreadySelected, $addShortCut = false)
5831
    {
5832
        $userList = self::getCourseUsers(true);
5833
        $groupList = self::getCourseGroups();
5834
5835
        $array = self::buildSelectOptions(
5836
            $groupList,
5837
            $userList,
5838
            $alreadySelected
5839
        );
5840
5841
        $result = [];
5842
        foreach ($array as $content) {
5843
            $result[$content['value']] = $content['content'];
5844
        }
5845
5846
        $multiple = $form->addElement(
5847
            'advmultiselect',
5848
            'users',
5849
            get_lang('Users'),
5850
            $result,
5851
            ['select_all_checkbox' => true, 'id' => 'users']
5852
        );
5853
5854
        $sessionId = api_get_session_id();
5855
        if ($addShortCut && empty($sessionId)) {
5856
            $addStudents = [];
5857
            foreach ($userList as $user) {
5858
                if (STUDENT == $user['status_rel']) {
5859
                    $addStudents[] = $user['user_id'];
5860
                }
5861
            }
5862
            if (!empty($addStudents)) {
5863
                $form->addHtml(
5864
                    '<script>
5865
                    $(function() {
5866
                        $("#add_students").on("click", function() {
5867
                            var addStudents = '.json_encode($addStudents).';
5868
                            $.each(addStudents, function( index, value ) {
5869
                                var option = $("#users option[value=\'USER:"+value+"\']");
5870
                                if (option.val()) {
5871
                                    $("#users_to").append(new Option(option.text(), option.val()))
5872
                                    option.remove();
5873
                                }
5874
                            });
5875
5876
                            return false;
5877
                        });
5878
                    });
5879
                    </script>'
5880
                );
5881
5882
                $form->addLabel(
5883
                    '',
5884
                    Display::url(get_lang('Add learners'), '#', ['id' => 'add_students', 'class' => 'btn btn-primary'])
5885
                );
5886
            }
5887
        }
5888
5889
        return $multiple;
5890
    }
5891
5892
    /**
5893
     * This function separates the users from the groups
5894
     * users have a value USER:XXX (with XXX the groups id have a value
5895
     *  GROUP:YYY (with YYY the group id).
5896
     *
5897
     * @param array $to Array of strings that define the type and id of each destination
5898
     *
5899
     * @return array Array of groups and users (each an array of IDs)
5900
     */
5901
    public static function separateUsersGroups($to)
5902
    {
5903
        $groupList = [];
5904
        $userList = [];
5905
5906
        foreach ($to as $to_item) {
5907
            if (!empty($to_item)) {
5908
                $parts = explode(':', $to_item);
5909
                $type = isset($parts[0]) ? $parts[0] : '';
5910
                $id = isset($parts[1]) ? $parts[1] : '';
5911
5912
                switch ($type) {
5913
                    case 'GROUP':
5914
                        $groupList[] = (int) $id;
5915
                        break;
5916
                    case 'USER':
5917
                        $userList[] = (int) $id;
5918
                        break;
5919
                }
5920
            }
5921
        }
5922
5923
        $send_to['groups'] = $groupList;
5924
        $send_to['users'] = $userList;
5925
5926
        return $send_to;
5927
    }
5928
5929
    /**
5930
     * Shows the form for sending a message to a specific group or user.
5931
     *
5932
     * @return HTML_QuickForm_element
5933
     */
5934
    public static function addGroupMultiSelect(FormValidator $form, CGroup $group, $to = [])
5935
    {
5936
        $groupUsers = GroupManager::get_subscribed_users($group);
5937
        $array = self::buildSelectOptions([$group], $groupUsers, $to);
5938
5939
        $result = [];
5940
        foreach ($array as $content) {
5941
            $result[$content['value']] = $content['content'];
5942
        }
5943
5944
        return $form->addElement('advmultiselect', 'users', get_lang('Users'), $result);
5945
    }
5946
5947
    /**
5948
     * this function shows the form for sending a message to a specific group or user.
5949
     *
5950
     * @param CGroup[] $groupList
5951
     * @param array    $userList
5952
     * @param array    $alreadySelected
5953
     *
5954
     * @return array
5955
     */
5956
    public static function buildSelectOptions($groupList = [], $userList = [], $alreadySelected = [])
5957
    {
5958
        if (empty($alreadySelected)) {
5959
            $alreadySelected = [];
5960
        }
5961
5962
        $result = [];
5963
        // adding the groups to the select form
5964
        if ($groupList) {
5965
            foreach ($groupList as $thisGroup) {
5966
                $groupId = $thisGroup->getIid();
5967
                if (is_array($alreadySelected)) {
5968
                    if (!in_array(
5969
                        "GROUP:".$groupId,
5970
                        $alreadySelected
5971
                    )
5972
                    ) {
5973
                        $userCount = $thisGroup->getMembers()->count();
5974
5975
                        // $alreadySelected is the array containing the groups (and users) that are already selected
5976
                        $userLabel = ($userCount > 0) ? get_lang('Users') : get_lang('user');
5977
                        $userDisabled = ($userCount > 0) ? "" : "disabled=disabled";
5978
                        $result[] = [
5979
                            'disabled' => $userDisabled,
5980
                            'value' => "GROUP:".$groupId,
5981
                            // The space before "G" is needed in order to advmultiselect.php js puts groups first
5982
                            'content' => " G: ".$thisGroup->getName()." - ".$userCount." ".$userLabel,
5983
                        ];
5984
                    }
5985
                }
5986
            }
5987
        }
5988
5989
        // adding the individual users to the select form
5990
        if ($userList) {
5991
            foreach ($userList as $user) {
5992
                if (is_array($alreadySelected)) {
5993
                    if (!in_array(
5994
                        "USER:".$user['user_id'],
5995
                        $alreadySelected
5996
                    )
5997
                    ) {
5998
                        // $alreadySelected is the array containing the users (and groups) that are already selected
5999
                        $result[] = [
6000
                            'value' => "USER:".$user['user_id'],
6001
                            'content' => api_get_person_name($user['firstname'], $user['lastname']),
6002
                        ];
6003
                    }
6004
                }
6005
            }
6006
        }
6007
6008
        return $result;
6009
    }
6010
6011
    /**
6012
     * @return array a list (array) of all courses
6013
     */
6014
    public static function get_course_list()
6015
    {
6016
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
6017
6018
        return Database::store_result(Database::query("SELECT *, id as real_id FROM $table"));
6019
    }
6020
6021
    /**
6022
     * Returns course code from a given gradebook category's id.
6023
     *
6024
     * @param int  Category ID
6025
     *
6026
     * @return string Course code
6027
     */
6028
    public static function get_course_by_category($category_id)
6029
    {
6030
        $category_id = (int) $category_id;
6031
        $sql = 'SELECT c_id FROM '.Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY).'
6032
                WHERE id='.$category_id;
6033
        $info = Database::fetch_array(Database::query($sql), 'ASSOC');
6034
6035
        return $info ? $info['c_id'] : false;
6036
    }
6037
6038
    /**
6039
     * This function gets all the courses that are not in a session.
6040
     *
6041
     * @param date Start date
6042
     * @param date End date
6043
     * @param bool $includeClosed Whether to include closed and hidden courses
6044
     *
6045
     * @return array Not-in-session courses
6046
     */
6047
    public static function getCoursesWithoutSession(
6048
        $startDate = null,
6049
        $endDate = null,
6050
        $includeClosed = false
6051
    ) {
6052
        $dateConditional = ($startDate && $endDate) ?
6053
            " WHERE session_id IN (SELECT id FROM ".Database::get_main_table(TABLE_MAIN_SESSION).
6054
            " WHERE access_start_date = '$startDate' AND access_end_date = '$endDate')" : null;
6055
        $visibility = ($includeClosed ? '' : 'visibility NOT IN (0, 4) AND ');
6056
6057
        $sql = "SELECT id, code, title
6058
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
6059
                WHERE $visibility code NOT IN (
6060
                    SELECT DISTINCT course_code
6061
                    FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE).$dateConditional."
6062
                )
6063
                ORDER BY id";
6064
6065
        $result = Database::query($sql);
6066
        $courses = [];
6067
        while ($row = Database::fetch_array($result)) {
6068
            $courses[] = $row;
6069
        }
6070
6071
        return $courses;
6072
    }
6073
6074
    /**
6075
     * Get list of courses based on users of a group for a group admin.
6076
     *
6077
     * @param int $userId The user id
6078
     *
6079
     * @return array
6080
     */
6081
    public static function getCoursesFollowedByGroupAdmin($userId)
6082
    {
6083
        $coursesList = [];
6084
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
6085
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6086
        $userGroup = new UserGroupModel();
6087
        $userIdList = $userGroup->getGroupUsersByUser($userId);
6088
6089
        if (empty($userIdList)) {
6090
            return [];
6091
        }
6092
6093
        $sql = "SELECT DISTINCT(c.id), c.title
6094
                FROM $courseTable c
6095
                INNER JOIN $courseUserTable cru ON c.id = cru.c_id
6096
                WHERE (
6097
                    cru.user_id IN (".implode(', ', $userIdList).")
6098
                    AND cru.relation_type = 0
6099
                )";
6100
6101
        if (api_is_multiple_url_enabled()) {
6102
            $courseAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
6103
            $accessUrlId = api_get_current_access_url_id();
6104
6105
            if (-1 != $accessUrlId) {
6106
                $sql = "SELECT DISTINCT(c.id), c.title
6107
                        FROM $courseTable c
6108
                        INNER JOIN $courseUserTable cru ON c.id = cru.c_id
6109
                        INNER JOIN $courseAccessUrlTable crau ON c.id = crau.c_id
6110
                        WHERE crau.access_url_id = $accessUrlId
6111
                            AND (
6112
                            cru.id_user IN (".implode(', ', $userIdList).") AND
6113
                            cru.relation_type = 0
6114
                        )";
6115
            }
6116
        }
6117
6118
        $result = Database::query($sql);
6119
        while ($row = Database::fetch_assoc($result)) {
6120
            $coursesList[] = $row;
6121
        }
6122
6123
        return $coursesList;
6124
    }
6125
6126
    /**
6127
     * Direct course link see #5299.
6128
     *
6129
     * You can send to your students an URL like this
6130
     * http://chamilodev.beeznest.com/main/auth/inscription.php?c=ABC&e=3
6131
     * Where "c" is the course code and "e" is the exercise Id, after a successful
6132
     * registration the user will be sent to the course or exercise
6133
     *
6134
     * @param array $form_data
6135
     *
6136
     * @return array
6137
     */
6138
    public static function redirectToCourse($form_data)
6139
    {
6140
        $course_code_redirect = Session::read('course_redirect');
6141
        $_user = api_get_user_info();
6142
        $userId = api_get_user_id();
6143
6144
        if (!empty($course_code_redirect)) {
6145
            $course_info = api_get_course_info($course_code_redirect);
6146
            if (!empty($course_info)) {
6147
                if (in_array(
6148
                    $course_info['visibility'],
6149
                    [Course::OPEN_PLATFORM, Course::OPEN_WORLD]
6150
                )
6151
                ) {
6152
                    if (self::is_user_subscribed_in_course($userId, $course_info['code'])) {
6153
                        $form_data['action'] = $course_info['course_public_url'];
6154
                        $form_data['message'] = sprintf(get_lang('You have been registered to course %s'), $course_info['title']);
6155
                        $form_data['button'] = Display::button(
6156
                            'next',
6157
                            get_lang('Go to the course', null, $_user['language']),
6158
                            ['class' => 'btn btn-primary btn-large']
6159
                        );
6160
6161
                        $exercise_redirect = (int) Session::read('exercise_redirect');
6162
                        // Specify the course id as the current context does not
6163
                        // hold a global $_course array
6164
                        $objExercise = new Exercise($course_info['real_id']);
6165
                        $result = $objExercise->read($exercise_redirect);
6166
6167
                        if (!empty($exercise_redirect) && !empty($result)) {
6168
                            $form_data['action'] = api_get_path(WEB_CODE_PATH).
6169
                                'exercise/overview.php?exerciseId='.$exercise_redirect.'&cid='.$course_info['real_id'];
6170
                            $form_data['message'] .= '<br />'.get_lang('Go to the test');
6171
                            $form_data['button'] = Display::button(
6172
                                'next',
6173
                                get_lang('Go', null, $_user['language']),
6174
                                ['class' => 'btn btn-primary btn-large']
6175
                            );
6176
                        }
6177
6178
                        if (!empty($form_data['action'])) {
6179
                            header('Location: '.$form_data['action']);
6180
                            exit;
6181
                        }
6182
                    }
6183
                }
6184
            }
6185
        }
6186
6187
        return $form_data;
6188
    }
6189
6190
    /**
6191
     * Return tab of params to display a course title in the My Courses tab
6192
     * Check visibility, right, and notification icons, and load_dirs option
6193
     * get html course params.
6194
     *
6195
     * @param $courseId
6196
     * @param bool $loadDirs
6197
     *
6198
     * @return array with keys ['right_actions'] ['teachers'] ['notifications']
6199
     */
6200
    public static function getCourseParamsForDisplay($courseId, $loadDirs = false)
6201
    {
6202
        $userId = api_get_user_id();
6203
        $courseId = intval($courseId);
6204
        // Table definitions
6205
        $TABLECOURS = Database::get_main_table(TABLE_MAIN_COURSE);
6206
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6207
        $TABLE_ACCESS_URL_REL_COURSE = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
6208
        $current_url_id = api_get_current_access_url_id();
6209
6210
        // Get course list auto-register
6211
        $special_course_list = self::get_special_course_list();
6212
6213
        $without_special_courses = '';
6214
        if (!empty($special_course_list)) {
6215
            $without_special_courses = ' AND course.id NOT IN ("'.implode('","', $special_course_list).'")';
6216
        }
6217
6218
        //AND course_rel_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
6219
        $sql = "SELECT
6220
                    course.id,
6221
                    course.title,
6222
                    course.code,
6223
                    course.subscribe subscr,
6224
                    course.unsubscribe unsubscr,
6225
                    course_rel_user.status status,
6226
                    course_rel_user.sort sort,
6227
                    course_rel_user.user_course_cat user_course_cat
6228
                FROM
6229
                $TABLECOURS course
6230
                INNER JOIN $TABLECOURSUSER course_rel_user
6231
                ON (course.id = course_rel_user.c_id)
6232
                INNER JOIN $TABLE_ACCESS_URL_REL_COURSE url
6233
                ON (url.c_id = course.id)
6234
                WHERE
6235
                    course.id = $courseId AND
6236
                    course_rel_user.user_id = $userId
6237
                    $without_special_courses
6238
                ";
6239
6240
        // If multiple URL access mode is enabled, only fetch courses
6241
        // corresponding to the current URL.
6242
        if (api_get_multiple_access_url() && -1 != $current_url_id) {
6243
            $sql .= " AND url.c_id = course.id AND access_url_id = $current_url_id";
6244
        }
6245
        // Use user's classification for courses (if any).
6246
        $sql .= " ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC";
6247
6248
        $result = Database::query($sql);
6249
6250
        // Browse through all courses. We can only have one course because
6251
        // of the  course.id=".intval($courseId) in sql query
6252
        $course = Database::fetch_array($result);
6253
        $course_info = api_get_course_info_by_id($courseId);
6254
        if (empty($course_info)) {
6255
            return '';
6256
        }
6257
6258
        //$course['id_session'] = null;
6259
        $course_info['id_session'] = null;
6260
        $course_info['status'] = $course['status'];
6261
6262
        // For each course, get if there is any notification icon to show
6263
        // (something that would have changed since the user's last visit).
6264
        $show_notification = !api_get_configuration_value('hide_course_notification')
6265
            ? Display::show_notification($course_info)
6266
            : '';
6267
6268
        // New code displaying the user's status in respect to this course.
6269
        $status_icon = Display::return_icon(
6270
            'blackboard.png',
6271
            $course_info['title'],
6272
            [],
6273
            ICON_SIZE_LARGE
6274
        );
6275
6276
        $params = [];
6277
        $params['right_actions'] = '';
6278
6279
        if (api_is_platform_admin()) {
6280
            if ($loadDirs) {
6281
                $params['right_actions'] .= '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview" href="javascript:void(0);">'.Display::return_icon('folder.png', get_lang('Documents'), ['align' => 'absmiddle'], ICON_SIZE_SMALL).'</a>';
6282
                $params['right_actions'] .= '<a href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'].'">'.
6283
                    Display::return_icon('edit.png', get_lang('Edit'), ['align' => 'absmiddle'], ICON_SIZE_SMALL).
6284
                    '</a>';
6285
                $params['right_actions'] .= Display::div(
6286
                    '',
6287
                    [
6288
                        'id' => 'document_result_'.$course_info['real_id'].'_0',
6289
                        'class' => 'document_preview_container',
6290
                    ]
6291
                );
6292
            } else {
6293
                $params['right_actions'] .=
6294
                    '<a class="btn btn-default btn-sm" title="'.get_lang('Edit').'" href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'].'">'.
6295
                    Display::returnFontAwesomeIcon('pencil').'</a>';
6296
            }
6297
        } else {
6298
            if (COURSE_VISIBILITY_CLOSED != $course_info['visibility']) {
6299
                if ($loadDirs) {
6300
                    $params['right_actions'] .= '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview" href="javascript:void(0);">'.
6301
                        Display::return_icon('folder.png', get_lang('Documents'), ['align' => 'absmiddle'], ICON_SIZE_SMALL).'</a>';
6302
                    $params['right_actions'] .= Display::div(
6303
                        '',
6304
                        [
6305
                            'id' => 'document_result_'.$course_info['real_id'].'_0',
6306
                            'class' => 'document_preview_container',
6307
                        ]
6308
                    );
6309
                } else {
6310
                    if (COURSEMANAGER == $course_info['status']) {
6311
                        $params['right_actions'] .= '<a
6312
                            class="btn btn-default btn-sm" title="'.get_lang('Edit').'" href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'].'">'.
6313
                            Display::returnFontAwesomeIcon('pencil').'</a>';
6314
                    }
6315
                }
6316
            }
6317
        }
6318
6319
        $course_title_url = '';
6320
        if (COURSE_VISIBILITY_CLOSED != $course_info['visibility'] || COURSEMANAGER == $course['status']) {
6321
            $course_title_url = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/?id_session=0';
6322
            $course_title = Display::url($course_info['title'], $course_title_url);
6323
        } else {
6324
            $course_title = $course_info['title'].' '.Display::tag(
6325
                'span',
6326
                get_lang('(the course is currently closed)'),
6327
                ['class' => 'item_closed']
6328
            );
6329
        }
6330
6331
        // Start displaying the course block itself
6332
        if ('true' === api_get_setting('display_coursecode_in_courselist')) {
6333
            $course_title .= ' ('.$course_info['visual_code'].') ';
6334
        }
6335
        $teachers = '';
6336
        if ('true' === api_get_setting('display_teacher_in_courselist')) {
6337
            $teachers = self::getTeacherListFromCourseCodeToString(
6338
                $course['code'],
6339
                self::USER_SEPARATOR,
6340
                true
6341
            );
6342
        }
6343
        $params['link'] = $course_title_url;
6344
        $params['icon'] = $status_icon;
6345
        $params['title'] = $course_title;
6346
        $params['teachers'] = $teachers;
6347
        if (COURSE_VISIBILITY_CLOSED != $course_info['visibility']) {
6348
            $params['notifications'] = $show_notification;
6349
        }
6350
6351
        return $params;
6352
    }
6353
6354
    /**
6355
     * Get the course id based on the original id and field name in the extra fields.
6356
     * Returns 0 if course was not found.
6357
     *
6358
     * @param string $original_course_id_value Original course id
6359
     * @param string $original_course_id_name  Original field name
6360
     *
6361
     * @return int Course id
6362
     */
6363
    public static function get_course_id_from_original_id($original_course_id_value, $original_course_id_name)
6364
    {
6365
        $extraFieldValue = new ExtraFieldValue('course');
6366
        $value = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
6367
            $original_course_id_name,
6368
            $original_course_id_value
6369
        );
6370
6371
        if ($value) {
6372
            return $value['item_id'];
6373
        }
6374
6375
        return 0;
6376
    }
6377
6378
    /**
6379
     * Helper function to create a default gradebook (if necessary) upon course creation.
6380
     *
6381
     * @param int    $modelId    The gradebook model ID
6382
     * @param string $courseCode Course code
6383
     */
6384
    public static function createDefaultGradebook($modelId, $courseCode)
6385
    {
6386
        if ('true' === api_get_setting('gradebook_enable_grade_model')) {
6387
            //Create gradebook_category for the new course and add
6388
            // a gradebook model for the course
6389
            if (isset($modelId) &&
6390
                !empty($modelId) &&
6391
                '-1' != $modelId
6392
            ) {
6393
                GradebookUtils::create_default_course_gradebook(
6394
                    $courseCode,
6395
                    $modelId
6396
                );
6397
            }
6398
        }
6399
    }
6400
6401
    /**
6402
     * Helper function to check if there is a course template and, if so, to
6403
     * copy the template as basis for the new course.
6404
     *
6405
     * @param string $courseCode     Course code
6406
     * @param int    $courseTemplate 0 if no course template is defined
6407
     */
6408
    public static function useTemplateAsBasisIfRequired($courseCode, $courseTemplate)
6409
    {
6410
        $template = api_get_setting('course_creation_use_template');
6411
        $teacherCanSelectCourseTemplate = 'true' === api_get_setting('teacher_can_select_course_template');
6412
        $courseTemplate = isset($courseTemplate) ? intval($courseTemplate) : 0;
6413
6414
        $useTemplate = false;
6415
6416
        if ($teacherCanSelectCourseTemplate && $courseTemplate) {
6417
            $useTemplate = true;
6418
            $originCourse = api_get_course_info_by_id($courseTemplate);
6419
        } elseif (!empty($template)) {
6420
            $useTemplate = true;
6421
            $originCourse = api_get_course_info_by_id($template);
6422
        }
6423
6424
        if ($useTemplate) {
6425
            // Include the necessary libraries to generate a course copy
6426
            // Call the course copy object
6427
            $originCourse['official_code'] = $originCourse['code'];
6428
            $cb = new CourseBuilder(null, $originCourse);
6429
            $course = $cb->build(null, $originCourse['code']);
6430
            $cr = new CourseRestorer($course);
6431
            $cr->set_file_option();
6432
            $cr->restore($courseCode);
6433
        }
6434
    }
6435
6436
    /**
6437
     * Helper method to get the number of users defined with a specific course extra field.
6438
     *
6439
     * @param string $name                 Field title
6440
     * @param string $tableExtraFields     The extra fields table name
6441
     * @param string $tableUserFieldValues The user extra field value table name
6442
     *
6443
     * @return int The number of users with this extra field with a specific value
6444
     */
6445
    public static function getCountRegisteredUsersWithCourseExtraField(
6446
        $name,
6447
        $tableExtraFields = '',
6448
        $tableUserFieldValues = ''
6449
    ) {
6450
        if (empty($tableExtraFields)) {
6451
            $tableExtraFields = Database::get_main_table(TABLE_EXTRA_FIELD);
6452
        }
6453
        if (empty($tableUserFieldValues)) {
6454
            $tableUserFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
6455
        }
6456
6457
        $registered_users_with_extra_field = 0;
6458
        if (!empty($name) && '-' != $name) {
6459
            $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
6460
            $name = Database::escape_string($name);
6461
            $sql = "SELECT count(v.item_id) as count
6462
                    FROM $tableUserFieldValues v
6463
                    INNER JOIN $tableExtraFields f
6464
                    ON (f.id = v.field_id)
6465
                    WHERE value = '$name' AND extra_field_type = $extraFieldType";
6466
            $result_count = Database::query($sql);
6467
            if (Database::num_rows($result_count)) {
6468
                $row_count = Database::fetch_array($result_count);
6469
                $registered_users_with_extra_field = $row_count['count'];
6470
            }
6471
        }
6472
6473
        return $registered_users_with_extra_field;
6474
    }
6475
6476
    /**
6477
     * Get the course categories form a course list.
6478
     *
6479
     * @return array
6480
     */
6481
    public static function getCourseCategoriesFromCourseList(array $courseList)
6482
    {
6483
        $allCategories = array_column($courseList, 'category');
6484
        $categories = array_unique($allCategories);
6485
6486
        sort($categories);
6487
6488
        return $categories;
6489
    }
6490
6491
    /**
6492
     * Display the description button of a course in the course catalog.
6493
     *
6494
     * @param array  $course
6495
     * @param string $url
6496
     *
6497
     * @return string HTML string
6498
     */
6499
    public static function returnDescriptionButton($course, $url = '')
6500
    {
6501
        if (empty($course)) {
6502
            return '';
6503
        }
6504
6505
        $class = '';
6506
        if ('true' === api_get_setting('show_courses_descriptions_in_catalog')) {
6507
            $title = $course['title'];
6508
            if (empty($url)) {
6509
                $class = 'ajax';
6510
                $url = api_get_path(WEB_CODE_PATH).
6511
                    'inc/ajax/course_home.ajax.php?a=show_course_information&code='.$course['code'];
6512
            } else {
6513
                if (false !== strpos($url, 'ajax')) {
6514
                    $class = 'ajax';
6515
                }
6516
            }
6517
6518
            return Display::url(
6519
                Display::returnFontAwesomeIcon('info-circle', 'lg'),
6520
                $url,
6521
                [
6522
                    'class' => "$class btn btn-default btn-sm",
6523
                    'data-title' => $title,
6524
                    'title' => get_lang('Description'),
6525
                    'aria-label' => get_lang('Description'),
6526
                    'data-size' => 'lg',
6527
                ]
6528
            );
6529
        }
6530
6531
        return '';
6532
    }
6533
6534
    /**
6535
     * @return int
6536
     */
6537
    public static function getCountOpenCourses()
6538
    {
6539
        $visibility = [
6540
            Course::REGISTERED,
6541
            Course::OPEN_PLATFORM,
6542
            Course::OPEN_WORLD,
6543
        ];
6544
6545
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
6546
        $sql = "SELECT count(id) count
6547
                FROM $table
6548
                WHERE visibility IN (".implode(',', $visibility).")";
6549
        $result = Database::query($sql);
6550
        $row = Database::fetch_array($result);
6551
6552
        return (int) $row['count'];
6553
    }
6554
6555
    /**
6556
     * @return int
6557
     */
6558
    public static function getCountExercisesFromOpenCourse()
6559
    {
6560
        $visibility = [
6561
            Course::REGISTERED,
6562
            Course::OPEN_PLATFORM,
6563
            Course::OPEN_WORLD,
6564
        ];
6565
6566
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
6567
        $tableExercise = Database::get_course_table(TABLE_QUIZ_TEST);
6568
        $sql = "SELECT count(e.iid) count
6569
                FROM $table c
6570
                INNER JOIN $tableExercise e
6571
                ON (c.id = e.c_id)
6572
                WHERE e.active <> -1 AND visibility IN (".implode(',', $visibility).")";
6573
        $result = Database::query($sql);
6574
        $row = Database::fetch_array($result);
6575
6576
        return (int) $row['count'];
6577
    }
6578
6579
    /**
6580
     * retrieves all the courses that the user has already subscribed to.
6581
     *
6582
     * @param int $user_id
6583
     *
6584
     * @return array an array containing all the information of the courses of the given user
6585
     */
6586
    public static function getCoursesByUserCourseCategory($user_id)
6587
    {
6588
        $course = Database::get_main_table(TABLE_MAIN_COURSE);
6589
        $courseRelUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6590
        $avoidCoursesCondition = CoursesAndSessionsCatalog::getAvoidCourseCondition();
6591
        $visibilityCondition = self::getCourseVisibilitySQLCondition('course', true);
6592
6593
        // Secondly we select the courses that are in a category (user_course_cat<>0) and
6594
        // sort these according to the sort of the category
6595
        $user_id = (int) $user_id;
6596
        $sql = "SELECT
6597
                    course.code k,
6598
                    course.visual_code vc,
6599
                    course.subscribe subscr,
6600
                    course.unsubscribe unsubscr,
6601
                    course.title i,
6602
                    course.tutor_name t,
6603
                    course.category_code cat,
6604
                    course.directory dir,
6605
                    course_rel_user.status status,
6606
                    course_rel_user.sort sort,
6607
                    course_rel_user.user_course_cat user_course_cat
6608
                FROM $course course, $courseRelUser course_rel_user
6609
                WHERE
6610
                    course.id = course_rel_user.c_id AND
6611
                    course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
6612
                    course_rel_user.user_id = '".$user_id."'
6613
                    $avoidCoursesCondition
6614
                    $visibilityCondition
6615
                ORDER BY course_rel_user.sort ASC";
6616
6617
        $result = Database::query($sql);
6618
        $courses = [];
6619
        while ($row = Database::fetch_array($result, 'ASOC')) {
6620
            $courses[] = [
6621
                'code' => $row['k'],
6622
                'visual_code' => $row['vc'],
6623
                'title' => $row['i'],
6624
                'directory' => $row['dir'],
6625
                'status' => $row['status'],
6626
                'tutor' => $row['t'],
6627
                'subscribe' => $row['subscr'],
6628
                'category' => $row['cat'],
6629
                'unsubscribe' => $row['unsubscr'],
6630
                'sort' => $row['sort'],
6631
                'user_course_category' => $row['user_course_cat'],
6632
            ];
6633
        }
6634
6635
        return $courses;
6636
    }
6637
6638
    /**
6639
     * @param string $listType
6640
     *
6641
     * @return string
6642
     */
6643
    public static function getCourseListTabs($listType)
6644
    {
6645
        $tabs = [
6646
            [
6647
                'content' => get_lang('Standard list'),
6648
                'url' => api_get_path(WEB_CODE_PATH).'admin/course_list.php',
6649
            ],
6650
            [
6651
                'content' => get_lang('Management List'),
6652
                'url' => api_get_path(WEB_CODE_PATH).'admin/course_list_admin.php',
6653
            ],
6654
        ];
6655
6656
        $default = 1;
6657
        switch ($listType) {
6658
            case 'simple':
6659
                $default = 1;
6660
                break;
6661
            case 'admin':
6662
                $default = 2;
6663
                break;
6664
        }
6665
6666
        return Display::tabsOnlyLink($tabs, $default);
6667
    }
6668
6669
    public static function getUrlMarker($courseId)
6670
    {
6671
        if (UrlManager::getCountAccessUrlFromCourse($courseId) > 1) {
6672
            return '&nbsp;'.Display::returnFontAwesomeIcon(
6673
                'link',
6674
                null,
6675
                null,
6676
                null,
6677
                get_lang('CourseUsedInOtherURL')
6678
            );
6679
        }
6680
6681
        return '';
6682
    }
6683
6684
    public static function insertUserInCourse(int $studentId, int $courseId, array $relationInfo = [])
6685
    {
6686
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6687
6688
        $relationInfo = array_merge(
6689
            ['relation_type' => 0, 'status' => STUDENT, 'sort' => 0, 'user_course_cat' => 0],
6690
            $relationInfo
6691
        );
6692
6693
        Database::insert(
6694
            $courseUserTable,
6695
            [
6696
                'c_id' => $courseId,
6697
                'user_id' => $studentId,
6698
                'status' => $relationInfo['status'],
6699
                'sort' => $relationInfo['sort'],
6700
                'relation_type' => $relationInfo['relation_type'],
6701
                'user_course_cat' => $relationInfo['user_course_cat'],
6702
            ]
6703
        );
6704
6705
        Event::logSubscribedUserInCourse($studentId, $courseId);
6706
    }
6707
    /**
6708
     * Check if a specific access-url-related setting is a problem or not.
6709
     *
6710
     * @param array  $_configuration The $_configuration array
6711
     * @param int    $accessUrlId    The access URL ID
6712
     * @param string $param
6713
     * @param string $msgLabel
6714
     *
6715
     * @return bool|string
6716
     */
6717
    private static function checkCreateCourseAccessUrlParam($_configuration, $accessUrlId, $param, $msgLabel)
6718
    {
6719
        if (isset($_configuration[$accessUrlId][$param]) && $_configuration[$accessUrlId][$param] > 0) {
6720
            $num = null;
6721
            switch ($param) {
6722
                case 'hosting_limit_courses':
6723
            $num = self::count_courses($accessUrlId);
6724
                    break;
6725
                case 'hosting_limit_active_courses':
6726
                    $num = self::countActiveCourses($accessUrlId);
6727
                    break;
6728
            }
6729
6730
            if ($num && $num >= $_configuration[$accessUrlId][$param]) {
6731
                api_warn_hosting_contact($param);
6732
6733
                Display::addFlash(
6734
                    Display::return_message($msgLabel)
6735
                );
6736
6737
                return true;
6738
            }
6739
        }
6740
6741
        return false;
6742
    }
6743
6744
    /**
6745
     * Fill course with all necessary items.
6746
     *
6747
     * @param array $courseInfo Course info array
6748
     * @param array $params     Parameters from the course creation form
6749
     * @param int   $authorId
6750
     */
6751
    private static function fillCourse($courseInfo, $params, $authorId = 0)
6752
    {
6753
        $authorId = empty($authorId) ? api_get_user_id() : (int) $authorId;
6754
6755
        AddCourse::fillCourse(
6756
            $courseInfo,
6757
            $params['exemplary_content'],
6758
            $authorId
6759
        );
6760
6761
        if (isset($params['gradebook_model_id'])) {
6762
            self::createDefaultGradebook(
6763
                $params['gradebook_model_id'],
6764
                $courseInfo['code']
6765
            );
6766
        }
6767
6768
        // If parameter defined, copy the contents from a specific
6769
        // template course into this new course
6770
        if (isset($params['course_template'])) {
6771
            self::useTemplateAsBasisIfRequired(
6772
                $courseInfo['id'],
6773
                $params['course_template']
6774
            );
6775
        }
6776
        $params['course_code'] = $courseInfo['code'];
6777
        $params['item_id'] = $courseInfo['real_id'];
6778
6779
        $courseFieldValue = new ExtraFieldValue('course');
6780
        $courseFieldValue->saveFieldValues($params);
6781
    }
6782
6783
    public static function addVisibilityOptions(FormValidator $form): void
6784
    {
6785
        $group = [];
6786
        $group[] = $form->createElement(
6787
            'radio',
6788
            'visibility',
6789
            get_lang('Course access'),
6790
            get_lang('Public - access allowed for the whole world'),
6791
            Course::OPEN_WORLD
6792
        );
6793
        $group[] = $form->createElement(
6794
            'radio',
6795
            'visibility',
6796
            null,
6797
            get_lang(' Open - access allowed for users registered on the platform'),
6798
            Course::OPEN_PLATFORM
6799
        );
6800
        $group[] = $form->createElement(
6801
            'radio',
6802
            'visibility',
6803
            null,
6804
            get_lang('Private access (access authorized to group members only)'),
6805
            Course::REGISTERED
6806
        );
6807
        $group[] = $form->createElement(
6808
            'radio',
6809
            'visibility',
6810
            null,
6811
            get_lang('Closed - the course is only accessible to the teachers'),
6812
            Course::CLOSED
6813
        );
6814
        $group[] = $form->createElement(
6815
            'radio',
6816
            'visibility',
6817
            null,
6818
            get_lang('Hidden - Completely hidden to all users except the administrators'),
6819
            Course::HIDDEN
6820
        );
6821
        $form->addGroup($group, '', get_lang('Course access'));
6822
    }
6823
}
6824