Passed
Push — master ( 1c618d...c1c6b0 )
by Yannick
10:36 queued 02:52
created

CourseManager::get_courses_list()   F

Complexity

Conditions 21
Paths 10368

Size

Total Lines 116
Code Lines 72

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 21
eloc 72
nc 10368
nop 10
dl 0
loc 116
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/* For licensing terms, see /license.txt*/
4
5
use Chamilo\CoreBundle\Entity\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\Entity\Session as SessionEntity;
11
use Chamilo\CoreBundle\Entity\User;
12
use Chamilo\CoreBundle\Framework\Container;
13
use Chamilo\CoreBundle\Repository\SequenceResourceRepository;
14
use Chamilo\CourseBundle\Component\CourseCopy\CourseBuilder;
15
use Chamilo\CourseBundle\Component\CourseCopy\CourseRestorer;
16
use Chamilo\CourseBundle\Entity\CGroup;
17
use ChamiloSession as Session;
18
use Doctrine\Common\Collections\Criteria;
19
use Chamilo\CoreBundle\Component\Utils\ActionIcon;
20
use Chamilo\CoreBundle\Component\Utils\ObjectIcon;
21
22
/**
23
 * Class CourseManager.
24
 *
25
 * This is the course library for Chamilo.
26
 *
27
 * All main course functions should be placed here.
28
 *
29
 * There are probably some places left with the wrong code.
30
 */
31
class CourseManager
32
{
33
    public const MAX_COURSE_LENGTH_CODE = 40;
34
    /** This constant is used to show separate user names in the course
35
     * list (userportal), footer, etc */
36
    public const USER_SEPARATOR = ' |';
37
38
    /**
39
     * Creates a course.
40
     *
41
     * @param array $params      Columns in the main.course table.
42
     * @param int   $authorId    Optional.
43
     * @param int   $accessUrlId Optional.
44
     *
45
     * @return Course|null
46
     */
47
    public static function create_course($params, $authorId = 0, $accessUrlId = 0)
48
    {
49
        // Check portal limits
50
        $accessUrlId = !empty($accessUrlId) ? (int) $accessUrlId : api_get_current_access_url_id();
51
        $authorId = empty($authorId) ? api_get_user_id() : (int) $authorId;
52
53
        if (empty($params['title'])) {
54
            return false;
55
        }
56
57
        if (empty($params['wanted_code'])) {
58
            $params['wanted_code'] = $params['title'];
59
            // Check whether the requested course code has already been occupied.
60
            $substring = api_substr($params['title'], 0, self::MAX_COURSE_LENGTH_CODE);
61
            if (false === $substring || empty($substring)) {
62
                return false;
63
            } else {
64
                $params['wanted_code'] = self::generate_course_code($substring);
65
            }
66
        }
67
68
        // Create the course keys
69
        $keys = AddCourse::define_course_keys($params['wanted_code']);
70
        $params['exemplary_content'] = $params['exemplary_content'] ?? false;
71
72
        if (count($keys)) {
73
            $params['code'] = $keys['currentCourseCode'];
74
            $params['visual_code'] = $keys['currentCourseId'];
75
            $params['directory'] = $keys['currentCourseRepository'];
76
            $courseInfo = api_get_course_info($params['code']);
77
            if (empty($courseInfo)) {
78
                $course = AddCourse::register_course($params);
79
                if (null !== $course) {
80
                    self::fillCourse($course, $params, $authorId);
81
82
                    return $course;
83
                }
84
            }
85
        }
86
87
        return null;
88
    }
89
90
    /**
91
     * Returns all the information of a given course code.
92
     *
93
     * @param string $course_code , the course code
94
     *
95
     * @return array with all the fields of the course table
96
     *
97
     * @deprecated Use api_get_course_info() instead
98
     *
99
     * @author Patrick Cool <[email protected]>, Ghent University
100
     * @assert ('') === false
101
     */
102
    public static function get_course_information($course_code)
103
    {
104
        return Database::fetch_array(
105
            Database::query(
106
                "SELECT *, id as real_id FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
107
                WHERE code = '".Database::escape_string($course_code)."'"
108
            ),
109
            'ASSOC'
110
        );
111
    }
112
113
    /**
114
     * Returns a list of courses. Should work with quickform syntax.
115
     *
116
     * @param int    $from               Offset (from the 7th = '6'). Optional.
117
     * @param int    $howmany            Number of results we want. Optional.
118
     * @param string $orderby            The column we want to order it by. Optional, defaults to first column.
119
     * @param string $orderdirection     The direction of the order (ASC or DESC). Optional, defaults to ASC.
120
     * @param int    $visibility         the visibility of the course, or all by default
121
     * @param string $startwith          If defined, only return results for which the course *title* begins with this
122
     *                                   string
123
     * @param string $urlId              The Access URL ID, if using multiple URLs
124
     * @param bool   $alsoSearchCode     An extension option to indicate that we also want to search for course codes
125
     *                                   (not *only* titles)
126
     * @param array  $conditionsLike
127
     * @param array  $onlyThisCourseList
128
     *
129
     * @return array
130
     */
131
    public static function get_courses_list(
132
        $from = 0,
133
        $howmany = 0,
134
        $orderby = 'title',
135
        $orderdirection = 'ASC',
136
        $visibility = -1,
137
        $startwith = '',
138
        $urlId = null,
139
        $alsoSearchCode = false,
140
        $conditionsLike = [],
141
        $onlyThisCourseList = []
142
    ) {
143
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
144
        $sql = "SELECT course.*, course.id as real_id
145
                FROM $courseTable course  ";
146
147
        if (!empty($urlId)) {
148
            $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
149
            $sql .= " INNER JOIN $table url ON (url.c_id = course.id) ";
150
        }
151
152
        $visibility = (int) $visibility;
153
154
        if (!empty($startwith)) {
155
            $sql .= "WHERE (title LIKE '".Database::escape_string($startwith)."%' ";
156
            if ($alsoSearchCode) {
157
                $sql .= "OR code LIKE '".Database::escape_string($startwith)."%' ";
158
            }
159
            $sql .= ') ';
160
            if (-1 !== $visibility) {
161
                $sql .= " AND visibility = $visibility ";
162
            }
163
        } else {
164
            $sql .= 'WHERE 1 ';
165
            if (-1 !== $visibility) {
166
                $sql .= " AND visibility = $visibility ";
167
            }
168
        }
169
170
        if (!empty($urlId)) {
171
            $urlId = (int) $urlId;
172
            $sql .= " AND access_url_id = $urlId";
173
        }
174
175
        if (!empty($onlyThisCourseList)) {
176
            $onlyThisCourseList = array_map('intval', $onlyThisCourseList);
177
            $onlyThisCourseList = implode("','", $onlyThisCourseList);
178
            $sql .= " AND course.id IN ('$onlyThisCourseList') ";
179
        }
180
181
        $allowedFields = [
182
            'title',
183
            'code',
184
        ];
185
186
        if (count($conditionsLike) > 0) {
187
            $sql .= ' AND ';
188
            $temp_conditions = [];
189
            foreach ($conditionsLike as $field => $value) {
190
                if (!in_array($field, $allowedFields)) {
191
                    continue;
192
                }
193
                $field = Database::escape_string($field);
194
                $value = Database::escape_string($value);
195
                $simple_like = false;
196
                if ($simple_like) {
197
                    $temp_conditions[] = $field." LIKE '$value%'";
198
                } else {
199
                    $temp_conditions[] = $field.' LIKE \'%'.$value.'%\'';
200
                }
201
            }
202
            $condition = ' AND ';
203
            if (!empty($temp_conditions)) {
204
                $sql .= implode(' '.$condition.' ', $temp_conditions);
205
            }
206
        }
207
208
        if (empty($orderby)) {
209
            $sql .= ' ORDER BY title ';
210
        } else {
211
            if (in_array($orderby, ['title'])) {
212
                $sql .= " ORDER BY `".Database::escape_string($orderby)."` ";
213
            } else {
214
                $sql .= ' ORDER BY title ';
215
            }
216
        }
217
218
        $orderdirection = strtoupper($orderdirection);
219
        if (!in_array($orderdirection, ['ASC', 'DESC'])) {
220
            $sql .= 'ASC';
221
        } else {
222
            $sql .= 'ASC' === $orderdirection ? 'ASC' : 'DESC';
223
        }
224
225
        $howmany = (int) $howmany;
226
        if (!empty($howmany)) {
227
            $sql .= ' LIMIT '.$howmany;
228
        } else {
229
            $sql .= ' LIMIT 1000000'; //virtually no limit
230
        }
231
        if (!empty($from)) {
232
            $from = intval($from);
233
            $sql .= ' OFFSET '.intval($from);
234
        } else {
235
            $sql .= ' OFFSET 0';
236
        }
237
238
        $data = [];
239
        $res = Database::query($sql);
240
        if (Database::num_rows($res) > 0) {
241
            while ($row = Database::fetch_assoc($res)) {
242
                $data[] = $row;
243
            }
244
        }
245
246
        return $data;
247
    }
248
249
    /**
250
     * Returns the status of a user in a course, which is COURSEMANAGER or STUDENT.
251
     *
252
     * @param int $userId
253
     * @param int $courseId
254
     *
255
     * @return int|bool the status of the user in that course (or false if the user is not in that course)
256
     */
257
    public static function getUserInCourseStatus($userId, $courseId)
258
    {
259
        $courseId = (int) $courseId;
260
        $userId = (int) $userId;
261
        if (empty($courseId)) {
262
            return false;
263
        }
264
265
        $result = Database::fetch_array(
266
            Database::query(
267
                "SELECT status FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
268
                WHERE
269
                    c_id  = $courseId AND
270
                    user_id = $userId"
271
            )
272
        );
273
274
        if (empty($result['status'])) {
275
            return false;
276
        }
277
278
        return $result['status'];
279
    }
280
281
    /**
282
     * @param int $userId
283
     * @param int $courseId
284
     *
285
     * @return mixed
286
     */
287
    public static function getUserCourseInfo($userId, $courseId)
288
    {
289
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
290
                WHERE
291
                    c_id  = ".intval($courseId)." AND
292
                    user_id = ".intval($userId);
293
294
        return Database::fetch_array(Database::query($sql));
295
    }
296
297
    /**
298
     * @param int  $userId
299
     * @param int  $courseId
300
     * @param bool $isTutor
301
     *
302
     * @return bool
303
     */
304
    public static function updateUserCourseTutor($userId, $courseId, $isTutor)
305
    {
306
        $table = Database::escape_string(TABLE_MAIN_COURSE_USER);
307
308
        $courseId = (int) $courseId;
309
        $isTutor = (int) $isTutor;
310
311
        $sql = "UPDATE $table SET is_tutor = '".$isTutor."'
312
			    WHERE
313
				    user_id = ".$userId." AND
314
				    c_id = ".$courseId;
315
316
        $result = Database::query($sql);
317
318
        if (Database::affected_rows($result) > 0) {
319
            return true;
320
        }
321
322
        return false;
323
    }
324
325
    /**
326
     * @param int $userId
327
     * @param int $courseId
328
     *
329
     * @return mixed
330
     */
331
    public static function get_tutor_in_course_status($userId, $courseId)
332
    {
333
        $userId = intval($userId);
334
        $courseId = intval($courseId);
335
        $result = Database::fetch_array(
336
            Database::query(
337
                "SELECT is_tutor
338
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
339
                WHERE
340
                    c_id = $courseId AND
341
                    user_id = $userId"
342
            )
343
        );
344
345
        return $result['is_tutor'];
346
    }
347
348
    /**
349
     * Unsubscribe one or more users from a course.
350
     *
351
     * @param   mixed   user_id or an array with user ids
352
     * @param   string  course code
353
     * @param   int     session id
354
     *
355
     * @return bool
356
     *
357
     * @assert ('', '') === false
358
     */
359
    public static function unsubscribe_user($user_id, $course_code, $session_id = 0)
360
    {
361
        if (empty($user_id)) {
362
            return false;
363
        }
364
        if (!is_array($user_id)) {
365
            $user_id = [$user_id];
366
        }
367
368
        if (0 == count($user_id)) {
369
            return false;
370
        }
371
372
        if (!empty($session_id)) {
373
            $session_id = (int) $session_id;
374
        } else {
375
            $session_id = api_get_session_id();
376
        }
377
378
        if (empty($course_code)) {
379
            return false;
380
        }
381
382
        $userList = [];
383
        // Cleaning the $user_id variable
384
        if (is_array($user_id)) {
385
            $new_user_id_list = [];
386
            foreach ($user_id as $my_user_id) {
387
                $new_user_id_list[] = (int) $my_user_id;
388
            }
389
            $new_user_id_list = array_filter($new_user_id_list);
390
            $userList = $new_user_id_list;
391
            $user_ids = implode(',', $new_user_id_list);
392
        } else {
393
            $user_ids = (int) $user_id;
394
            $userList[] = $user_id;
395
        }
396
397
        $course_info = api_get_course_info($course_code);
398
        $course_id = $course_info['real_id'];
399
400
        // Unsubscribe user from all groups in the course.
401
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_GROUP_USER)."
402
                WHERE c_id = $course_id AND user_id IN (".$user_ids.")";
403
        Database::query($sql);
404
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_GROUP_TUTOR)."
405
                WHERE c_id = $course_id AND user_id IN (".$user_ids.")";
406
        Database::query($sql);
407
408
        // Erase user student publications (works) in the course - by André Boivin
409
        // @todo this should be handled by doctrine.
410
        /*if (!empty($userList)) {
411
            foreach ($userList as $userId) {
412
                // Getting all work from user
413
                $workList = getWorkPerUser($userId);
414
                if (!empty($workList)) {
415
                    foreach ($workList as $work) {
416
                        $work = $work['work'];
417
                        // Getting user results
418
                        if (!empty($work->user_results)) {
419
                            foreach ($work->user_results as $workSent) {
420
                                deleteWorkItem($workSent['id'], $course_info);
421
                            }
422
                        }
423
                    }
424
                }
425
            }
426
        }*/
427
428
        // Unsubscribe user from all blogs in the course.
429
        /*$sql = "DELETE FROM ".Database::get_course_table(TABLE_BLOGS_REL_USER)."
430
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
431
        Database::query($sql);
432
433
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_BLOGS_TASKS_REL_USER)."
434
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
435
        Database::query($sql);*/
436
437
        // Deleting users in forum_notification and mailqueue course tables
438
        $sql = "DELETE FROM  ".Database::get_course_table(TABLE_FORUM_NOTIFICATION)."
439
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
440
        Database::query($sql);
441
442
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_FORUM_MAIL_QUEUE)."
443
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
444
        Database::query($sql);
445
446
        // Unsubscribe user from the course.
447
        if (!empty($session_id)) {
448
            foreach ($userList as $uid) {
449
                SessionManager::unSubscribeUserFromCourseSession($uid, $course_id, $session_id);
450
451
                // check if a user is register in the session with other course
452
                $sql = "SELECT user_id FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)."
453
                        WHERE session_id = $session_id AND user_id = $uid";
454
                $rs = Database::query($sql);
455
456
                if (0 == Database::num_rows($rs)) {
457
                    SessionManager::unsubscribe_user_from_session($uid, $session_id);
458
                }
459
            }
460
461
            Event::addEvent(
462
                LOG_UNSUBSCRIBE_USER_FROM_COURSE,
463
                LOG_COURSE_CODE,
464
                $course_code,
465
                api_get_utc_datetime(),
466
                $user_id,
467
                $course_id,
468
                $session_id
469
            );
470
        } else {
471
            $sql = "DELETE FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
472
                    WHERE
473
                        user_id IN ($user_ids) AND
474
                        relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
475
                        c_id = $course_id";
476
            Database::query($sql);
477
478
            // add event to system log
479
            $user_id = api_get_user_id();
480
481
            Event::addEvent(
482
                LOG_UNSUBSCRIBE_USER_FROM_COURSE,
483
                LOG_COURSE_CODE,
484
                $course_code,
485
                api_get_utc_datetime(),
486
                $user_id,
487
                $course_id
488
            );
489
490
            foreach ($userList as $userId) {
491
                $userInfo = api_get_user_info($userId);
492
                Event::addEvent(
493
                    LOG_UNSUBSCRIBE_USER_FROM_COURSE,
494
                    LOG_USER_OBJECT,
495
                    $userInfo,
496
                    api_get_utc_datetime(),
497
                    $user_id,
498
                    $course_id
499
                );
500
            }
501
        }
502
        if ('true' === api_get_setting('session.catalog_course_subscription_in_user_s_session')) {
503
            // Also unlink the course from the users' currently accessible sessions
504
            /** @var Course $course */
505
            $course = Container::getCourseRepository()->findOneBy([
506
                'code' => $course_code,
507
            ]);
508
            if (is_null($course)) {
509
                return false;
510
            }
511
            /** @var Chamilo\CoreBundle\Entity\User $user */
512
            foreach (UserManager::getRepository()->matching(
513
                Criteria::create()->where(Criteria::expr()->in('id', $userList))
514
            ) as $user) {
515
                foreach ($user->getCurrentlyAccessibleSessions() as $session) {
516
                    $session->removeCourse($course);
517
                    // unsubscribe user from course within this session
518
                    SessionManager::unSubscribeUserFromCourseSession($user->getId(), $course->getId(), $session->getId());
519
                }
520
            }
521
            try {
522
                Database::getManager()->flush();
523
            } catch (\Doctrine\ORM\OptimisticLockException $exception) {
524
                Display::addFlash(
525
                    Display::return_message(
526
                        get_lang('InternalDatabaseError').': '.$exception->getMessage(),
527
                        'warning'
528
                    )
529
                );
530
531
                return false;
532
            }
533
        }
534
535
        return true;
536
    }
537
538
    /**
539
     * @param string $courseCode
540
     * @param int    $status
541
     *
542
     * @return bool
543
     */
544
    public static function autoSubscribeToCourse($courseCode, $status = STUDENT)
545
    {
546
        if (api_is_anonymous()) {
547
            return false;
548
        }
549
550
        $course = Container::getCourseRepository()->findOneBy(['code' => $courseCode]);
551
552
        if (null === $course) {
553
            return false;
554
        }
555
556
        $visibility = (int) $course->getVisibility();
557
558
        if (in_array($visibility, [
559
                Course::CLOSED,
560
                //Course::REGISTERED,
561
                Course::HIDDEN,
562
        ])) {
563
            Display::addFlash(
564
                Display::return_message(
565
                    get_lang('SubscribingNotAllowed'),
566
                    'warning'
567
        )
568
            );
569
570
            return false;
571
        }
572
573
        // Private course can allow auto subscription
574
        if (Course::REGISTERED === $visibility && false === $course->getSubscribe()) {
575
            Display::addFlash(
576
                Display::return_message(
577
                    get_lang('Subscribing not allowed'),
578
                    'warning'
579
                )
580
            );
581
582
            return false;
583
        }
584
585
        $userId = api_get_user_id();
586
587
        if ('true' === api_get_setting('session.catalog_course_subscription_in_user_s_session')) {
588
            $user = api_get_user_entity($userId);
589
            $sessions = $user->getCurrentlyAccessibleSessions();
590
            if (empty($sessions)) {
591
                // user has no accessible session
592
                if ($user->getSessionsAsStudent()) {
593
                    // user has ancient or future student session(s) but not available now
594
                    Display::addFlash(
595
                        Display::return_message(
596
                            get_lang('CanNotSubscribeToCourseUserSessionExpired'),
597
                            'warning'
598
                        )
599
                    );
600
601
                    return false;
602
                }
603
                // user has no session at all, create one starting now
604
                $numberOfDays = (int) api_get_setting('session.user_s_session_duration');
605
                try {
606
                    $duration = new DateInterval(sprintf('P%dD', $numberOfDays));
607
                } catch (Exception $exception) {
608
                    Display::addFlash(
609
                        Display::return_message(
610
                            get_lang('WrongNumberOfDays').': '.$numberOfDays.': '.$exception->getMessage(),
611
                            'warning'
612
                        )
613
                    );
614
615
                    return false;
616
                }
617
                $endDate = new DateTime();
618
                $endDate->add($duration);
619
                $session = new SessionEntity();
620
                $session->setTitle(
621
                    sprintf(get_lang('FirstnameLastnameCourses'), $user->getFirstname(), $user->getLastname())
622
                );
623
                $session->setAccessEndDate($endDate);
624
                $session->setCoachAccessEndDate($endDate);
625
                $session->setDisplayEndDate($endDate);
626
                $session->setSendSubscriptionNotification(false);
627
                $adminId = (int) api_get_setting('session.session_automatic_creation_user_id');
628
                $session->addSessionAdmin(api_get_user_entity($adminId));
629
                $session->addUserInSession(0, $user);
630
                Database::getManager()->persist($session);
631
                try {
632
                    Database::getManager()->flush();
633
                } catch (\Doctrine\ORM\OptimisticLockException $exception) {
634
                    Display::addFlash(
635
                        Display::return_message(
636
                            get_lang('InternalDatabaseError').': '.$exception->getMessage(),
637
                            'warning'
638
                        )
639
                    );
640
641
                    return false;
642
                }
643
                $accessUrlRelSession = new AccessUrlRelSession();
644
                $accessUrlRelSession->setUrl(api_get_url_entity());
645
                $accessUrlRelSession->setSession($session);
646
                Database::getManager()->persist($accessUrlRelSession);
647
                try {
648
                    Database::getManager()->flush();
649
                } catch (\Doctrine\ORM\OptimisticLockException $exception) {
650
                    Display::addFlash(
651
                        Display::return_message(
652
                            get_lang('InternalDatabaseError').': '.$exception->getMessage(),
653
                            'warning'
654
                        )
655
                    );
656
657
                    return false;
658
                }
659
            } else {
660
                // user has at least one accessible session, let's use it
661
                $session = $sessions[0];
662
            }
663
            // add chosen course to the user session
664
            $session->addCourse($course);
665
            Database::getManager()->persist($session);
666
            try {
667
                Database::getManager()->flush();
668
            } catch (\Doctrine\ORM\OptimisticLockException $exception) {
669
                Display::addFlash(
670
                    Display::return_message(
671
                        get_lang('InternalDatabaseError').': '.$exception->getMessage(),
672
                        'warning'
673
                    )
674
                );
675
676
                return false;
677
            }
678
            // subscribe user to course within this session
679
            SessionManager::subscribe_users_to_session_course([$userId], $session->getId(), $course->getCode());
680
681
            return true;
682
        }
683
684
        return self::subscribeUser($userId, $course->getId(), $status, 0);
685
    }
686
687
    /**
688
     * Subscribe a user to a course. No checks are performed here to see if
689
     * course subscription is allowed.
690
     *
691
     * @param int  $userId
692
     * @param int  $courseId
693
     * @param int  $status                 (STUDENT, COURSEMANAGER, COURSE_ADMIN, NORMAL_COURSE_MEMBER)
694
     * @param int  $sessionId
695
     * @param int  $userCourseCategoryId
696
     * @param bool $checkTeacherPermission
697
     *
698
     * @return bool True on success, false on failure
699
     *
700
     * @assert ('', '') === false
701
     */
702
    public static function subscribeUser(
703
        $userId,
704
        $courseId,
705
        $status = STUDENT,
706
        $sessionId = 0,
707
        $userCourseCategoryId = 0,
708
        $checkTeacherPermission = true
709
    ) {
710
        $userId = (int) $userId;
711
        $status = (int) $status;
712
713
        if (empty($userId) || empty($courseId)) {
714
            return false;
715
        }
716
717
        $course = api_get_course_entity($courseId);
718
719
        if (null === $course) {
720
            Display::addFlash(Display::return_message(get_lang('This course doesn\'t exist'), 'warning'));
721
722
            return false;
723
        }
724
725
        $user = api_get_user_entity($userId);
726
727
        if (null === $user) {
728
            Display::addFlash(Display::return_message(get_lang('This user doesn\'t exist'), 'warning'));
729
730
            return false;
731
        }
732
733
        $courseCode = $course->getCode();
734
        $userCourseCategoryId = (int) $userCourseCategoryId;
735
        $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
736
        $status = STUDENT === $status || COURSEMANAGER === $status ? $status : STUDENT;
737
738
        if (!empty($sessionId)) {
739
            SessionManager::subscribe_users_to_session_course(
740
                [$userId],
741
                $sessionId,
742
                $courseCode
743
            );
744
745
            return true;
746
        } else {
747
            // Check whether the user has not been already subscribed to the course.
748
            $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
749
                    WHERE
750
                        user_id = $userId AND
751
                        relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
752
                        c_id = $courseId
753
                    ";
754
            if (Database::num_rows(Database::query($sql)) > 0) {
755
                Display::addFlash(Display::return_message(get_lang('Already registered in course'), 'warning'));
756
757
                return false;
758
            }
759
760
            if ($checkTeacherPermission && !api_is_course_admin()) {
761
                // Check in advance whether subscription is allowed or not for this course.
762
                if (SUBSCRIBE_NOT_ALLOWED === (int) $course->getSubscribe()) {
763
                    Display::addFlash(Display::return_message(get_lang('Subscription not allowed'), 'warning'));
764
765
                    return false;
766
                }
767
            }
768
769
            if (STUDENT === $status) {
770
                // Check if max students per course extra field is set
771
                $extraFieldValue = new ExtraFieldValue('course');
772
                $value = $extraFieldValue->get_values_by_handler_and_field_variable(
773
                    $courseId,
774
                    'max_subscribed_students'
775
                );
776
                if (!empty($value) && isset($value['value']) && '' !== $value['value']) {
777
                    $maxStudents = (int) $value['value'];
778
                    $count = self::get_user_list_from_course_code(
779
                        $courseCode,
780
                        0,
781
                        null,
782
                        null,
783
                        STUDENT,
784
                        true,
785
                        false
786
                    );
787
788
                    if ($count >= $maxStudents) {
789
                        Display::addFlash(
790
                            Display::return_message(
791
                                get_lang(
792
                                    'The maximum number of student has already been reached, it is not possible to subscribe more student.'
793
                                ),
794
                                'warning'
795
                            )
796
                        );
797
798
                        return false;
799
                    }
800
                }
801
            }
802
803
            $maxSort = api_max_sort_value(0, $userId) + 1;
804
805
            $insertId = self::insertUserInCourse(
806
                $user,
807
                $course,
808
                ['status' => $status, 'sort' => $maxSort, 'user_course_cat' => $userCourseCategoryId]
809
            );
810
811
            if ($insertId) {
812
                Display::addFlash(
813
                    Display::return_message(
814
                        sprintf(
815
                            get_lang('User %s has been registered to course %s'),
816
                            UserManager::formatUserFullName($user, true),
817
                            $course->getTitle()
818
                        )
819
                    )
820
                );
821
822
                $send = (int) api_get_course_setting('email_alert_to_teacher_on_new_user_in_course', $course);
823
824
                if (1 === $send) {
825
                    self::email_to_tutor(
826
                        $userId,
827
                        $courseId,
828
                        false
829
                    );
830
                } elseif (2 === $send) {
831
                    self::email_to_tutor(
832
                        $userId,
833
                        $courseId,
834
                        true
835
                    );
836
                }
837
838
                $subscribe = (int) api_get_course_setting('subscribe_users_to_forum_notifications', $course);
839
                if (1 === $subscribe) {
840
                    /*$forums = get_forums(0,  true, $sessionId);
841
                    foreach ($forums as $forum) {
842
                        set_notification('forum', $forum->getIid(), false, $userInfo, $courseInfo);
843
                    }*/
844
                }
845
846
                return true;
847
            }
848
849
            return false;
850
        }
851
    }
852
853
    /**
854
     * Get the course id based on the original id and field name in the
855
     * extra fields. Returns 0 if course was not found.
856
     *
857
     * @param string $original_course_id_value
858
     * @param string $original_course_id_name
859
     *
860
     * @return int Course id
861
     *
862
     * @assert ('', '') === false
863
     */
864
    public static function get_course_code_from_original_id(
865
        $original_course_id_value,
866
        $original_course_id_name
867
    ) {
868
        $t_cfv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
869
        $table_field = Database::get_main_table(TABLE_EXTRA_FIELD);
870
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
871
        $original_course_id_value = Database::escape_string($original_course_id_value);
872
        $original_course_id_name = Database::escape_string($original_course_id_name);
873
874
        $sql = "SELECT item_id
875
                FROM $table_field cf
876
                INNER JOIN $t_cfv cfv
877
                ON cfv.field_id=cf.id
878
                WHERE
879
                    variable = '$original_course_id_name' AND
880
                    value = '$original_course_id_value' AND
881
                    cf.item_type = $extraFieldType
882
                ";
883
        $res = Database::query($sql);
884
        $row = Database::fetch_object($res);
885
        if ($row) {
886
            return $row->item_id;
887
        } else {
888
            return 0;
889
        }
890
    }
891
892
    /**
893
     * Gets the course code from the course id. Returns null if course id was not found.
894
     *
895
     * @param int $id Course id
896
     *
897
     * @return string Course code
898
     * @assert ('') === false
899
     */
900
    public static function get_course_code_from_course_id($id)
901
    {
902
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
903
        $id = intval($id);
904
        $sql = "SELECT code FROM $table WHERE id = $id ";
905
        $res = Database::query($sql);
906
        $row = Database::fetch_object($res);
907
        if ($row) {
908
            return $row->code;
909
        } else {
910
            return null;
911
        }
912
    }
913
914
    /**
915
     * Add the user $userId visibility to the course $courseCode in the catalogue.
916
     *
917
     * @author David Nos (https://github.com/dnos)
918
     *
919
     * @param int    $userId     the id of the user
920
     * @param string $courseCode the course code
921
     * @param int    $visible    (optional) The course visibility in the catalogue to the user (1=visible, 0=invisible)
922
     *
923
     * @return bool true if added succesfully, false otherwise
924
     */
925
    public static function addUserVisibilityToCourseInCatalogue(
926
        $userId,
927
        $courseCode,
928
        $visible = 1
929
    ) {
930
        $debug = false;
931
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
932
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
933
        $visible = (int) $visible;
934
        if (empty($userId) || empty($courseCode) || ($userId != strval(intval($userId)))) {
935
            return false;
936
        }
937
938
        $courseCode = Database::escape_string($courseCode);
939
        $courseInfo = api_get_course_info($courseCode);
940
        $courseId = $courseInfo['real_id'];
941
942
        // Check in advance whether the user has already been registered on the platform.
943
        $sql = "SELECT status FROM ".$userTable." WHERE user_id = $userId ";
944
        if (0 == Database::num_rows(Database::query($sql))) {
945
            return false; // The user has not been registered to the platform.
946
        }
947
948
        // Check whether the user has already been registered to the course visibility in the catalogue.
949
        $sql = "SELECT * FROM $courseUserTable
950
                WHERE
951
                    user_id = $userId AND
952
                    visible = $visible AND
953
                    c_id = $courseId";
954
        if (Database::num_rows(Database::query($sql)) > 0) {
955
            return true; // The visibility of the user to the course in the catalogue does already exist.
956
        }
957
958
        // Register the user visibility to course in catalogue.
959
        $params = [
960
            'user_id' => $userId,
961
            'c_id' => $courseId,
962
            'visible' => $visible,
963
        ];
964
965
        return Database::insert($courseUserTable, $params);
966
    }
967
968
    /**
969
     * Remove the user $userId visibility to the course $courseCode in the catalogue.
970
     *
971
     * @author David Nos (https://github.com/dnos)
972
     *
973
     * @param int    $userId     the id of the user
974
     * @param string $courseCode the course code
975
     * @param int    $visible    (optional) The course visibility in the catalogue to the user (1=visible, 0=invisible)
976
     *
977
     * @return bool true if removed succesfully or register not found, false otherwise
978
     */
979
    public static function removeUserVisibilityToCourseInCatalogue(
980
        $userId,
981
        $courseCode,
982
        $visible = 1
983
    ) {
984
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
985
986
        if (empty($userId) || empty($courseCode) || ($userId != strval(intval($userId)))) {
987
            return false;
988
        }
989
990
        $courseCode = Database::escape_string($courseCode);
991
        $courseInfo = api_get_course_info($courseCode);
992
        $courseId = $courseInfo['real_id'];
993
994
        // Check whether the user has already been registered to the course visibility in the catalogue.
995
        $sql = "SELECT * FROM $courseUserTable
996
                WHERE
997
                    user_id = $userId AND
998
                    visible = $visible AND
999
                    c_id = $courseId";
1000
        if (Database::num_rows(Database::query($sql)) > 0) {
1001
            $cond = [
1002
                'user_id = ? AND c_id = ? AND visible = ? ' => [
1003
                    $userId,
1004
                    $courseId,
1005
                    $visible,
1006
                ],
1007
            ];
1008
1009
            return Database::delete($courseUserTable, $cond);
1010
        } else {
1011
            return true; // Register does not exist
1012
        }
1013
    }
1014
1015
    /**
1016
     * @param string $code
1017
     *
1018
     * @return bool if there already are one or more courses
1019
     *              with the same code OR visual_code (visualcode), false otherwise
1020
     */
1021
    public static function course_code_exists($code)
1022
    {
1023
        $code = Database::escape_string($code);
1024
        $sql = "SELECT COUNT(*) as number
1025
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
1026
                WHERE code = '$code' OR visual_code = '$code'";
1027
        $result = Database::fetch_array(Database::query($sql));
1028
1029
        return $result['number'] > 0;
1030
    }
1031
1032
    /**
1033
     * @param int    $userId
1034
     * @param string $keyword
1035
     *
1036
     * @return array an array with the course info of all the courses (real and virtual)
1037
     *               of which the current user is course admin
1038
     */
1039
    public static function get_course_list_of_user_as_course_admin($userId, $keyword = ''): array
1040
    {
1041
        $user = api_get_user_entity($userId);
1042
1043
        if (null === $user) {
1044
            return [];
1045
        }
1046
1047
        $url = api_get_url_entity();
1048
        $repo = Container::getCourseRepository();
1049
1050
        return $repo->getCoursesInfoByUser($user, $url, COURSEMANAGER, $keyword);
1051
    }
1052
1053
    /**
1054
     * @param int   $userId
1055
     * @param array $courseInfo
1056
     *
1057
     * @return bool|null
1058
     */
1059
    public static function isUserSubscribedInCourseAsDrh($userId, $courseInfo)
1060
    {
1061
        $userId = intval($userId);
1062
1063
        if (!api_is_drh()) {
1064
            return false;
1065
        }
1066
1067
        if (empty($courseInfo) || empty($userId)) {
1068
            return false;
1069
        }
1070
1071
        $courseId = intval($courseInfo['real_id']);
1072
        $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1073
1074
        $sql = "SELECT * FROM $table
1075
                WHERE
1076
                    user_id = $userId AND
1077
                    relation_type = ".COURSE_RELATION_TYPE_RRHH." AND
1078
                    c_id = $courseId";
1079
1080
        $result = Database::fetch_array(Database::query($sql));
1081
1082
        if (!empty($result)) {
1083
            // The user has been registered in this course.
1084
            return true;
1085
        }
1086
    }
1087
1088
    /**
1089
     * Check if user is subscribed inside a course.
1090
     *
1091
     * @param int    $userId
1092
     * @param string $course_code  , if this parameter is null, it'll check for all courses
1093
     * @param bool   $in_a_session True for checking inside sessions too, by default is not checked
1094
     * @param int    $session_id
1095
     *
1096
     * @return bool $session_id true if the user is registered in the course, false otherwise
1097
     */
1098
    public static function is_user_subscribed_in_course(
1099
        $userId,
1100
        $course_code = null,
1101
        $in_a_session = false,
1102
        $session_id = 0
1103
    ) {
1104
        $userId = (int) $userId;
1105
        $session_id = (int) $session_id;
1106
1107
        if ('true' === api_get_setting('session.catalog_course_subscription_in_user_s_session')) {
1108
            // with this option activated, only check whether the course is in one of the users' sessions
1109
            $course = Container::getCourseRepository()->findOneBy([
1110
                'code' => $course_code,
1111
            ]);
1112
            if (is_null($course)) {
1113
                return false;
1114
            }
1115
1116
            $user = api_get_user_entity($userId);
1117
            if (is_null($user)) {
1118
                return false;
1119
            }
1120
            foreach ($user->getSessionsAsStudent() as $session) {
1121
                if ($session->hasCourse($course)) {
1122
                    return true;
1123
                }
1124
            }
1125
1126
            return false;
1127
        }
1128
1129
        if (empty($session_id)) {
1130
            $session_id = api_get_session_id();
1131
        }
1132
1133
        $condition_course = '';
1134
        if (isset($course_code)) {
1135
            $courseInfo = api_get_course_info($course_code);
1136
            if (empty($courseInfo)) {
1137
                return false;
1138
            }
1139
            $courseId = $courseInfo['real_id'];
1140
            $condition_course = " AND c_id = $courseId";
1141
        }
1142
1143
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
1144
                WHERE
1145
                    user_id = $userId AND
1146
                    relation_type<>".COURSE_RELATION_TYPE_RRHH."
1147
                    $condition_course ";
1148
1149
        $result = Database::fetch_array(Database::query($sql));
1150
1151
        if (!empty($result)) {
1152
            // The user has been registered in this course.
1153
            return true;
1154
        }
1155
1156
        if (!$in_a_session) {
1157
            // The user has not been registered in this course.
1158
            return false;
1159
        }
1160
1161
        $tableSessionCourseUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1162
        $sql = "SELECT 1 FROM $tableSessionCourseUser
1163
                WHERE user_id = $userId AND session_id = $session_id $condition_course";
1164
1165
        if (Database::num_rows(Database::query($sql)) > 0) {
1166
            return true;
1167
        }
1168
1169
        $sql = "SELECT 1 FROM $tableSessionCourseUser
1170
                WHERE user_id = $userId AND session_id = $session_id AND status = ".SessionEntity::COURSE_COACH." $condition_course";
1171
1172
        if (Database::num_rows(Database::query($sql)) > 0) {
1173
            return true;
1174
        }
1175
1176
        $sql = "SELECT s.id FROM ".Database::get_main_table(TABLE_MAIN_SESSION)." s
1177
                INNER JOIN ".Database::get_main_table(TABLE_MAIN_SESSION_USER)." sru
1178
                ON (sru.session_id = s.id AND sru.relation_type = ".SessionEntity::GENERAL_COACH.")
1179
                WHERE sru.user_id = $userId AND s.id = $session_id";
1180
1181
        if (Database::num_rows(Database::query($sql)) > 0) {
1182
            return true;
1183
        }
1184
1185
        return false;
1186
    }
1187
1188
    /**
1189
     * Is the user a teacher in the given course?
1190
     *
1191
     * @param int $userId
1192
     * @param int $courseId
1193
     *
1194
     * @return bool if the user is a teacher in the course, false otherwise
1195
     */
1196
    public static function isCourseTeacher($userId, $courseId)
1197
    {
1198
        $userId = (int) $userId;
1199
        $courseId = (int) $courseId;
1200
1201
        if (empty($courseId) || empty($userId)) {
1202
            return false;
1203
        }
1204
1205
        $sql = "SELECT status FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
1206
                WHERE c_id = $courseId AND user_id = $userId ";
1207
        $result = Database::query($sql);
1208
1209
        if (Database::num_rows($result) > 0) {
1210
            return 1 == Database::result($result, 0, 'status');
1211
        }
1212
1213
        return false;
1214
    }
1215
1216
    /**
1217
     * Get user info array of all users registered in a course, by course code.
1218
     * Wrapper: This method calls getUserListFromCourseId() in the background.
1219
     * @param string|null $courseCode Cours code is allowed to be null if we want all users
1220
     * @param int         $sessionId
1221
     * @param string      $limit
1222
     * @param string      $order_by the field to order the users by.
1223
     *                                    Valid values are 'lastname', 'firstname', 'username', 'email',
1224
     *                                    'official_code' OR a part of a SQL statement that starts with ORDER BY ...
1225
     * @param int|null    $filter_by_status if using the session_id: 0 or 2 (student, coach),
1226
     *                                    if using session_id = 0 STUDENT or COURSEMANAGER
1227
     * @param bool|null   $return_count
1228
     * @param bool        $add_reports
1229
     * @param bool        $resumed_report
1230
     * @param array       $extra_field
1231
     * @param array       $courseCodeList
1232
     * @param array       $userIdList
1233
     * @param bool        $filterByActive
1234
     * @param array       $sessionIdList
1235
     * @param string      $searchByKeyword
1236
     *
1237
     * @return array|int
1238
     * @throws Exception
1239
     */
1240
    public static function get_user_list_from_course_code(
1241
        $courseCode,
1242
        $sessionId = 0,
1243
        $limit = null,
1244
        $order_by = null,
1245
        $filter_by_status = null,
1246
        $return_count = null,
1247
        $add_reports = false,
1248
        $resumed_report = false,
1249
        $extra_field = [],
1250
        $courseCodeList = [],
1251
        $userIdList = [],
1252
        $filterByActive = null,
1253
        $sessionIdList = [],
1254
        $searchByKeyword = '',
1255
        $options = []
1256
    )
1257
    {
1258
        $courseId = api_get_course_int_id($courseCode);
1259
        return self::getUserListFromCourseId(
1260
            $courseId,
1261
            $sessionId,
1262
            $limit,
1263
            $order_by,
1264
            $filter_by_status,
1265
            $return_count,
1266
            $add_reports,
1267
            $resumed_report,
1268
            $extra_field,
1269
            $courseCodeList,
1270
            $userIdList,
1271
            $filterByActive,
1272
            $sessionIdList,
1273
            $searchByKeyword,
1274
            $options
1275
        );
1276
    }
1277
1278
    /**
1279
     * Return user info array of all users registered in a course (by course ID and session ID).
1280
     * This only returns the users that are registered in this actual course, not linked courses.
1281
     *
1282
     * @param ?int    $courseCode Course ID is allowed to be null if we want all users
1283
     * @param ?int    $sessionId
1284
     * @param ?string $limit
1285
     * @param ?string $order_by the field to order the users by.
1286
     *                                    Valid values are 'lastname', 'firstname', 'username', 'email',
1287
     *                                    'official_code' OR a part of a SQL statement that starts with ORDER BY ...
1288
     * @param ?int    $filter_by_status if using the session_id: 0 or 2 (student, coach),
1289
     *                                    if using session_id = 0 STUDENT or COURSEMANAGER
1290
     * @param ?bool   $return_count
1291
     * @param ?bool   $add_reports
1292
     * @param ?bool   $resumed_report
1293
     * @param ?array  $extra_field
1294
     * @param ?array  $courseCodeList
1295
     * @param ?array  $userIdList
1296
     * @param ?bool   $filterByActive
1297
     * @param ?array  $sessionIdList
1298
     * @param ?string $searchByKeyword
1299
     * @param ?array
1300
     *
1301
     * @return array|int
1302
     * @throws Exception
1303
     */
1304
    public static function getUserListFromCourseId(
1305
        ?int $courseId = null,
1306
        ?int $sessionId = 0,
1307
        ?string $limit = null,
1308
        ?string $order_by = null,
1309
        ?int $filter_by_status = null,
1310
        ?bool $return_count = null,
1311
        ?bool $add_reports = false,
1312
        ?bool $resumed_report = false,
1313
        ?array $extra_field = [],
1314
        ?array $courseIdsList = [],
1315
        ?array $userIdList = [],
1316
        ?bool $filterByActive = null,
1317
        ?array $sessionIdList = [],
1318
        ?string $searchByKeyword = '',
1319
        ?array $options = []
1320
    ) {
1321
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
1322
        $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
1323
1324
        $sessionId = (int) $sessionId;
1325
        $session = null;
1326
        if (!empty($sessionId)) {
1327
            $session = api_get_session_entity($sessionId);
1328
        }
1329
        $where = [];
1330
        if (empty($order_by)) {
1331
            $order_by = 'user.lastname, user.firstname';
1332
            if (api_is_western_name_order()) {
1333
                $order_by = 'user.firstname, user.lastname';
1334
            }
1335
        }
1336
1337
        // if the $order_by does not contain 'ORDER BY'
1338
        // we have to check if it is a valid field that can be sorted on
1339
        if (!strstr($order_by, 'ORDER BY')) {
1340
            if (!empty($order_by)) {
1341
                $order_by = "ORDER BY $order_by";
1342
            } else {
1343
                $order_by = '';
1344
            }
1345
        }
1346
1347
        $filter_by_status_condition = null;
1348
        $whereExtraField = '';
1349
        $injectExtraFields = ' , ';
1350
        $sqlInjectJoins = '';
1351
        if (!empty($options)) {
1352
            $extraFieldModel = new ExtraField('user');
1353
            $conditions = $extraFieldModel->parseConditions($options, 'user');
1354
            if (!empty($conditions)) {
1355
                $injectExtraFields = $conditions['inject_extra_fields'];
1356
1357
                if (!empty($injectExtraFields)) {
1358
                    $injectExtraFields = ', '.$injectExtraFields;
1359
                } else {
1360
                    $injectExtraFields = ' , ';
1361
                }
1362
                $sqlInjectJoins = $conditions['inject_joins'];
1363
                $whereExtraField = $conditions['where'];
1364
            }
1365
        }
1366
1367
        if (!empty($sessionId) || !empty($sessionIdList)) {
1368
            $sql = 'SELECT DISTINCT
1369
                        user.id as user_id,
1370
                        user.email,
1371
                        session_course_user.status as status_session,
1372
                        session_id,
1373
                        user.*,
1374
                        course.*,
1375
                        course.id AS c_id
1376
                         '.$injectExtraFields.'
1377
                        session.title as session_name
1378
                    ';
1379
            if ($return_count) {
1380
                $sql = ' SELECT COUNT(user.id) as count';
1381
            }
1382
1383
            $sessionCondition = " session_course_user.session_id = $sessionId";
1384
            if (!empty($sessionIdList)) {
1385
                $sessionIdListToString = implode("','", array_map('intval', $sessionIdList));
1386
                $sessionCondition = " session_course_user.session_id IN ('$sessionIdListToString') ";
1387
            }
1388
1389
            $courseCondition = " course.id IS NOT NULL ";
1390
            if (!empty($courseId)) {
1391
                $courseCondition = " course.id = $courseId";
1392
            }
1393
            if (!empty($courseCodeList)) {
1394
                $courseCodeListForSession = array_map(['Database', 'escape_string'], $courseCodeList);
1395
                $courseCodeListForSession = implode("','", $courseCodeListForSession);
1396
                $courseCondition = " course.code IN ('$courseCodeListForSession')  ";
1397
            }
1398
1399
            $sql .= ' FROM '.Database::get_main_table(TABLE_MAIN_USER).' as user ';
1400
            $sql .= " LEFT JOIN ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." as session_course_user
1401
                      ON
1402
                        user.id = session_course_user.user_id AND
1403
                        $sessionCondition
1404
                        INNER JOIN $course_table course
1405
                        ON session_course_user.c_id = course.id AND
1406
                        $courseCondition
1407
                        INNER JOIN $sessionTable session
1408
                        ON session_course_user.session_id = session.id
1409
                    $sqlInjectJoins
1410
                   ";
1411
            $where[] = ' session_course_user.c_id IS NOT NULL ';
1412
1413
            // 2 = coach
1414
            // 0 = student
1415
            if (isset($filter_by_status)) {
1416
                $filter_by_status_condition = " session_course_user.status = $filter_by_status AND ";
1417
            }
1418
        } else {
1419
            if ($return_count) {
1420
                $sql = " SELECT COUNT(*) as count";
1421
            } else {
1422
                if (empty($courseCode)) {
1423
                    $sql = 'SELECT DISTINCT
1424
                                course.title,
1425
                                course.code,
1426
                                course.id AS c_id,
1427
                                course_rel_user.status as status_rel,
1428
                                user.id as user_id,
1429
                                user.email,
1430
                                course_rel_user.is_tutor
1431
                                '.$injectExtraFields.'
1432
                                user.*  ';
1433
                } else {
1434
                    $sql = 'SELECT DISTINCT
1435
                                course_rel_user.status as status_rel,
1436
                                user.id as user_id,
1437
                                user.email,
1438
                                course_rel_user.is_tutor
1439
                                '.$injectExtraFields.'
1440
                                user.*  ';
1441
                }
1442
            }
1443
1444
            $sql .= " FROM ".Database::get_main_table(TABLE_MAIN_USER)." as user
1445
                      LEFT JOIN ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." as course_rel_user
1446
                      ON
1447
                        user.id = course_rel_user.user_id AND
1448
                        course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
1449
                       INNER JOIN $course_table course
1450
                       ON (course_rel_user.c_id = course.id)
1451
                       $sqlInjectJoins
1452
                       ";
1453
1454
            if (!empty($courseId)) {
1455
                $sql .= " AND course_rel_user.c_id = $courseId";
1456
            }
1457
            $where[] = ' course_rel_user.c_id IS NOT NULL ';
1458
1459
            if (isset($filter_by_status)) {
1460
                $filter_by_status_condition = " course_rel_user.status = $filter_by_status AND ";
1461
            }
1462
        }
1463
1464
        $multiple_access_url = api_get_multiple_access_url();
1465
        if ($multiple_access_url) {
1466
            $sql .= ' LEFT JOIN '.Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER).' au
1467
                      ON (au.user_id = user.id) ';
1468
        }
1469
1470
        $extraFieldWasAdded = false;
1471
        if ($return_count && $resumed_report) {
1472
            foreach ($extra_field as $extraField) {
1473
                $extraFieldInfo = UserManager::get_extra_field_information_by_name($extraField);
1474
                if (!empty($extraFieldInfo)) {
1475
                    $fieldValuesTable = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1476
                    $sql .= " LEFT JOIN $fieldValuesTable as ufv
1477
                            ON (
1478
                                user.id = ufv.item_id AND
1479
                                (field_id = ".$extraFieldInfo['id']." OR field_id IS NULL)
1480
                            )";
1481
                    $extraFieldWasAdded = true;
1482
                }
1483
            }
1484
        }
1485
1486
        $sql .= " WHERE user.active <> ".USER_SOFT_DELETED." AND
1487
            $filter_by_status_condition
1488
            ".implode(' OR ', $where);
1489
1490
        if ($multiple_access_url) {
1491
            $current_access_url_id = api_get_current_access_url_id();
1492
            $sql .= " AND (access_url_id =  $current_access_url_id ) ";
1493
        }
1494
1495
        if ($return_count && $resumed_report && $extraFieldWasAdded) {
1496
            $sql .= ' AND field_id IS NOT NULL GROUP BY value ';
1497
        }
1498
1499
        if (!empty($courseIdsList)) {
1500
            $courseIdsList = array_map('intval', $courseIdsList);
1501
            $courseIdsList = implode('","', $courseIdsList);
1502
            if (empty($sessionIdList)) {
1503
                $sql .= ' AND course.id IN ("'.$courseIdsList.'")';
1504
            }
1505
        }
1506
1507
        if (!empty($userIdList)) {
1508
            $userIdList = array_map('intval', $userIdList);
1509
            $userIdList = implode('","', $userIdList);
1510
            $sql .= ' AND user.id IN ("'.$userIdList.'")';
1511
        }
1512
1513
        if (isset($filterByActive)) {
1514
            $filterByActive = (int) $filterByActive;
1515
            $sql .= " AND user.active = $filterByActive";
1516
        }
1517
1518
        if (!empty($searchByKeyword)) {
1519
            $searchByKeyword = Database::escape_string($searchByKeyword);
1520
            $sql .= " AND (
1521
                        user.firstname LIKE '$searchByKeyword' OR
1522
                        user.username LIKE '$searchByKeyword' OR
1523
                        user.lastname LIKE '$searchByKeyword'
1524
                    ) ";
1525
        }
1526
1527
        $sql .= $whereExtraField;
1528
        $sql .= " $order_by $limit";
1529
1530
        $rs = Database::query($sql);
1531
        $users = [];
1532
1533
        $extra_fields = UserManager::get_extra_fields(
1534
            0,
1535
            100,
1536
            null,
1537
            null,
1538
            true,
1539
            true
1540
        );
1541
1542
        $counter = 1;
1543
        $count_rows = Database::num_rows($rs);
1544
1545
        if ($return_count && $resumed_report) {
1546
            return $count_rows;
1547
        }
1548
        $table_user_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1549
        $tableExtraField = Database::get_main_table(TABLE_EXTRA_FIELD);
1550
        if ($count_rows) {
1551
            while ($user = Database::fetch_array($rs)) {
1552
                if ($return_count) {
1553
                    return $user['count'];
1554
                }
1555
1556
                $report_info = [];
1557
                $user_info = $user;
1558
                $user_info['status'] = $user['status'];
1559
                if (isset($user['is_tutor'])) {
1560
                    $user_info['is_tutor'] = $user['is_tutor'];
1561
                }
1562
                if (!empty($sessionId)) {
1563
                    $user_info['status_session'] = $user['status_session'];
1564
                }
1565
1566
                $sessionId = $user['session_id'] ?? 0;
1567
                $sessionName = isset($user['session_name']) ? ' ('.$user['session_name'].') ' : '';
1568
1569
                if ($add_reports) {
1570
                    if ($resumed_report) {
1571
                        $extra = [];
1572
                        if (!empty($extra_fields)) {
1573
                            foreach ($extra_fields as $extra) {
1574
                                if (in_array($extra['1'], $extra_field)) {
1575
                                    $user_data = UserManager::get_extra_user_data_by_field(
1576
                                        $user['user_id'],
1577
                                        $extra['1']
1578
                                    );
1579
                                    break;
1580
                                }
1581
                            }
1582
                        }
1583
1584
                        $row_key = '-1';
1585
                        $name = '-';
1586
                        if (!empty($extra)) {
1587
                            if (!empty($user_data[$extra['1']])) {
1588
                                $row_key = $user_data[$extra['1']];
1589
                                $name = $user_data[$extra['1']];
1590
                                $users[$row_key]['extra_'.$extra['1']] = $name;
1591
                            }
1592
                        }
1593
1594
                        if (empty($users[$row_key])) {
1595
                            $users[$row_key] = [];
1596
                        }
1597
1598
                        if (!array_key_exists('training_hours', $users[$row_key])) {
1599
                            $users[$row_key]['training_hours'] = 0;
1600
                        }
1601
1602
                        $users[$row_key]['training_hours'] += Tracking::get_time_spent_on_the_course(
1603
                            $user['user_id'],
1604
                            $user['c_id'],
1605
                            $sessionId
1606
                        );
1607
1608
                        if (!array_key_exists('count_users', $users[$row_key])) {
1609
                            $users[$row_key]['count_users'] = 0;
1610
                        }
1611
1612
                        $users[$row_key]['count_users'] += $counter;
1613
1614
                        $registered_users_with_extra_field = self::getCountRegisteredUsersWithCourseExtraField(
1615
                            $name,
1616
                            $tableExtraField,
1617
                            $table_user_field_value
1618
                        );
1619
1620
                        $users[$row_key]['count_users_registered'] = $registered_users_with_extra_field;
1621
                        $users[$row_key]['average_hours_per_user'] = $users[$row_key]['training_hours'] / $users[$row_key]['count_users'];
1622
1623
                        $category = Category::load(
1624
                            null,
1625
                            null,
1626
                            $user['c_id'],
1627
                            null,
1628
                            null,
1629
                            $sessionId
1630
                        );
1631
1632
                        if (!isset($users[$row_key]['count_certificates'])) {
1633
                            $users[$row_key]['count_certificates'] = 0;
1634
                        }
1635
1636
                        if (isset($category[0]) && $category[0]->is_certificate_available($user['user_id'])) {
1637
                            $users[$row_key]['count_certificates']++;
1638
                        }
1639
1640
                        foreach ($extra_fields as $extra) {
1641
                            if ('ruc' === $extra['1']) {
1642
                                continue;
1643
                            }
1644
1645
                            if (!isset($users[$row_key][$extra['1']])) {
1646
                                $user_data = UserManager::get_extra_user_data_by_field($user['user_id'], $extra['1']);
1647
                                if (!empty($user_data[$extra['1']])) {
1648
                                    $users[$row_key][$extra['1']] = $user_data[$extra['1']];
1649
                                }
1650
                            }
1651
                        }
1652
                    } else {
1653
                        $report_info['course'] = $user['title'].$sessionName;
1654
                        $report_info['user'] = api_get_person_name($user['firstname'], $user['lastname']);
1655
                        $report_info['email'] = $user['email'];
1656
                        $report_info['time'] = api_time_to_hms(
1657
                            Tracking::get_time_spent_on_the_course(
1658
                                $user['user_id'],
1659
                                $user['c_id'],
1660
                                $sessionId
1661
                            )
1662
                        );
1663
1664
                        $category = Category:: load(
1665
                            null,
1666
                            null,
1667
                            $user['c_id'],
1668
                            null,
1669
                            null,
1670
                            $sessionId
1671
                        );
1672
1673
                        $report_info['certificate'] = Display::label(get_lang('No'));
1674
                        if (isset($category[0]) && $category[0]->is_certificate_available($user['user_id'])) {
1675
                            $report_info['certificate'] = Display::label(get_lang('Yes'), 'success');
1676
                        }
1677
                        $course = api_get_course_entity($user['c_id']);
1678
                        $progress = (int) Tracking::get_avg_student_progress(
1679
                            $user['user_id'],
1680
                            $course,
1681
                            [],
1682
                            $session
1683
                        );
1684
1685
                        $report_info['progress_100'] = 100 == $progress ? Display::label(get_lang('Yes'), 'success') : Display::label(get_lang('No'));
1686
                        $report_info['progress'] = $progress."%";
1687
                        foreach ($extra_fields as $extra) {
1688
                            $user_data = UserManager::get_extra_user_data_by_field($user['user_id'], $extra['1']);
1689
                            $report_info[$extra['1']] = $user_data[$extra['1']];
1690
                        }
1691
                        $report_info['user_id'] = $user['user_id'];
1692
                        $users[] = $report_info;
1693
                    }
1694
                } else {
1695
                    $users[$user['user_id']] = $user_info;
1696
                }
1697
            }
1698
        }
1699
1700
        return $users;
1701
    }
1702
1703
    /**
1704
     * @param bool  $resumed_report
1705
     * @param array $extra_field
1706
     * @param array $courseCodeList
1707
     * @param array $userIdList
1708
     * @param array $sessionIdList
1709
     * @param array $options
1710
     *
1711
     * @return array|int
1712
     */
1713
    public static function get_count_user_list_from_course_code(
1714
        $resumed_report = false,
1715
        $extra_field = [],
1716
        $courseCodeList = [],
1717
        $userIdList = [],
1718
        $sessionIdList = [],
1719
        $options = []
1720
    ) {
1721
        return self::get_user_list_from_course_code(
1722
            null,
1723
            0,
1724
            null,
1725
            null,
1726
            null,
1727
            true,
1728
            false,
1729
            $resumed_report,
1730
            $extra_field,
1731
            $courseCodeList,
1732
            $userIdList,
1733
            null,
1734
            $sessionIdList,
1735
            null,
1736
            $options
1737
        );
1738
    }
1739
1740
    /**
1741
     * Gets subscribed users in a course or in a course/session.
1742
     *
1743
     * @param string $course_code
1744
     * @param int    $session_id
1745
     *
1746
     * @return int
1747
     */
1748
    public static function get_users_count_in_course(
1749
        $course_code,
1750
        $session_id = 0,
1751
        $status = null
1752
    ) {
1753
        // variable initialisation
1754
        $session_id = (int) $session_id;
1755
        $course_code = Database::escape_string($course_code);
1756
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
1757
        $tblSessionCourseUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1758
        $tblCourseUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1759
        $tblUrlUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1760
1761
        $courseInfo = api_get_course_info($course_code);
1762
        $courseId = $courseInfo['real_id'];
1763
1764
        $sql = "
1765
            SELECT DISTINCT count(user.id) as count
1766
            FROM $tblUser as user
1767
        ";
1768
        $where = [];
1769
        if (!empty($session_id)) {
1770
            $sql .= "
1771
                LEFT JOIN $tblSessionCourseUser as session_course_user
1772
                ON user.id = session_course_user.user_id
1773
                    AND session_course_user.c_id = $courseId
1774
                    AND session_course_user.session_id = $session_id
1775
            ";
1776
1777
            $where[] = ' session_course_user.c_id IS NOT NULL ';
1778
        } else {
1779
            $sql .= "
1780
                LEFT JOIN $tblCourseUser as course_rel_user
1781
                    ON user.id = course_rel_user.user_id
1782
                    AND course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
1783
                    AND course_rel_user.c_id = $courseId
1784
            ";
1785
            $where[] = ' course_rel_user.c_id IS NOT NULL ';
1786
        }
1787
1788
        $multiple_access_url = api_get_multiple_access_url();
1789
        if ($multiple_access_url) {
1790
            $sql .= " LEFT JOIN $tblUrlUser au ON (au.user_id = user.id) ";
1791
        }
1792
1793
        $sql .= ' WHERE user.active <> '.USER_SOFT_DELETED.' AND '.implode(' OR ', $where);
1794
1795
        if ($multiple_access_url) {
1796
            $current_access_url_id = api_get_current_access_url_id();
1797
            $sql .= " AND (access_url_id =  $current_access_url_id ) ";
1798
        }
1799
        $rs = Database::query($sql);
1800
        $count = 0;
1801
        if (Database::num_rows($rs)) {
1802
            $user = Database::fetch_array($rs);
1803
            $count = $user['count'];
1804
        }
1805
1806
        return $count;
1807
    }
1808
1809
    /**
1810
     * Get a list of coaches of a course and a session.
1811
     *
1812
     * @param string $course_code
1813
     * @param int    $session_id
1814
     * @param bool   $addGeneralCoach
1815
     *
1816
     * @return array List of users
1817
     */
1818
    public static function get_coach_list_from_course_code(
1819
        $course_code,
1820
        $session_id,
1821
        $addGeneralCoach = true
1822
    ) {
1823
        if (empty($course_code) || empty($session_id)) {
1824
            return [];
1825
        }
1826
1827
        $course_code = Database::escape_string($course_code);
1828
        $courseInfo = api_get_course_info($course_code);
1829
        $courseId = $courseInfo['real_id'];
1830
        $session_id = (int) $session_id;
1831
        $users = [];
1832
1833
        // We get the coach for the given course in a given session.
1834
        $sql = 'SELECT user_id FROM '.Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER).
1835
               " WHERE session_id = $session_id AND c_id = $courseId AND status = ".SessionEntity::COURSE_COACH;
1836
        $rs = Database::query($sql);
1837
        while ($user = Database::fetch_array($rs)) {
1838
            $userInfo = api_get_user_info($user['user_id']);
1839
            if ($userInfo) {
1840
                $users[$user['user_id']] = $userInfo;
1841
            }
1842
        }
1843
1844
        if ($addGeneralCoach) {
1845
            $generalCoachesId = SessionManager::getGeneralCoachesIdForSession($session_id);
1846
1847
            foreach ($generalCoachesId as $session_id_coach) {
1848
                $userInfo = api_get_user_info($session_id_coach);
1849
                if ($userInfo) {
1850
                    $users[$session_id_coach] = $userInfo;
1851
                }
1852
            }
1853
        }
1854
1855
        return $users;
1856
    }
1857
1858
    /**
1859
     *  Return user info array of all users registered in a course
1860
     *  This only returns the users that are registered in this actual course, not linked courses.
1861
     *
1862
     * @param string $course_code
1863
     * @param bool   $with_session
1864
     * @param int    $sessionId
1865
     * @param string $date_from
1866
     * @param string $date_to
1867
     * @param bool   $includeInvitedUsers Whether include the invited users
1868
     * @param int    $groupId
1869
     * @param bool   $getCount
1870
     * @param int    $start
1871
     * @param int    $limit
1872
     *
1873
     * @return array with user id
1874
     */
1875
    public static function get_student_list_from_course_code(
1876
        $course_code,
1877
        $with_session = false,
1878
        $sessionId = 0,
1879
        $date_from = null,
1880
        $date_to = null,
1881
        $includeInvitedUsers = true,
1882
        $groupId = 0,
1883
        $getCount = false,
1884
        $start = 0,
1885
        $limit = 0
1886
    ) {
1887
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1888
        $sessionId = (int) $sessionId;
1889
        $courseInfo = api_get_course_info($course_code);
1890
        if (empty($courseInfo)) {
1891
            return [];
1892
        }
1893
        $courseId = $courseInfo['real_id'];
1894
        $students = [];
1895
1896
        $limitCondition = '';
1897
        if (isset($start) && isset($limit) && !empty($limit)) {
1898
            $start = (int) $start;
1899
            $limit = (int) $limit;
1900
            $limitCondition = " LIMIT $start, $limit";
1901
        }
1902
1903
        $select = '*';
1904
        if ($getCount) {
1905
            $select = 'count(u.id) as count';
1906
        }
1907
1908
        if (empty($sessionId)) {
1909
            if (empty($groupId)) {
1910
                // students directly subscribed to the course
1911
                $sql = "SELECT $select
1912
                        FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
1913
                        INNER JOIN $userTable u
1914
                        ON cu.user_id = u.id
1915
                        WHERE u.active <> ".USER_SOFT_DELETED." AND c_id = $courseId AND cu.status = ".STUDENT;
1916
1917
                if (!$includeInvitedUsers) {
1918
                    $sql .= " AND u.status != ".INVITEE;
1919
                }
1920
                $sql .= $limitCondition;
1921
                $rs = Database::query($sql);
1922
1923
                if ($getCount) {
1924
                    $row = Database::fetch_array($rs);
1925
1926
                    return (int) $row['count'];
1927
                }
1928
1929
                while ($student = Database::fetch_array($rs)) {
1930
                    $students[$student['user_id']] = $student;
1931
                }
1932
            } else {
1933
                $students = GroupManager::get_users(
1934
                    $groupId,
1935
                    false,
1936
                    $start,
1937
                    $limit,
1938
                    $getCount,
1939
                    $courseInfo['real_id']
1940
                );
1941
                $students = array_flip($students);
1942
            }
1943
        }
1944
1945
        // students subscribed to the course through a session
1946
        if ($with_session) {
1947
            $joinSession = '';
1948
            //Session creation date
1949
            if (!empty($date_from) && !empty($date_to)) {
1950
                $joinSession = "INNER JOIN ".Database::get_main_table(TABLE_MAIN_SESSION)." s";
1951
            }
1952
1953
            $sql = "SELECT $select
1954
                      FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." scu
1955
                      $joinSession
1956
                      INNER JOIN $userTable u
1957
                      ON scu.user_id = u.id
1958
                      WHERE u.active <> ".USER_SOFT_DELETED." AND scu.c_id = $courseId AND scu.status = ".SessionEntity::STUDENT;
1959
1960
            if (!empty($date_from) && !empty($date_to)) {
1961
                $date_from = Database::escape_string($date_from);
1962
                $date_to = Database::escape_string($date_to);
1963
                $sql .= " AND s.access_start_date >= '$date_from' AND s.access_end_date <= '$date_to'";
1964
            }
1965
1966
            if (0 != $sessionId) {
1967
                $sql .= " AND scu.session_id = $sessionId";
1968
            }
1969
1970
            if (!$includeInvitedUsers) {
1971
                $sql .= " AND u.status != ".INVITEE;
1972
            }
1973
            $sql .= $limitCondition;
1974
1975
            $rs = Database::query($sql);
1976
1977
            if ($getCount) {
1978
                $row = Database::fetch_array($rs);
1979
1980
                return (int) $row['count'];
1981
            }
1982
1983
            while ($student = Database::fetch_array($rs)) {
1984
                $students[$student['user_id']] = $student;
1985
            }
1986
        }
1987
1988
        return $students;
1989
    }
1990
1991
    /**
1992
     * Return user info array of all teacher-users registered in a course
1993
     * This only returns the users that are registered in this actual course, not linked courses.
1994
     *
1995
     * @param string $course_code
1996
     *
1997
     * @return array with user id
1998
     */
1999
    public static function get_teacher_list_from_course_code($course_code)
2000
    {
2001
        $courseInfo = api_get_course_info($course_code);
2002
        $courseId = $courseInfo['real_id'];
2003
        if (empty($courseId)) {
2004
            return false;
2005
        }
2006
2007
        $sql = "SELECT DISTINCT
2008
                    u.id as user_id,
2009
                    u.lastname,
2010
                    u.firstname,
2011
                    u.email,
2012
                    u.username,
2013
                    u.status
2014
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
2015
                INNER JOIN ".Database::get_main_table(TABLE_MAIN_USER)." u
2016
                ON (cu.user_id = u.id)
2017
                WHERE
2018
                    cu.c_id = $courseId AND
2019
                    cu.status = 1 ";
2020
        $rs = Database::query($sql);
2021
        $teachers = [];
2022
        while ($teacher = Database::fetch_array($rs)) {
2023
            $teachers[$teacher['user_id']] = $teacher;
2024
        }
2025
2026
        return $teachers;
2027
    }
2028
2029
    /**
2030
     * Return user info array of all teacher-users registered in a course
2031
     * This only returns the users that are registered in this actual course, not linked courses.
2032
     *
2033
     * @param int  $courseId
2034
     * @param bool $loadAvatars
2035
     *
2036
     * @return array with user id
2037
     */
2038
    public static function getTeachersFromCourse($courseId, $loadAvatars = true)
2039
    {
2040
        $courseId = (int) $courseId;
2041
2042
        if (empty($courseId)) {
2043
            return false;
2044
        }
2045
2046
        $sql = "SELECT DISTINCT
2047
                    u.id as user_id,
2048
                    u.lastname,
2049
                    u.firstname,
2050
                    u.email,
2051
                    u.username,
2052
                    u.status
2053
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
2054
                INNER JOIN ".Database::get_main_table(TABLE_MAIN_USER)." u
2055
                ON (cu.user_id = u.id)
2056
                WHERE
2057
                    cu.c_id = $courseId AND
2058
                    cu.status = 1 ";
2059
        $rs = Database::query($sql);
2060
        $listTeachers = [];
2061
        $teachers = [];
2062
        $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&course_id='.$courseId;
2063
        while ($teacher = Database::fetch_array($rs)) {
2064
            $teachers['id'] = $teacher['user_id'];
2065
            $teachers['lastname'] = $teacher['lastname'];
2066
            $teachers['firstname'] = $teacher['firstname'];
2067
            $teachers['email'] = $teacher['email'];
2068
            $teachers['username'] = $teacher['username'];
2069
            $teachers['status'] = $teacher['status'];
2070
            $teachers['fullname'] = api_get_person_name($teacher['firstname'], $teacher['lastname']);
2071
            $teachers['avatar'] = '';
2072
            /*if ($loadAvatars) {
2073
                $userPicture = UserManager::getUserPicture($teacher['user_id'], USER_IMAGE_SIZE_SMALL);
2074
                $teachers['avatar'] = $userPicture;
2075
            }*/
2076
            $teachers['url'] = $url.'&user_id='.$teacher['user_id'];
2077
            $listTeachers[] = $teachers;
2078
        }
2079
2080
        return $listTeachers;
2081
    }
2082
2083
    /**
2084
     * Returns a string list of teachers assigned to the given course.
2085
     *
2086
     * @param string $course_code
2087
     * @param string $separator           between teachers names
2088
     * @param bool   $add_link_to_profile Whether to add a link to the teacher's profile
2089
     * @param bool   $orderList
2090
     *
2091
     * @return string List of teachers teaching the course
2092
     */
2093
    public static function getTeacherListFromCourseCodeToString(
2094
        $course_code,
2095
        $separator = self::USER_SEPARATOR,
2096
        $add_link_to_profile = false,
2097
        $orderList = false
2098
    ) {
2099
        $teacher_list = self::get_teacher_list_from_course_code($course_code);
2100
        $html = '';
2101
        $list = [];
2102
        if (!empty($teacher_list)) {
2103
            foreach ($teacher_list as $teacher) {
2104
                $teacher_name = api_get_person_name(
2105
                    $teacher['firstname'],
2106
                    $teacher['lastname']
2107
                );
2108
                if ($add_link_to_profile) {
2109
                    $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$teacher['user_id'];
2110
                    $teacher_name = Display::url(
2111
                        $teacher_name,
2112
                        $url,
2113
                        [
2114
                            'class' => 'ajax',
2115
                            'data-title' => $teacher_name,
2116
                        ]
2117
                    );
2118
                }
2119
                $list[] = $teacher_name;
2120
            }
2121
2122
            if (!empty($list)) {
2123
                if (true === $orderList) {
2124
                    $html .= '<ul class="user-teacher">';
2125
                    foreach ($list as $teacher) {
2126
                        $html .= '<li>';
2127
                        $html .= Display::getMdiIcon(ObjectIcon::TEACHER, 'ch-tool-icon', null, ICON_SIZE_TINY);
2128
                        $html .= ' '.$teacher;
2129
                        $html .= '</li>';
2130
                    }
2131
                    $html .= '</ul>';
2132
                } else {
2133
                    $html .= array_to_string($list, $separator);
2134
                }
2135
            }
2136
        }
2137
2138
        return $html;
2139
    }
2140
2141
    /**
2142
     * This function returns information about coachs from a course in session.
2143
     *
2144
     * @param int $session_id
2145
     * @param int $courseId
2146
     *
2147
     * @return array containing user_id, lastname, firstname, username
2148
     */
2149
    public static function get_coachs_from_course($session_id = 0, $courseId = 0)
2150
    {
2151
        if (!empty($session_id)) {
2152
            $session_id = intval($session_id);
2153
        } else {
2154
            $session_id = api_get_session_id();
2155
        }
2156
2157
        if (!empty($courseId)) {
2158
            $courseId = intval($courseId);
2159
        } else {
2160
            $courseId = api_get_course_int_id();
2161
        }
2162
2163
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
2164
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2165
2166
        $sql = "SELECT DISTINCT
2167
                    u.id as user_id,
2168
                    u.lastname,
2169
                    u.firstname,
2170
                    u.username
2171
                FROM $tbl_user u
2172
                INNER JOIN $tbl_session_course_user scu
2173
                ON (u.id = scu.user_id)
2174
                WHERE
2175
                    scu.session_id = $session_id AND
2176
                    scu.c_id = $courseId AND
2177
                    scu.status = ".SessionEntity::COURSE_COACH;
2178
        $rs = Database::query($sql);
2179
2180
        $coaches = [];
2181
        if (Database::num_rows($rs) > 0) {
2182
            while ($row = Database::fetch_array($rs)) {
2183
                $completeName = api_get_person_name($row['firstname'], $row['lastname']);
2184
                $coaches[] = $row + ['full_name' => $completeName];
2185
            }
2186
        }
2187
2188
        return $coaches;
2189
    }
2190
2191
    /**
2192
     * @param int    $session_id
2193
     * @param int    $courseId
2194
     * @param string $separator
2195
     * @param bool   $add_link_to_profile
2196
     * @param bool   $orderList
2197
     *
2198
     * @return string
2199
     */
2200
    public static function get_coachs_from_course_to_string(
2201
        $session_id = 0,
2202
        $courseId = 0,
2203
        $separator = self::USER_SEPARATOR,
2204
        $add_link_to_profile = false,
2205
        $orderList = false
2206
    ) {
2207
        $coachList = self::get_coachs_from_course($session_id, $courseId);
2208
        $course_coachs = [];
2209
        if (!empty($coachList)) {
2210
            foreach ($coachList as $coach_course) {
2211
                $coach_name = $coach_course['full_name'];
2212
                if ($add_link_to_profile) {
2213
                    $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;
2214
                    $coach_name = Display::url(
2215
                        $coach_name,
2216
                        $url,
2217
                        [
2218
                            'class' => 'ajax',
2219
                            'data-title' => $coach_name,
2220
                        ]
2221
                    );
2222
                }
2223
                $course_coachs[] = $coach_name;
2224
            }
2225
        }
2226
2227
        $html = '';
2228
        if (!empty($course_coachs)) {
2229
            if (true === $orderList) {
2230
                $html .= '<ul class="user-coachs">';
2231
                foreach ($course_coachs as $coachs) {
2232
                    $html .= Display::tag(
2233
                        'li',
2234
                        Display::getMdiIcon(
2235
                            ObjectIcon::TEACHER,
2236
                            'ch-tool-icon',
2237
                            null,
2238
                            ICON_SIZE_TINY,
2239
                            get_lang('Coach')
2240
                        ).' '.$coachs
2241
                    );
2242
                }
2243
                $html .= '</ul>';
2244
            } else {
2245
                $html = array_to_string($course_coachs, $separator);
2246
            }
2247
        }
2248
2249
        return $html;
2250
    }
2251
2252
    /**
2253
     * Get the list of groups from the course.
2254
     *
2255
     * @param string $course_code
2256
     * @param int    $session_id     Session ID (optional)
2257
     * @param int    $getEmptyGroups get empty groups (optional)
2258
     *
2259
     * @return CGroup[]
2260
     */
2261
    public static function get_group_list_of_course(
2262
        $course_code,
2263
        $session_id = 0,
2264
        $getEmptyGroups = 0,
2265
        $asArray = false
2266
    ) {
2267
        $course_info = api_get_course_info($course_code);
2268
2269
        if (empty($course_info)) {
2270
            return [];
2271
        }
2272
        $course_id = $course_info['real_id'];
2273
2274
        if (empty($course_id)) {
2275
            return [];
2276
        }
2277
2278
        $repo = Container::getGroupRepository();
2279
2280
        $course = api_get_course_entity($course_info['real_id']);
2281
        $session = api_get_session_entity($session_id);
2282
        $qb = $repo->getResourcesByCourse($course, $session);
2283
        $groups = $qb->getQuery()->getResult();
2284
        $groupList = [];
2285
        /** @var CGroup $group */
2286
        foreach ($groups as $group) {
2287
            if (0 === $getEmptyGroups) {
2288
                if (!$group->hasMembers()) {
2289
                    continue;
2290
                }
2291
            }
2292
            if ($asArray) {
2293
                $groupList[$group->getIid()] = ['id' => $group->getIid(), 'name' => $group->getTitle()];
2294
            } else {
2295
                $groupList[$group->getIid()] = $group;
2296
            }
2297
        }
2298
2299
        /* 0 != $session_id ? $session_condition = ' WHERE g.session_id IN(1,'.intval($session_id).')' : $session_condition = ' WHERE g.session_id = 0';
2300
         if (0 == $in_get_empty_group) {
2301
             // get only groups that are not empty
2302
             $sql = "SELECT DISTINCT g.iid, g.title
2303
                     FROM ".Database::get_course_table(TABLE_GROUP)." AS g
2304
                     INNER JOIN ".Database::get_course_table(TABLE_GROUP_USER)." gu
2305
                     ON (g.iid = gu.group_id)
2306
                     $session_condition
2307
                     ORDER BY g.title";
2308
         } else {
2309
             // get all groups even if they are empty
2310
             $sql = "SELECT g.iid, g.title
2311
                     FROM ".Database::get_course_table(TABLE_GROUP)." AS g
2312
                     $session_condition
2313
                     AND c_id = $course_id";
2314
         }
2315
2316
         $result = Database::query($sql);
2317
         $groupList = [];
2318
         while ($groupData = Database::fetch_array($result)) {
2319
             $groupData['userNb'] = GroupManager::number_of_students($groupData['iid'], $course_id);
2320
             $groupList[$groupData['iid']] = $groupData;
2321
         }*/
2322
2323
        return $groupList;
2324
    }
2325
2326
    /**
2327
     * Delete a course
2328
     * This function deletes a whole course-area from the platform. When the
2329
     * given course is a virtual course, the database and directory will not be
2330
     * deleted.
2331
     * When the given course is a real course, also all virtual courses refering
2332
     * to the given course will be deleted.
2333
     * Considering the fact that we remove all traces of the course in the main
2334
     * database, it makes sense to remove all tracking as well (if stats databases exist)
2335
     * so that a new course created with this code would not use the remains of an older
2336
     * course.
2337
     *
2338
     * @param string $code The code of the course to delete
2339
     */
2340
    public static function delete_course($code)
2341
    {
2342
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2343
        $table_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
2344
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2345
2346
        $table_stats_hotpots = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES);
2347
        $table_stats_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
2348
        $table_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2349
        $table_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
2350
        $table_stats_lastaccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
2351
        $table_stats_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2352
        $table_stats_online = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
2353
        $table_stats_downloads = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
2354
        $table_stats_links = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
2355
        $table_stats_uploads = Database::get_main_table(TABLE_STATISTIC_TRACK_E_UPLOADS);
2356
2357
        if (empty($code)) {
2358
            return false;
2359
        }
2360
2361
        $courseRepo = Container::getCourseRepository();
2362
        /** @var Course $course */
2363
        $course = $courseRepo->findOneBy(['code' => $code]);
2364
2365
        if (null === $course) {
2366
            return false;
2367
        }
2368
2369
        $courseId = $course->getId();
2370
2371
        /** @var SequenceResourceRepository $repo */
2372
        $repo = Database::getManager()->getRepository(SequenceResource::class);
2373
        $sequenceResource = $repo->findRequirementForResource(
2374
            $courseId,
2375
            SequenceResource::COURSE_TYPE
2376
        );
2377
2378
        if ($sequenceResource) {
2379
            Display::addFlash(
2380
                Display::return_message(
2381
                    get_lang('ThereIsASequenceResourceLinkedToThisCourseYouNeedToDeleteItFirst'),
2382
                    'error'
2383
                )
2384
            );
2385
2386
            return false;
2387
        }
2388
2389
        $count = 0;
2390
        if (api_is_multiple_url_enabled()) {
2391
            $url_id = 1;
2392
            if (-1 != api_get_current_access_url_id()) {
2393
                $url_id = api_get_current_access_url_id();
2394
            }
2395
            UrlManager::delete_url_rel_course($courseId, $url_id);
2396
            $count = UrlManager::getCountUrlRelCourse($courseId);
2397
        }
2398
2399
        if (0 === $count) {
2400
            // Cleaning group categories
2401
            $groupCategories = GroupManager::get_categories($course);
2402
            if (!empty($groupCategories)) {
2403
                foreach ($groupCategories as $category) {
2404
                    GroupManager::delete_category($category['iid'], $course->getCode());
2405
                }
2406
            }
2407
2408
            $course_tables = AddCourse::get_course_tables();
2409
            // Cleaning c_x tables
2410
            if (!empty($courseId)) {
2411
                foreach ($course_tables as $table) {
2412
                    if ('document' === $table) {
2413
                        // Table document will be deleted by Doctrine.
2414
                        continue;
2415
                    }
2416
                    $table = Database::get_course_table($table);
2417
                }
2418
            }
2419
2420
            $resourceLink = $course->getFirstResourceLink();
2421
            $resourceLinkId = $resourceLink?->getId();
2422
2423
            // Unsubscribe all users from the course
2424
            $sql = "DELETE FROM $table_course_user WHERE c_id = $courseId";
2425
            Database::query($sql);
2426
            // Delete the course from the sessions tables
2427
            $sql = "DELETE FROM $table_session_course WHERE c_id = $courseId";
2428
            Database::query($sql);
2429
            $sql = "DELETE FROM $table_session_course_user WHERE c_id = $courseId";
2430
            Database::query($sql);
2431
2432
            // Delete from Course - URL
2433
            // Already deleted because of entities.
2434
            //$sql = "DELETE FROM $table_course_rel_url WHERE c_id = $courseId";
2435
            //Database::query($sql);
2436
2437
            // Delete the course from the stats tables
2438
            $sql = "DELETE FROM $table_stats_hotpots WHERE c_id = $courseId";
2439
            Database::query($sql);
2440
            $sql = "DELETE FROM $table_stats_access WHERE c_id = $courseId";
2441
            Database::query($sql);
2442
            $sql = "DELETE FROM $table_stats_lastaccess WHERE c_id = $courseId";
2443
            Database::query($sql);
2444
            $sql = "DELETE FROM $table_stats_course_access WHERE c_id = $courseId";
2445
            Database::query($sql);
2446
            $sql = "DELETE FROM $table_stats_online WHERE c_id = $courseId";
2447
            Database::query($sql);
2448
            // Do not delete rows from track_e_default as these include course
2449
            // creation and other important things that do not take much space
2450
            // but give information on the course history
2451
            //$sql = "DELETE FROM $table_stats_default WHERE c_id = $courseId";
2452
            //Database::query($sql);
2453
            if ($resourceLinkId) {
2454
                $sql = "DELETE FROM $table_stats_downloads WHERE resource_link_id = $resourceLinkId";
2455
                Database::query($sql);
2456
            }
2457
            $sql = "DELETE FROM $table_stats_links WHERE c_id = $courseId";
2458
            Database::query($sql);
2459
            $sql = "DELETE FROM $table_stats_uploads WHERE c_id = $courseId";
2460
            Database::query($sql);
2461
2462
            // Update ticket
2463
            $table = Database::get_main_table(TABLE_TICKET_TICKET);
2464
            $sql = "UPDATE $table SET course_id = NULL WHERE course_id = $courseId";
2465
            Database::query($sql);
2466
2467
            $repo->deleteSequenceResource(
2468
                $courseId,
2469
                SequenceResource::COURSE_TYPE
2470
            );
2471
2472
            // Class
2473
            $table = Database::get_main_table(TABLE_USERGROUP_REL_COURSE);
2474
            $sql = "DELETE FROM $table
2475
                    WHERE course_id = $courseId";
2476
            Database::query($sql);
2477
2478
            // Skills
2479
            $table = Database::get_main_table(TABLE_MAIN_SKILL_REL_USER);
2480
            $argumentation = Database::escape_string(
2481
                sprintf(
2482
                    get_lang('This skill was obtained through course %s which has been removed since then.'),
2483
                    $course->getCode()
2484
                )
2485
            );
2486
            $sql = "UPDATE $table SET course_id = NULL, session_id = NULL, argumentation = '$argumentation'
2487
                    WHERE course_id = $courseId";
2488
            Database::query($sql);
2489
2490
            // Should be deleted by doctrine
2491
            //$sql = "DELETE FROM skill_rel_course WHERE c_id = $courseId";
2492
            //Database::query($sql);
2493
2494
            // Deletes all groups, group-users, group-tutors information
2495
            // To prevent fK mix up on some tables
2496
            //GroupManager::deleteAllGroupsFromCourse($courseId);
2497
2498
            $appPlugin = new AppPlugin();
2499
            $appPlugin->performActionsWhenDeletingItem('course', $courseId);
2500
2501
            //$repo = Container::getQuizRepository();
2502
            //$repo->deleteAllByCourse($courseEntity);
2503
2504
            // Delete the course from the database
2505
            $courseRepo->deleteCourse($course);
2506
2507
            // delete extra course fields
2508
            $extraFieldValues = new ExtraFieldValue('course');
2509
            $extraFieldValues->deleteValuesByItem($courseId);
2510
2511
            // Add event to system log
2512
            Event::addEvent(
2513
                LOG_COURSE_DELETE,
2514
                LOG_COURSE_CODE,
2515
                $code,
2516
                api_get_utc_datetime(),
2517
                api_get_user_id(),
2518
                $courseId
2519
            );
2520
2521
            return true;
2522
        }
2523
    }
2524
2525
    /**
2526
     * Sort courses for a specific user ??
2527
     *
2528
     * @param int    $user_id     User ID
2529
     * @param string $course_code Course code
2530
     *
2531
     * @return int Minimum course order
2532
     *
2533
     * @todo Review documentation
2534
     */
2535
    public static function userCourseSort($user_id, $course_code)
2536
    {
2537
        $user_id = (int) $user_id;
2538
2539
        if (empty($user_id) || empty($course_code)) {
2540
            return 0;
2541
        }
2542
2543
        $course_code = Database::escape_string($course_code);
2544
        $TABLECOURSE = Database::get_main_table(TABLE_MAIN_COURSE);
2545
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2546
2547
        $course_title = Database::result(
2548
            Database::query(
2549
                "SELECT title FROM $TABLECOURSE WHERE code = '$course_code'"
2550
            ),
2551
            0,
2552
            0
2553
        );
2554
        if (false === $course_title) {
2555
            $course_title = '';
2556
        }
2557
2558
        $sql = "SELECT course.code as code, course.title as title, cu.sort as sort
2559
                FROM $TABLECOURSUSER as cu, $TABLECOURSE as course
2560
                WHERE   course.id = cu.c_id AND user_id = $user_id AND
2561
                        cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
2562
                        user_course_cat = 0
2563
                ORDER BY cu.sort";
2564
        $result = Database::query($sql);
2565
2566
        $course_title_precedent = '';
2567
        $counter = 0;
2568
        $course_found = false;
2569
        $course_sort = 1;
2570
2571
        if (Database::num_rows($result) > 0) {
2572
            while ($courses = Database::fetch_array($result)) {
2573
                if ('' == $course_title_precedent) {
2574
                    $course_title_precedent = $courses['title'];
2575
                }
2576
                if (api_strcasecmp($course_title_precedent, $course_title) < 0) {
2577
                    $course_found = true;
2578
                    if (!empty($courses['sort'])) {
2579
                        $course_sort = $courses['sort'];
2580
                    }
2581
                    if (0 == $counter) {
2582
                        $sql = "UPDATE $TABLECOURSUSER
2583
                                SET sort = sort+1
2584
                                WHERE
2585
                                    user_id= $user_id AND
2586
                                    relation_type <> ".COURSE_RELATION_TYPE_RRHH."
2587
                                    AND user_course_cat = 0
2588
                                    AND sort > $course_sort";
2589
                        $course_sort++;
2590
                    } else {
2591
                        $sql = "UPDATE $TABLECOURSUSER SET sort = sort+1
2592
                                WHERE
2593
                                    user_id= $user_id AND
2594
                                    relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
2595
                                    user_course_cat = 0 AND
2596
                                    sort >= $course_sort";
2597
                    }
2598
                    Database::query($sql);
2599
                    break;
2600
                } else {
2601
                    $course_title_precedent = $courses['title'];
2602
                }
2603
                $counter++;
2604
            }
2605
2606
            // We must register the course in the beginning of the list
2607
            if (!$course_found) {
2608
                $course_sort = Database::result(
2609
                    Database::query(
2610
                        'SELECT min(sort) as min_sort FROM '.$TABLECOURSUSER.' WHERE user_id = "'.$user_id.'" AND user_course_cat="0"'
2611
                    ),
2612
                    0,
2613
                    0
2614
                );
2615
                Database::query("UPDATE $TABLECOURSUSER SET sort = sort+1 WHERE user_id = $user_id AND user_course_cat = 0");
2616
            }
2617
        }
2618
2619
        return (int) $course_sort;
2620
    }
2621
2622
    /**
2623
     * check if course exists.
2624
     *
2625
     * @param string $courseCode
2626
     *
2627
     * @return int if exists, false else
2628
     */
2629
    public static function course_exists($courseCode)
2630
    {
2631
        $courseCode = Database::escape_string($courseCode);
2632
        $sql = "SELECT 1 FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
2633
                WHERE code = '$courseCode'";
2634
2635
        return Database::num_rows(Database::query($sql));
2636
    }
2637
2638
    /**
2639
     * Send an email to tutor after the auth-suscription of a student in your course.
2640
     *
2641
     * @author Carlos Vargas <[email protected]>, Dokeos Latino
2642
     *
2643
     * @param int    $user_id            the id of the user
2644
     * @param string $courseId           the course code
2645
     * @param bool   $send_to_tutor_also
2646
     *
2647
     * @return false|null we return the message that is displayed when the action is successful
2648
     */
2649
    public static function email_to_tutor($user_id, $courseId, $send_to_tutor_also = false)
2650
    {
2651
        $user_id = (int) $user_id;
2652
        $courseId = (int) $courseId;
2653
        $information = api_get_course_info_by_id($courseId);
2654
        $course_code = $information['code'];
2655
        $student = api_get_user_info($user_id);
2656
2657
        $name_course = $information['title'];
2658
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
2659
                WHERE c_id = $courseId";
2660
2661
        // TODO: Ivan: This is a mistake, please, have a look at it. Intention here is diffcult to be guessed.
2662
        //if ($send_to_tutor_also = true)
2663
        // Proposed change:
2664
        if ($send_to_tutor_also) {
2665
            $sql .= ' AND is_tutor = 1';
2666
        } else {
2667
            $sql .= ' AND status = 1';
2668
        }
2669
2670
        $result = Database::query($sql);
2671
        while ($row = Database::fetch_array($result)) {
2672
            $tutor = api_get_user_info($row['user_id']);
2673
            $emailto = $tutor['email'];
2674
            $emailsubject = get_lang('New user in the course').': '.$name_course;
2675
            $emailbody = get_lang('Dear').': '.api_get_person_name($tutor['firstname'], $tutor['lastname'])."\n";
2676
            $emailbody .= get_lang('MessageNew user in the course').': '.$name_course."\n";
2677
            $emailbody .= get_lang('Username').': '.$student['username']."\n";
2678
            if (api_is_western_name_order()) {
2679
                $emailbody .= get_lang('First name').': '.$student['firstname']."\n";
2680
                $emailbody .= get_lang('Last name').': '.$student['lastname']."\n";
2681
            } else {
2682
                $emailbody .= get_lang('Last name').': '.$student['lastname']."\n";
2683
                $emailbody .= get_lang('First name').': '.$student['firstname']."\n";
2684
            }
2685
            $emailbody .= get_lang('e-mail').': <a href="mailto:'.$student['email'].'">'.$student['email']."</a>\n\n";
2686
            $recipient_name = api_get_person_name(
2687
                $tutor['firstname'],
2688
                $tutor['lastname'],
2689
                null,
2690
                PERSON_NAME_EMAIL_ADDRESS
2691
            );
2692
            $sender_name = api_get_person_name(
2693
                api_get_setting('administratorName'),
2694
                api_get_setting('administratorSurname'),
2695
                null,
2696
                PERSON_NAME_EMAIL_ADDRESS
2697
            );
2698
            $email_admin = api_get_setting('emailAdministrator');
2699
2700
            api_mail_html(
2701
                $recipient_name,
2702
                $emailto,
2703
                $emailsubject,
2704
                $emailbody,
2705
                $sender_name,
2706
                $email_admin
2707
            );
2708
        }
2709
    }
2710
2711
    /**
2712
     * @return array
2713
     */
2714
    public static function get_special_course_list()
2715
    {
2716
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
2717
        $tbl_course_field = Database::get_main_table(TABLE_EXTRA_FIELD);
2718
        $tbl_course_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2719
        $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2720
2721
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
2722
2723
        $courseList = [];
2724
        // get course list auto-register
2725
2726
        $sql = "SELECT id FROM $tbl_course_field
2727
                WHERE item_type = $extraFieldType AND
2728
                variable = 'special_course'";
2729
        $result = Database::query($sql);
2730
        $courseList = [];
2731
2732
        if (Database::num_rows($result) > 0) {
2733
            $row = Database::fetch_assoc($result);
2734
            // Get list of special courses (appear to all)
2735
            // Note: The value is better indexed as string, so
2736
            // using '1' instead of integer is more efficient
2737
            $sql = "SELECT DISTINCT(item_id) as cid
2738
                FROM $tbl_course_field_value
2739
                WHERE field_id = ".$row['id']." AND field_value = '1'";
2740
            $result = Database::query($sql);
2741
            while ($row = Database::fetch_assoc($result)) {
2742
                $courseList[] = $row['cid'];
2743
            }
2744
            if (count($courseList) < 1) {
2745
                return $courseList;
2746
            }
2747
            if (api_get_multiple_access_url()) {
2748
                //we filter the courses by the active URL
2749
                $coursesSelect = '';
2750
                if (1 == count($courseList)) {
2751
                    $coursesSelect = $courseList[0];
2752
                } else {
2753
                    $coursesSelect = implode(',', $courseList);
2754
                }
2755
                $access_url_id = api_get_current_access_url_id();
2756
                if (-1 != $access_url_id) {
2757
                    $sql = "SELECT c_id FROM $tbl_url_course
2758
                            WHERE access_url_id = $access_url_id
2759
                            AND c_id IN ($coursesSelect)";
2760
                    $result = Database::query($sql);
2761
                    while ($row = Database::fetch_assoc($result)) {
2762
                        $courseList[] = $row['c_id'];
2763
                    }
2764
                }
2765
            }
2766
        }
2767
2768
        return $courseList;
2769
    }
2770
2771
    /**
2772
     * Get the course codes that have been restricted in the catalogue, and if byUserId is set
2773
     * then the courses that the user is allowed or not to see in catalogue.
2774
     *
2775
     * @param bool $allowed  Either if the courses have some users that are or are not allowed to see in catalogue
2776
     * @param int  $byUserId if the courses are or are not allowed to see to the user
2777
     *
2778
     * @return array Course codes allowed or not to see in catalogue by some user or the user
2779
     */
2780
    public static function getCatalogCourseList($allowed = true, $byUserId = -1)
2781
    {
2782
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
2783
        $tblCourseRelUserCatalogue = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
2784
        $visibility = $allowed ? 1 : 0;
2785
2786
        // Restriction by user id
2787
        $currentUserRestriction = '';
2788
2789
        $byUserId = (int) $byUserId;
2790
        if ($byUserId > 0) {
2791
            $currentUserRestriction = " AND tcruc.user_id = $byUserId ";
2792
        }
2793
2794
        //we filter the courses from the URL
2795
        $joinAccessUrl = '';
2796
        $whereAccessUrl = '';
2797
        if (api_get_multiple_access_url()) {
2798
            $accessUrlId = api_get_current_access_url_id();
2799
            if (-1 != $accessUrlId) {
2800
                $tblUrlCourse = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2801
                $joinAccessUrl = "LEFT JOIN $tblUrlCourse url_rel_course
2802
                                  ON url_rel_course.c_id = c.id ";
2803
                $whereAccessUrl = " AND access_url_id = $accessUrlId ";
2804
            }
2805
        }
2806
2807
        // get course list auto-register
2808
        $sql = "SELECT DISTINCT(c.code)
2809
                FROM $tblCourseRelUserCatalogue tcruc
2810
                INNER JOIN $courseTable c
2811
                ON (c.id = tcruc.c_id) $joinAccessUrl
2812
                WHERE tcruc.visible = $visibility $currentUserRestriction $whereAccessUrl";
2813
2814
        $result = Database::query($sql);
2815
        $courseList = [];
2816
2817
        if (Database::num_rows($result) > 0) {
2818
            while ($resultRow = Database::fetch_array($result)) {
2819
                $courseList[] = $resultRow['code'];
2820
            }
2821
        }
2822
2823
        return $courseList;
2824
    }
2825
2826
    /**
2827
     * Get list of courses for a given user.
2828
     *
2829
     * @param int   $user_id
2830
     * @param bool  $include_sessions                   Whether to include courses from session or not
2831
     * @param bool  $adminGetsAllCourses                If the user is platform admin,
2832
     *                                                  whether he gets all the courses or just his. Note: This does
2833
     *                                                  *not* include all sessions
2834
     * @param bool  $loadSpecialCourses
2835
     * @param array $skipCourseList                     List of course ids to skip
2836
     * @param bool  $useUserLanguageFilterIfAvailable
2837
     * @param bool  $showCoursesSessionWithDifferentKey
2838
     *
2839
     * @return array List of codes and db name
2840
     *
2841
     * @author isaac flores paz
2842
     */
2843
    public static function get_courses_list_by_user_id(
2844
        $user_id,
2845
        $include_sessions = false,
2846
        $adminGetsAllCourses = false,
2847
        $loadSpecialCourses = true,
2848
        $skipCourseList = [],
2849
        $useUserLanguageFilterIfAvailable = true,
2850
        $showCoursesSessionWithDifferentKey = false
2851
    ) {
2852
        $user_id = intval($user_id);
2853
        $urlId = api_get_current_access_url_id();
2854
        $course_list = [];
2855
        $codes = [];
2856
2857
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2858
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2859
        $tableCourseUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2860
        $tblCourseCategory = Database::get_main_table(TABLE_MAIN_CATEGORY);
2861
2862
        $languageCondition = '';
2863
        $onlyInUserLanguage = ('true' === api_get_setting('course.my_courses_show_courses_in_user_language_only'));
2864
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
2865
            $userInfo = api_get_user_info(api_get_user_id());
2866
            if (!empty($userInfo['language'])) {
2867
                $languageCondition = " AND course.course_language = '".$userInfo['language']."' ";
2868
            }
2869
        }
2870
2871
        if ($adminGetsAllCourses && UserManager::is_admin($user_id)) {
2872
            // get the whole courses list
2873
            $sql = "SELECT DISTINCT(course.code), course.id as real_id, course.title
2874
                    FROM $tbl_course course
2875
                    INNER JOIN $tableCourseUrl url
2876
                    ON (course.id = url.c_id)
2877
                    WHERE
2878
                        url.access_url_id = $urlId
2879
                        $languageCondition
2880
                ";
2881
        } else {
2882
            $withSpecialCourses = $withoutSpecialCourses = '';
2883
2884
            if ($loadSpecialCourses) {
2885
                $specialCourseList = self::get_special_course_list();
2886
                if (!empty($specialCourseList)) {
2887
                    $specialCourseToString = '"'.implode('","', $specialCourseList).'"';
2888
                    $withSpecialCourses = ' AND course.id IN ('.$specialCourseToString.')';
2889
                    $withoutSpecialCourses = ' AND course.id NOT IN ('.$specialCourseToString.')';
2890
                }
2891
2892
                if (!empty($withSpecialCourses)) {
2893
                    $sql = "SELECT DISTINCT (course.code),
2894
                            course.id as real_id,
2895
                            course.title
2896
                            FROM $tbl_course_user course_rel_user
2897
                            LEFT JOIN $tbl_course course
2898
                            ON course.id = course_rel_user.c_id
2899
                            INNER JOIN $tableCourseUrl url
2900
                            ON (course.id = url.c_id)
2901
                            WHERE url.access_url_id = $urlId
2902
                            $withSpecialCourses
2903
                            $languageCondition
2904
                            GROUP BY course.code
2905
                            ORDER BY course.title, course_rel_user.sort ASC
2906
                    ";
2907
                    $result = Database::query($sql);
2908
                    if (Database::num_rows($result) > 0) {
2909
                        while ($result_row = Database::fetch_assoc($result)) {
2910
                            $result_row['special_course'] = 1;
2911
                            $course_list[] = $result_row;
2912
                            $codes[] = $result_row['real_id'];
2913
                        }
2914
                    }
2915
                }
2916
            }
2917
2918
            // get course list not auto-register. Use Distinct to avoid multiple
2919
            // entries when a course is assigned to a HRD (DRH) as watcher
2920
            $sql = "SELECT
2921
                        DISTINCT(course.code),
2922
                        course.id as real_id,
2923
                        course.title
2924
                    FROM $tbl_course course
2925
                    INNER JOIN $tbl_course_user cru
2926
                    ON (course.id = cru.c_id)
2927
                    INNER JOIN $tableCourseUrl url
2928
                    ON (course.id = url.c_id)
2929
                    WHERE
2930
                        url.access_url_id = $urlId AND
2931
                        cru.user_id = $user_id
2932
                        $withoutSpecialCourses
2933
                        $languageCondition
2934
                    ORDER BY course.title
2935
                    ";
2936
        }
2937
        $result = Database::query($sql);
2938
2939
        if (Database::num_rows($result)) {
2940
            while ($row = Database::fetch_assoc($result)) {
2941
                if (!empty($skipCourseList)) {
2942
                    if (in_array($row['real_id'], $skipCourseList)) {
2943
                        continue;
2944
                    }
2945
                }
2946
                $course_list[] = $row;
2947
                $codes[] = $row['real_id'];
2948
            }
2949
        }
2950
2951
        if (true === $include_sessions) {
2952
            $sql = "SELECT DISTINCT (c.code),
2953
                        c.id as real_id,
2954
                        s.id as session_id,
2955
                        s.name as session_name
2956
                    FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." scu
2957
                    INNER JOIN $tbl_course c
2958
                    ON (scu.c_id = c.id)
2959
                    INNER JOIN ".Database::get_main_table(TABLE_MAIN_SESSION)." s
2960
                    ON (s.id = scu.session_id)
2961
                    WHERE user_id = $user_id ";
2962
            $r = Database::query($sql);
2963
            while ($row = Database::fetch_assoc($r)) {
2964
                if (!empty($skipCourseList)) {
2965
                    if (in_array($row['real_id'], $skipCourseList)) {
2966
                        continue;
2967
                    }
2968
                }
2969
2970
                if ($showCoursesSessionWithDifferentKey) {
2971
                    $course_list[] = $row;
2972
                } else {
2973
                    if (!in_array($row['real_id'], $codes)) {
2974
                        $course_list[] = $row;
2975
                    }
2976
                }
2977
            }
2978
        }
2979
2980
        return $course_list;
2981
    }
2982
2983
    /**
2984
     * Get course ID from a given course directory name.
2985
     *
2986
     * @param string $path Course directory (without any slash)
2987
     *
2988
     * @return string Course code, or false if not found
2989
     */
2990
    public static function getCourseCodeFromDirectory($path)
2991
    {
2992
        $path = Database::escape_string(str_replace('.', '', str_replace('/', '', $path)));
2993
        $res = Database::query("SELECT code FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
2994
                WHERE directory LIKE BINARY '$path'");
2995
        if (false === $res) {
2996
            return false;
2997
        }
2998
        if (1 != Database::num_rows($res)) {
2999
            return false;
3000
        }
3001
        $row = Database::fetch_array($res);
3002
3003
        return $row['code'];
3004
    }
3005
3006
    /**
3007
     * Get course code(s) from visual code.
3008
     *
3009
     * @param   string  Visual code
3010
     *
3011
     * @return array List of codes for the given visual code
3012
     */
3013
    public static function get_courses_info_from_visual_code($code)
3014
    {
3015
        $result = [];
3016
        $sql_result = Database::query("SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
3017
                WHERE visual_code = '".Database::escape_string($code)."'");
3018
        while ($virtual_course = Database::fetch_array($sql_result)) {
3019
            $result[] = $virtual_course;
3020
        }
3021
3022
        return $result;
3023
    }
3024
3025
    /**
3026
     * Creates a new extra field for a given course.
3027
     *
3028
     * @param string $variable    Field's internal variable name
3029
     * @param int    $fieldType   Field's type
3030
     * @param string $displayText Field's language var name
3031
     * @param string $default     Optional. The default value
3032
     *
3033
     * @return int New extra field ID
3034
     */
3035
    public static function create_course_extra_field($variable, $fieldType, $displayText, $default = '')
3036
    {
3037
        $extraField = new ExtraField('course');
3038
        $params = [
3039
            'variable' => $variable,
3040
            'value_type' => $fieldType,
3041
            'display_text' => $displayText,
3042
            'default_value' => $default,
3043
        ];
3044
3045
        return $extraField->save($params);
3046
    }
3047
3048
    /**
3049
     * Update course attributes. Will only update attributes with a non-empty value.
3050
     * Note that you NEED to check that your attributes are valid before using this function.
3051
     *
3052
     * @param int Course id
3053
     * @param array Associative array with field names as keys and field values as values
3054
     *
3055
     * @return Doctrine\DBAL\Driver\Statement|null True if update was successful, false otherwise
3056
     */
3057
    public static function update_attributes($id, $attributes)
3058
    {
3059
        $id = (int) $id;
3060
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
3061
        $sql = "UPDATE $table SET ";
3062
        $i = 0;
3063
        foreach ($attributes as $name => $value) {
3064
            if ('' != $value) {
3065
                if ($i > 0) {
3066
                    $sql .= ", ";
3067
                }
3068
                $sql .= " $name = '".Database::escape_string($value)."'";
3069
                $i++;
3070
            }
3071
        }
3072
        $sql .= " WHERE id = $id";
3073
3074
        return Database::query($sql);
3075
    }
3076
3077
    /**
3078
     * Update an extra field value for a given course.
3079
     *
3080
     * @param string $course_code Course code
3081
     * @param string $variable    Field variable name
3082
     * @param string $value       Optional. Default field value
3083
     *
3084
     * @return bool|int An integer when register a new extra field. And boolean when update the extrafield
3085
     */
3086
    public static function update_course_extra_field_value($course_code, $variable, $value = '')
3087
    {
3088
        $courseInfo = api_get_course_info($course_code);
3089
        $courseId = $courseInfo['real_id'];
3090
3091
        $extraFieldValues = new ExtraFieldValue('course');
3092
        $params = [
3093
            'item_id' => $courseId,
3094
            'variable' => $variable,
3095
            'value' => $value,
3096
        ];
3097
3098
        return $extraFieldValues->save($params);
3099
    }
3100
3101
    /**
3102
     * @param int $sessionId
3103
     *
3104
     * @return mixed
3105
     */
3106
    public static function get_session_category_id_by_session_id($sessionId)
3107
    {
3108
        if (empty($sessionId)) {
3109
            return [];
3110
        }
3111
        $sessionId = intval($sessionId);
3112
        $sql = 'SELECT sc.id session_category
3113
                FROM '.Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY).' sc
3114
                INNER JOIN '.Database::get_main_table(TABLE_MAIN_SESSION).' s
3115
                ON sc.id = s.session_category_id
3116
                WHERE s.id = '.$sessionId;
3117
3118
        return Database::result(
3119
            Database::query($sql),
3120
            0,
3121
            'session_category'
3122
        );
3123
    }
3124
3125
    /**
3126
     * Gets the value of a course extra field. Returns null if it was not found.
3127
     *
3128
     * @param string $variable Name of the extra field
3129
     * @param string $code     Course code
3130
     *
3131
     * @return string Value
3132
     */
3133
    public static function get_course_extra_field_value($variable, $code)
3134
    {
3135
        $courseInfo = api_get_course_info($code);
3136
        $courseId = $courseInfo['real_id'];
3137
3138
        $extraFieldValues = new ExtraFieldValue('course');
3139
        $result = $extraFieldValues->get_values_by_handler_and_field_variable($courseId, $variable);
3140
        if (!empty($result['value'])) {
3141
            return $result['value'];
3142
        }
3143
3144
        return null;
3145
    }
3146
3147
    /**
3148
     * Gets extra field value data and formatted values of a course
3149
     * for extra fields listed in configuration.php in my_course_course_extrafields_to_be_presented
3150
     * (array of variables as value of key 'fields').
3151
     *
3152
     * @param $courseId  int The numeric identifier of the course
3153
     *
3154
     * @return array of data and formatted values as returned by ExtraField::getDataAndFormattedValues
3155
     */
3156
    public static function getExtraFieldsToBePresented($courseId)
3157
    {
3158
        $extraFields = [];
3159
        $fields = api_get_configuration_sub_value('my_course_course_extrafields_to_be_presented/fields');
3160
        if (!empty($fields) && is_array($fields)) {
3161
            $extraFieldManager = new ExtraField('course');
3162
            $dataAndFormattedValues = $extraFieldManager->getDataAndFormattedValues($courseId);
3163
            foreach ($fields as $variable) {
3164
                foreach ($dataAndFormattedValues as $value) {
3165
                    if ($value['variable'] === $variable && !empty($value['value'])) {
3166
                        $extraFields[] = $value;
3167
                    }
3168
                }
3169
            }
3170
        }
3171
3172
        return $extraFields;
3173
    }
3174
3175
    /**
3176
     * Lists details of the course description.
3177
     *
3178
     * @param array        The course description
3179
     * @param string    The encoding
3180
     * @param bool        If true is displayed if false is hidden
3181
     *
3182
     * @return string The course description in html
3183
     */
3184
    public static function get_details_course_description_html(
3185
        $descriptions,
3186
        $charset,
3187
        $action_show = true
3188
    ) {
3189
        $data = null;
3190
        if (isset($descriptions) && count($descriptions) > 0) {
3191
            foreach ($descriptions as $description) {
3192
                $data .= '<div class="sectiontitle">';
3193
                if (api_is_allowed_to_edit() && $action_show) {
3194
                    //delete
3195
                    $data .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=delete&description_id='.$description->id.'" onclick="javascript:if(!confirm(\''.addslashes(api_htmlentities(
3196
                        get_lang('Please confirm your choice'),
3197
                                ENT_QUOTES,
3198
                        $charset
3199
                    )).'\')) return false;">';
3200
                    $data .= Display::getMdiIcon(
3201
                        ActionIcon::DELETE,
3202
                        'ch-tool-icon',
3203
                        'vertical-align:middle;float:right;',
3204
                        ICON_SIZE_SMALL,
3205
                        get_lang('Delete')
3206
                    );
3207
                    $data .= '</a> ';
3208
                    //edit
3209
                    $data .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&description_id='.$description->id.'">';
3210
                    $data .= Display::getMdiIcon(
3211
                        ActionIcon::EDIT,
3212
                        'ch-tool-icon',
3213
                        'vertical-align:middle;float:right; padding-right:4px;',
3214
                        ICON_SIZE_SMALL,
3215
                        get_lang('Edit')
3216
                    );
3217
                    $data .= '</a> ';
3218
                }
3219
                $data .= $description->title;
3220
                $data .= '</div>';
3221
                $data .= '<div class="sectioncomment">';
3222
                $data .= Security::remove_XSS($description->content);
3223
                $data .= '</div>';
3224
            }
3225
        } else {
3226
            $data .= '<em>'.get_lang('There is no course description so far.').'</em>';
3227
        }
3228
3229
        return $data;
3230
    }
3231
3232
    /**
3233
     * Returns the details of a course category.
3234
     *
3235
     * @param string $code Category code
3236
     *
3237
     * @return array Course category
3238
     */
3239
    public static function get_course_category($code)
3240
    {
3241
        $table = Database::get_main_table(TABLE_MAIN_CATEGORY);
3242
        $code = Database::escape_string($code);
3243
        $sql = "SELECT * FROM $table WHERE code = '$code'";
3244
3245
        return Database::fetch_array(Database::query($sql));
3246
    }
3247
3248
    /**
3249
     * Subscribes courses to human resource manager (Dashboard feature).
3250
     *
3251
     * @param int   $hr_manager_id Human Resource Manager id
3252
     * @param array $courses_list  Courses code
3253
     *
3254
     * @return int
3255
     */
3256
    public static function subscribeCoursesToDrhManager($hr_manager_id, $courses_list)
3257
    {
3258
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3259
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3260
3261
        $hr_manager_id = intval($hr_manager_id);
3262
        $affected_rows = 0;
3263
3264
        //Deleting assigned courses to hrm_id
3265
        if (api_is_multiple_url_enabled()) {
3266
            $sql = "SELECT s.c_id FROM $tbl_course_rel_user s
3267
                    INNER JOIN $tbl_course_rel_access_url a
3268
                    ON (a.c_id = s.c_id)
3269
                    WHERE
3270
                        user_id = $hr_manager_id AND
3271
                        relation_type = ".COURSE_RELATION_TYPE_RRHH." AND
3272
                        access_url_id = ".api_get_current_access_url_id();
3273
        } else {
3274
            $sql = "SELECT c_id FROM $tbl_course_rel_user
3275
                    WHERE user_id = $hr_manager_id AND relation_type = ".COURSE_RELATION_TYPE_RRHH;
3276
        }
3277
        $result = Database::query($sql);
3278
        if (Database::num_rows($result) > 0) {
3279
            while ($row = Database::fetch_array($result)) {
3280
                $sql = "DELETE FROM $tbl_course_rel_user
3281
                        WHERE
3282
                            c_id = {$row['c_id']} AND
3283
                            user_id = $hr_manager_id AND
3284
                            relation_type = ".COURSE_RELATION_TYPE_RRHH;
3285
                Database::query($sql);
3286
            }
3287
        }
3288
3289
        // inserting new courses list
3290
        if (is_array($courses_list)) {
3291
            foreach ($courses_list as $course_code) {
3292
                $courseInfo = api_get_course_info($course_code);
3293
                $courseId = $courseInfo['real_id'];
3294
                $sql = "INSERT IGNORE INTO $tbl_course_rel_user(c_id, user_id, status, relation_type)
3295
                        VALUES($courseId, $hr_manager_id, ".DRH.", ".COURSE_RELATION_TYPE_RRHH.")";
3296
                $result = Database::query($sql);
3297
                if (Database::affected_rows($result)) {
3298
                    $affected_rows++;
3299
                }
3300
            }
3301
        }
3302
3303
        return $affected_rows;
3304
    }
3305
3306
    /**
3307
     * get courses followed by human resources manager.
3308
     *
3309
     * @param int    $user_id
3310
     * @param int    $status
3311
     * @param int    $from
3312
     * @param int    $limit
3313
     * @param string $column
3314
     * @param string $direction
3315
     * @param bool   $getCount
3316
     *
3317
     * @return array courses
3318
     */
3319
    public static function get_courses_followed_by_drh(
3320
        $user_id,
3321
        $status = DRH,
3322
        $from = null,
3323
        $limit = null,
3324
        $column = null,
3325
        $direction = null,
3326
        $getCount = false
3327
    ) {
3328
        return self::getCoursesFollowedByUser(
3329
            $user_id,
3330
            $status,
3331
            $from,
3332
            $limit,
3333
            $column,
3334
            $direction,
3335
            $getCount
3336
        );
3337
    }
3338
3339
    /**
3340
     * get courses followed by user.
3341
     *
3342
     * @param int    $user_id
3343
     * @param int    $status
3344
     * @param int    $from
3345
     * @param int    $limit
3346
     * @param string $column
3347
     * @param string $direction
3348
     * @param bool   $getCount
3349
     * @param string $keyword
3350
     * @param int    $sessionId
3351
     * @param bool   $showAllAssignedCourses
3352
     *
3353
     * @return array courses
3354
     */
3355
    public static function getCoursesFollowedByUser(
3356
        $user_id,
3357
        $status = null,
3358
        $from = null,
3359
        $limit = null,
3360
        $column = null,
3361
        $direction = null,
3362
        $getCount = false,
3363
        $keyword = null,
3364
        $sessionId = 0,
3365
        $showAllAssignedCourses = false
3366
    ) {
3367
        // Database Table Definitions
3368
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3369
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3370
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3371
        $sessionId = (int) $sessionId;
3372
        $user_id = (int) $user_id;
3373
        $select = "SELECT DISTINCT c.*, c.id as real_id ";
3374
3375
        if ($getCount) {
3376
            $select = "SELECT COUNT(DISTINCT c.id) as count";
3377
        }
3378
3379
        $whereConditions = '';
3380
        switch ($status) {
3381
            case COURSEMANAGER:
3382
                $whereConditions .= " AND cru.user_id = $user_id";
3383
                if (!$showAllAssignedCourses) {
3384
                    $whereConditions .= " AND cru.status = ".COURSEMANAGER;
3385
                } else {
3386
                    $whereConditions .= " AND relation_type = ".COURSE_RELATION_TYPE_COURSE_MANAGER;
3387
                }
3388
                break;
3389
            case DRH:
3390
                $whereConditions .= " AND
3391
                    cru.user_id = $user_id AND
3392
                    cru.status = ".DRH." AND
3393
                    relation_type = '".COURSE_RELATION_TYPE_RRHH."'
3394
                ";
3395
                break;
3396
        }
3397
3398
        $keywordCondition = null;
3399
        if (!empty($keyword)) {
3400
            $keyword = Database::escape_string($keyword);
3401
            $keywordCondition = " AND (c.code LIKE '%$keyword%' OR c.title LIKE '%$keyword%' ) ";
3402
        }
3403
3404
        $orderBy = null;
3405
        $extraInnerJoin = null;
3406
3407
        if (!empty($sessionId)) {
3408
            if (COURSEMANAGER == $status) {
3409
                // Teacher of course or teacher inside session
3410
                $whereConditions = " AND (cru.status = ".COURSEMANAGER." OR srcru.status = ".SessionEntity::COURSE_COACH.") ";
3411
            }
3412
            $courseList = SessionManager::get_course_list_by_session_id($sessionId);
3413
            if (!empty($courseList)) {
3414
                $courseListToString = implode("','", array_keys($courseList));
3415
                $whereConditions .= " AND c.id IN ('".$courseListToString."')";
3416
            }
3417
            $tableSessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3418
            $tableSessionRelCourseRelUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3419
            $orderBy = ' ORDER BY position';
3420
            $extraInnerJoin = " INNER JOIN $tableSessionRelCourse src
3421
                                ON (c.id = src.c_id AND src.session_id = $sessionId)
3422
                                INNER JOIN $tableSessionRelCourseRelUser srcru
3423
                                ON (src.session_id = srcru.session_id AND srcru.c_id = src.c_id)
3424
                            ";
3425
        }
3426
3427
        $whereConditions .= $keywordCondition;
3428
        $sql = "$select
3429
                FROM $tbl_course c
3430
                INNER JOIN $tbl_course_rel_user cru
3431
                ON (cru.c_id = c.id)
3432
                INNER JOIN $tbl_course_rel_access_url a
3433
                ON (a.c_id = c.id)
3434
                $extraInnerJoin
3435
                WHERE
3436
                    access_url_id = ".api_get_current_access_url_id()."
3437
                    $whereConditions
3438
                $orderBy
3439
                ";
3440
        if (isset($from) && isset($limit)) {
3441
            $from = intval($from);
3442
            $limit = intval($limit);
3443
            $sql .= " LIMIT $from, $limit";
3444
        }
3445
3446
        $result = Database::query($sql);
3447
3448
        if ($getCount) {
3449
            $row = Database::fetch_array($result);
3450
3451
            return $row['count'];
3452
        }
3453
3454
        $courses = [];
3455
        if (Database::num_rows($result) > 0) {
3456
            while ($row = Database::fetch_array($result)) {
3457
                $courses[$row['code']] = $row;
3458
            }
3459
        }
3460
3461
        return $courses;
3462
    }
3463
3464
    /**
3465
     * check if a course is special (autoregister).
3466
     *
3467
     * @param int $courseId
3468
     *
3469
     * @return bool
3470
     */
3471
    public static function isSpecialCourse($courseId)
3472
    {
3473
        $extraFieldValue = new ExtraFieldValue('course');
3474
        $result = $extraFieldValue->get_values_by_handler_and_field_variable(
3475
            $courseId,
3476
            'special_course'
3477
        );
3478
3479
        if (!empty($result)) {
3480
            if (1 == $result['field_value']) {
3481
                return true;
3482
            }
3483
        }
3484
3485
        return false;
3486
    }
3487
3488
    /**
3489
     * Display special courses (and only these) as several HTML divs of class userportal-course-item.
3490
     *
3491
     * Special courses are courses that stick on top of the list and are "auto-registerable"
3492
     * in the sense that any user clicking them is registered as a student
3493
     *
3494
     * @param int  $user_id                          User id
3495
     * @param bool $load_dirs                        Whether to show the document quick-loader or not
3496
     * @param bool $useUserLanguageFilterIfAvailable
3497
     *
3498
     * @return array
3499
     */
3500
    public static function returnSpecialCourses(
3501
        $user_id,
3502
        $load_dirs = false,
3503
        $useUserLanguageFilterIfAvailable = true
3504
    ) {
3505
        $user_id = (int) $user_id;
3506
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
3507
        $specialCourseList = self::get_special_course_list();
3508
3509
        if (empty($specialCourseList)) {
3510
            return [];
3511
        }
3512
3513
        // Filter by language
3514
        $languageCondition = '';
3515
        $onlyInUserLanguage = ('true' === api_get_setting('course.my_courses_show_courses_in_user_language_only'));
3516
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
3517
            $userInfo = api_get_user_info(api_get_user_id());
3518
            if (!empty($userInfo['language'])) {
3519
                $languageCondition = " AND course_language = '".$userInfo['language']."' ";
3520
            }
3521
        }
3522
3523
        $sql = "SELECT
3524
                    id,
3525
                    code,
3526
                    subscribe subscr,
3527
                    unsubscribe unsubscr
3528
                FROM $table
3529
                WHERE
3530
                    id IN ('".implode("','", $specialCourseList)."')
3531
                    $languageCondition
3532
                GROUP BY code";
3533
3534
        $rs_special_course = Database::query($sql);
3535
        $number_of_courses = Database::num_rows($rs_special_course);
3536
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
3537
3538
        $courseList = [];
3539
        if ($number_of_courses > 0) {
3540
            while ($course = Database::fetch_array($rs_special_course)) {
3541
                $course_info = api_get_course_info($course['code']);
3542
                $courseId = $course['id'];
3543
                if (Course::HIDDEN == $course_info['visibility']) {
3544
                    continue;
3545
                }
3546
3547
                $params = [];
3548
                $params['c_id'] = $courseId;
3549
                //Param (course_code) needed to get the student info in page "My courses"
3550
                $params['course_code'] = $course['code'];
3551
                $params['code'] = $course['code'];
3552
                // Get notifications.
3553
                $course_info['id_session'] = null;
3554
                $courseUserInfo = self::getUserCourseInfo($user_id, $courseId);
3555
3556
                if (empty($courseUserInfo)) {
3557
                    $course_info['status'] = STUDENT;
3558
                } else {
3559
                    $course_info['status'] = $courseUserInfo['status'];
3560
                }
3561
3562
                $params['edit_actions'] = '';
3563
                $params['document'] = '';
3564
                if (api_is_platform_admin()) {
3565
                    $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'];
3566
                    if ($load_dirs) {
3567
                        $params['document'] = '<a id="document_preview_'.$courseId.'_0" class="document_preview btn btn--secondary-outline btn-sm" href="javascript:void(0);">'
3568
                           .Display::getMdiIcon('folder-open-outline').'</a>';
3569
                        $params['document'] .= Display::div('', ['id' => 'document_result_'.$courseId.'_0', 'class' => 'document_preview_container']);
3570
                    }
3571
                } else {
3572
                    if (Course::CLOSED != $course_info['visibility'] && $load_dirs) {
3573
                        $params['document'] = '<a id="document_preview_'.$courseId.'_0" class="document_preview btn btn--secondary-outline btn-sm" href="javascript:void(0);">'
3574
                           .Display::getMdiIcon('folder-open-outline').'</a>';
3575
                        $params['document'] .= Display::div('', ['id' => 'document_result_'.$courseId.'_0', 'class' => 'document_preview_container']);
3576
                    }
3577
                }
3578
3579
                $params['visibility'] = $course_info['visibility'];
3580
                $params['status'] = $course_info['status'];
3581
                $params['category'] = $course_info['categoryName'];
3582
                $params['category_code'] = $course_info['categoryCode'];
3583
                $params['icon'] = Display::getMdiIcon(
3584
                    ObjectIcon::PIN,
3585
                    'ch-tool-icon',
3586
                    null,
3587
                    ICON_SIZE_LARGE
3588
                );
3589
3590
                if ('true' == api_get_setting('display_coursecode_in_courselist')) {
3591
                    $params['code_course'] = '('.$course_info['visual_code'].')';
3592
                }
3593
3594
                $params['title'] = $course_info['title'];
3595
                $params['title_cut'] = $course_info['title'];
3596
                $params['link'] = $course_info['course_public_url'].'?sid=0&autoreg=1';
3597
                if ('true' === api_get_setting('display_teacher_in_courselist')) {
3598
                    $params['teachers'] = self::getTeachersFromCourse(
3599
                        $courseId,
3600
                        true
3601
                    );
3602
                }
3603
3604
                $params['extrafields'] = CourseManager::getExtraFieldsToBePresented($course_info['real_id']);
3605
3606
                if ('true' === $showCustomIcon) {
3607
                    $params['thumbnails'] = $course_info['course_image'];
3608
                    $params['image'] = $course_info['course_image_large'];
3609
                }
3610
3611
                $params['is_special_course'] = true;
3612
                $courseList[] = $params;
3613
            }
3614
        }
3615
3616
        return $courseList;
3617
    }
3618
3619
    /**
3620
     *  Display courses inside a category (without special courses) as HTML dics of
3621
     *  class userportal-course-item.
3622
     *
3623
     * @param int  $user_category_id                 User category id
3624
     * @param bool $load_dirs                        Whether to show the document quick-loader or not
3625
     * @param int  $user_id
3626
     * @param bool $useUserLanguageFilterIfAvailable
3627
     *
3628
     * @return array
3629
     */
3630
    public static function returnCoursesCategories(
3631
        $user_category_id,
3632
        $load_dirs = false,
3633
        $user_id = 0,
3634
        $useUserLanguageFilterIfAvailable = true
3635
    ) {
3636
        $user_id = $user_id ? (int) $user_id : api_get_user_id();
3637
        $user_category_id = (int) $user_category_id;
3638
3639
        // Table definitions
3640
        $TABLECOURS = Database::get_main_table(TABLE_MAIN_COURSE);
3641
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3642
        $TABLE_ACCESS_URL_REL_COURSE = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3643
        $current_url_id = api_get_current_access_url_id();
3644
3645
        // Get course list auto-register
3646
        $special_course_list = self::get_special_course_list();
3647
        $without_special_courses = '';
3648
        if (!empty($special_course_list)) {
3649
            $without_special_courses = ' AND course.id NOT IN ("'.implode('","', $special_course_list).'")';
3650
        }
3651
3652
        $userCategoryCondition = " (course_rel_user.user_course_cat = $user_category_id) ";
3653
        if (empty($user_category_id)) {
3654
            $userCategoryCondition = ' (course_rel_user.user_course_cat = 0 OR course_rel_user.user_course_cat IS NULL) ';
3655
        }
3656
3657
        $languageCondition = '';
3658
        $onlyInUserLanguage = ('true' === api_get_setting('course.my_courses_show_courses_in_user_language_only'));
3659
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
3660
            $userInfo = api_get_user_info(api_get_user_id());
3661
            if (!empty($userInfo['language'])) {
3662
                $languageCondition = " AND course.course_language = '".$userInfo['language']."' ";
3663
            }
3664
        }
3665
3666
        $sql = "SELECT DISTINCT
3667
                    course.id,
3668
                    course_rel_user.status status,
3669
                    course.code as course_code,
3670
                    user_course_cat,
3671
                    course_rel_user.sort
3672
                FROM $TABLECOURS course
3673
                INNER JOIN $TABLECOURSUSER course_rel_user
3674
                ON (course.id = course_rel_user.c_id)
3675
                INNER JOIN $TABLE_ACCESS_URL_REL_COURSE url
3676
                ON (url.c_id = course.id)
3677
                WHERE
3678
                    course_rel_user.user_id = $user_id AND
3679
                    $userCategoryCondition
3680
                    $without_special_courses
3681
                    $languageCondition
3682
                ";
3683
        // If multiple URL access mode is enabled, only fetch courses
3684
        // corresponding to the current URL.
3685
        if (api_get_multiple_access_url() && -1 != $current_url_id) {
3686
            $sql .= " AND access_url_id = $current_url_id";
3687
        }
3688
        // Use user's classification for courses (if any).
3689
        $sql .= ' ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC';
3690
        $result = Database::query($sql);
3691
3692
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
3693
        // Browse through all courses.
3694
        $courseAdded = [];
3695
        $courseList = [];
3696
3697
        while ($row = Database::fetch_array($result)) {
3698
            $course_info = api_get_course_info_by_id($row['id']);
3699
            if (empty($course_info)) {
3700
                continue;
3701
            }
3702
3703
            if (isset($course_info['visibility']) &&
3704
                Course::HIDDEN == $course_info['visibility']
3705
            ) {
3706
                continue;
3707
            }
3708
3709
            // Skip if already in list
3710
            if (in_array($course_info['real_id'], $courseAdded)) {
3711
                continue;
3712
            }
3713
            $course_info['id_session'] = null;
3714
            $course_info['status'] = $row['status'];
3715
            $iconName = basename($course_info['course_image']);
3716
3717
            $params = [];
3718
            //Param (course_code) needed to get the student process
3719
            $params['course_code'] = $row['course_code'];
3720
            $params['code'] = $row['course_code'];
3721
3722
            if ('true' === $showCustomIcon && 'course.png' != $iconName) {
3723
                $params['thumbnails'] = $course_info['course_image'];
3724
                $params['image'] = $course_info['course_image_large'];
3725
            }
3726
3727
            $thumbnails = null;
3728
            $image = null;
3729
            if ('true' === $showCustomIcon && 'course.png' != $iconName) {
3730
                $thumbnails = $course_info['course_image'];
3731
                $image = $course_info['course_image_large'];
3732
            } else {
3733
                $image = Display::return_icon(
3734
                    'session_default.png',
3735
                    null,
3736
                    null,
3737
                    null,
3738
                    null,
3739
                    true
3740
                );
3741
            }
3742
3743
            $params['course_id'] = $course_info['real_id'];
3744
            $params['edit_actions'] = '';
3745
            $params['document'] = '';
3746
            if (api_is_platform_admin()) {
3747
                $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course_info['real_id'];
3748
                if ($load_dirs) {
3749
                    $params['document'] = '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview btn btn--plain btn-sm" href="javascript:void(0);">'
3750
                               .Display::getMdiIcon('folder-open-outline').'</a>';
3751
                    $params['document'] .= Display::div(
3752
                        '',
3753
                        [
3754
                            'id' => 'document_result_'.$course_info['real_id'].'_0',
3755
                            'class' => 'document_preview_container',
3756
                        ]
3757
                    );
3758
                }
3759
            }
3760
            if ($load_dirs) {
3761
                $params['document'] = '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview btn btn--plain btn-sm" href="javascript:void(0);">'
3762
                    .Display::getMdiIcon('folder-open-outline').'</a>';
3763
                $params['document'] .= Display::div(
3764
                    '',
3765
                    [
3766
                        'id' => 'document_result_'.$course_info['real_id'].'_0',
3767
                        'class' => 'document_preview_container',
3768
                    ]
3769
                );
3770
            }
3771
3772
            $courseUrl = $course_info['course_public_url'].'?sid=0';
3773
            $teachers = [];
3774
            if ('true' === api_get_setting('display_teacher_in_courselist')) {
3775
                $teachers = self::getTeachersFromCourse(
3776
                    $course_info['real_id'],
3777
                    true
3778
                );
3779
            }
3780
3781
            $params['status'] = $row['status'];
3782
            if ('true' === api_get_setting('display_coursecode_in_courselist')) {
3783
                $params['code_course'] = '('.$course_info['visual_code'].') ';
3784
            }
3785
3786
            $params['current_user_is_teacher'] = false;
3787
            /** @var array $teacher */
3788
            foreach ($teachers as $teacher) {
3789
                if ($teacher['id'] != $user_id) {
3790
                    continue;
3791
                }
3792
                $params['current_user_is_teacher'] = true;
3793
            }
3794
3795
            $params['visibility'] = $course_info['visibility'];
3796
            $params['link'] = $courseUrl;
3797
            $params['thumbnails'] = $thumbnails;
3798
            $params['image'] = $image;
3799
            $params['title'] = $course_info['title'];
3800
            $params['title_cut'] = $params['title'];
3801
            $params['category'] = $course_info['categoryName'];
3802
            $params['category_code'] = $course_info['categoryCode'];
3803
            $params['teachers'] = $teachers;
3804
            $params['extrafields'] = CourseManager::getExtraFieldsToBePresented($course_info['real_id']);
3805
            $params['real_id'] = $course_info['real_id'];
3806
3807
            if ('true' === api_get_setting('course.enable_unsubscribe_button_on_my_course_page')
3808
                && '1' === $course_info['unsubscribe']
3809
            ) {
3810
                $params['unregister_button'] = CoursesAndSessionsCatalog::return_unregister_button(
3811
                    $course_info,
3812
                    Security::get_existing_token(),
3813
                    '',
3814
                    ''
3815
                );
3816
            }
3817
3818
            $courseAdded[] = $course_info['real_id'];
3819
            $courseList[] = $params;
3820
        }
3821
3822
        return $courseList;
3823
    }
3824
3825
    /**
3826
     * Get the course id based on the original id and field name in the extra fields.
3827
     * Returns 0 if course was not found.
3828
     *
3829
     * @param string $value    Original course code
3830
     * @param string $variable Original field name
3831
     *
3832
     * @return array
3833
     */
3834
    public static function getCourseInfoFromOriginalId($value, $variable)
3835
    {
3836
        $extraFieldValue = new ExtraFieldValue('course');
3837
        $result = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
3838
            $variable,
3839
            $value
3840
        );
3841
3842
        if (!empty($result)) {
3843
            return api_get_course_info_by_id($result['item_id']);
3844
        }
3845
3846
        return [];
3847
    }
3848
3849
    /**
3850
     * Display code for one specific course a logged in user is subscribed to.
3851
     * Shows a link to the course, what's new icons...
3852
     *
3853
     * $my_course['d'] - course directory
3854
     * $my_course['i'] - course title
3855
     * $my_course['c'] - visual course code
3856
     * $my_course['k']  - system course code
3857
     *
3858
     * @param   array       Course details
3859
     * @param   int     Session ID
3860
     * @param   string      CSS class to apply to course entry
3861
     * @param   bool     Whether the session is supposedly accessible now
3862
     * (not in the case it has passed and is in invisible/unaccessible mode)
3863
     * @param bool      Whether to show the document quick-loader or not
3864
     *
3865
     * @return string The HTML to be printed for the course entry
3866
     *
3867
     * @version 1.0.3
3868
     *
3869
     * @todo refactor into different functions for database calls | logic | display
3870
     * @todo replace single-character $my_course['d'] indices
3871
     * @todo move code for what's new icons to a separate function to clear things up
3872
     * @todo add a parameter user_id so that it is possible to show the
3873
     * courselist of other users (=generalisation).
3874
     * This will prevent having to write a new function for this.
3875
     */
3876
    public static function get_logged_user_course_html(
3877
        $course,
3878
        $session_id = 0,
3879
        $class = 'courses',
3880
        $session_accessible = true,
3881
        $load_dirs = false
3882
    ) {
3883
        $now = date('Y-m-d h:i:s');
3884
        $user_id = api_get_user_id();
3885
        $course_info = api_get_course_info_by_id($course['real_id']);
3886
        $course_visibility = (int) $course_info['visibility'];
3887
        $allowUnsubscribe = ('true' === api_get_setting('course.enable_unsubscribe_button_on_my_course_page'));
3888
3889
        if (Course::HIDDEN === $course_visibility) {
3890
            return '';
3891
        }
3892
3893
        $sessionInfo = [];
3894
        if (!empty($session_id)) {
3895
            $sessionInfo = api_get_session_info($session_id);
3896
        }
3897
        $userInCourseStatus = self::getUserInCourseStatus($user_id, $course_info['real_id']);
3898
        $course_info['status'] = empty($session_id) ? $userInCourseStatus : STUDENT;
3899
        $course_info['id_session'] = $session_id;
3900
3901
        $is_coach = api_is_coach($session_id, $course_info['real_id']);
3902
        $isAdmin = api_is_platform_admin();
3903
3904
        // Display course entry.
3905
        // Show a hyperlink to the course, unless the course is closed and user is not course admin.
3906
        $session_url = '';
3907
        $params = [];
3908
        $params['icon'] = Display::getMdiIcon(
3909
            ObjectIcon::SESSION,
3910
            'ch-tool-icon',
3911
            null,
3912
            ICON_SIZE_LARGE
3913
        );
3914
        $params['real_id'] = $course_info['real_id'];
3915
        $params['visibility'] = $course_info['visibility'];
3916
3917
        $sessionCourseAvailable = false;
3918
        if ($session_accessible) {
3919
            if (Course::CLOSED != $course_visibility ||
3920
                COURSEMANAGER == $userInCourseStatus
3921
            ) {
3922
                if (empty($course_info['id_session'])) {
3923
                    $course_info['id_session'] = 0;
3924
                }
3925
3926
                $sessionCourseStatus = api_get_session_visibility($session_id, $course_info['real_id']);
3927
3928
                if (in_array(
3929
                    $sessionCourseStatus,
3930
                    [SESSION_VISIBLE_READ_ONLY, SESSION_VISIBLE, SESSION_AVAILABLE]
3931
                )) {
3932
                    $sessionCourseAvailable = true;
3933
                }
3934
3935
                if (COURSEMANAGER === $userInCourseStatus || $sessionCourseAvailable) {
3936
                    $session_url = $course_info['course_public_url'].'?sid='.$course_info['id_session'];
3937
                    $session_title = '<a title="'.$course_info['name'].'" href="'.$session_url.'">'.
3938
                        $course_info['name'].'</a>';
3939
                } else {
3940
                    $session_title = $course_info['name'];
3941
                }
3942
            } else {
3943
                $session_title =
3944
                    $course_info['name'].' '.
3945
                    Display::tag('span', get_lang('(the course is currently closed)'), ['class' => 'item_closed']);
3946
            }
3947
        } else {
3948
            $session_title = $course_info['name'];
3949
        }
3950
3951
        $thumbnails = null;
3952
        $image = null;
3953
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
3954
        $iconName = basename($course_info['course_image']);
3955
3956
        if ('true' === $showCustomIcon && 'course.png' != $iconName) {
3957
            $thumbnails = $course_info['course_image'];
3958
            $image = $course_info['course_image_large'];
3959
        } else {
3960
            $image = Display::return_icon(
3961
                'session_default.png',
3962
                null,
3963
                null,
3964
                null,
3965
                null,
3966
                true
3967
            );
3968
        }
3969
        $params['thumbnails'] = $thumbnails;
3970
        $params['image'] = $image;
3971
        $params['html_image'] = '';
3972
        if (!empty($thumbnails)) {
3973
            $params['html_image'] = Display::img($thumbnails, $course_info['name'], ['class' => 'img-responsive']);
3974
        } else {
3975
            $params['html_image'] = Display::getMdiIcon(
3976
                ObjectIcon::SESSION,
3977
                'ch-tool-icon img-responsive',
3978
                null,
3979
                ICON_SIZE_LARGE,
3980
                $course_info['name']
3981
            );
3982
        }
3983
        $params['link'] = $session_url;
3984
        $entityManager = Database::getManager();
3985
        /** @var SequenceResourceRepository $repo */
3986
        $repo = $entityManager->getRepository(SequenceResource::class);
3987
3988
        $sequences = $repo->getRequirements($course_info['real_id'], SequenceResource::COURSE_TYPE);
3989
        $sequenceList = $repo->checkRequirementsForUser(
3990
            $sequences,
3991
            SequenceResource::COURSE_TYPE,
3992
            $user_id,
3993
            $session_id
3994
        );
3995
        $completed = $repo->checkSequenceAreCompleted($sequenceList);
3996
        //var_dump($course_info['real_id'], $completed);
3997
        $params['completed'] = $completed;
3998
        $params['requirements'] = '';
3999
4000
        if ($isAdmin ||
4001
            COURSEMANAGER === $userInCourseStatus ||
4002
            $is_coach ||
4003
            SessionManager::sessionHasSessionAdmin($session_id, $user_id)
4004
        ) {
4005
            $params['completed'] = true;
4006
            $params['requirements'] = '';
4007
        } else {
4008
            if ($sequences && false === $completed) {
4009
                $hasRequirements = false;
4010
                foreach ($sequences as $sequence) {
4011
                    if (!empty($sequence['requirements'])) {
4012
                        $hasRequirements = true;
4013
                        break;
4014
                    }
4015
                }
4016
                if ($hasRequirements) {
4017
                    $params['requirements'] = CoursesAndSessionsCatalog::getRequirements(
4018
                    $course_info['real_id'],
4019
                    SequenceResource::COURSE_TYPE,
4020
                    false,
4021
                        false,
4022
                        $session_id
4023
                );
4024
                }
4025
            }
4026
        }
4027
4028
        $params['title'] = $session_title;
4029
        $params['name'] = $course_info['name'];
4030
        $params['edit_actions'] = '';
4031
        $params['document'] = '';
4032
        $params['category'] = $course_info['categoryName'];
4033
        if (Course::CLOSED != $course_visibility &&
4034
            false === $is_coach && $allowUnsubscribe && '1' === $course_info['unsubscribe']) {
4035
            $params['unregister_button'] =
4036
                CoursesAndSessionsCatalog::return_unregister_button(
4037
                    ['code' => $course_info['code']],
4038
                    Security::get_existing_token(),
4039
                    '',
4040
                    '',
4041
                    $session_id
4042
                );
4043
        }
4044
4045
        if (Course::CLOSED != $course_visibility &&
4046
            Course::HIDDEN != $course_visibility
4047
        ) {
4048
            if ($isAdmin) {
4049
                $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course_info['code'];
4050
                if ($load_dirs) {
4051
                    $params['document'] .= '<a
4052
                        id="document_preview_'.$course_info['real_id'].'_'.$session_id.'"
4053
                        class="document_preview btn btn--plain btn-sm"
4054
                        href="javascript:void(0);">'.
4055
                        Display::getMdiIcon('folder-open-outline').'</a>';
4056
                    $params['document'] .= Display::div('', [
4057
                        'id' => 'document_result_'.$course_info['real_id'].'_'.$session_id,
4058
                        'class' => 'document_preview_container',
4059
                    ]);
4060
                }
4061
            }
4062
        }
4063
        if ('true' === api_get_setting('display_teacher_in_courselist')) {
4064
            $teacher_list = self::getTeachersFromCourse($course_info['real_id'], true);
4065
            $course_coachs = self::get_coachs_from_course(
4066
                $session_id,
4067
                $course_info['real_id'],
4068
                true
4069
            );
4070
            $params['teachers'] = $teacher_list;
4071
4072
            if ((STUDENT == $course_info['status'] && !empty($session_id)) ||
4073
                ($is_coach && COURSEMANAGER != $course_info['status'])
4074
            ) {
4075
                $params['coaches'] = $course_coachs;
4076
            }
4077
        }
4078
        $special = isset($course['special_course']) ? true : false;
4079
        $params['title'] = $session_title;
4080
        $params['special'] = $special;
4081
        if ('true' === api_get_setting('display_coursecode_in_courselist')) {
4082
            $params['visual_code'] = '('.$course_info['visual_code'].')';
4083
        }
4084
        $params['extra'] = '';
4085
        $html = $params;
4086
4087
        $session_category_id = null;
4088
        $active = false;
4089
        if (!empty($session_id)) {
4090
            $sessionCoachName = implode(
4091
                ' - ',
4092
                SessionManager::getGeneralCoachesNamesForSession($session_id)
4093
            );
4094
4095
            $session_category_id = self::get_session_category_id_by_session_id($course_info['id_session']);
4096
4097
            if (
4098
                '0000-00-00 00:00:00' === $sessionInfo['access_start_date'] ||
4099
                empty($sessionInfo['access_start_date']) ||
4100
                '0000-00-00' === $sessionInfo['access_start_date']
4101
                ) {
4102
                $sessionInfo['dates'] = '';
4103
                if ('true' === api_get_setting('show_session_coach')) {
4104
                    $sessionInfo['coach'] = get_lang('GeneralCoach').': '.$sessionCoachName;
4105
                }
4106
                $active = true;
4107
            } else {
4108
                $sessionInfo['dates'] = ' - '.
4109
                    get_lang('From').' '.$sessionInfo['access_start_date'].' '.
4110
                    get_lang('To').' '.$sessionInfo['access_end_date'];
4111
                if ('true' === api_get_setting('show_session_coach')) {
4112
                    $sessionInfo['coach'] = get_lang('GeneralCoach').': '.$sessionCoachName;
4113
                }
4114
                $date_start = $sessionInfo['access_start_date'];
4115
                $date_end = $sessionInfo['access_end_date'];
4116
                $active = !$date_end ? ($date_start <= $now) : ($date_start <= $now && $date_end >= $now);
4117
            }
4118
        }
4119
        $user_course_category = '';
4120
        if (isset($course_info['user_course_cat'])) {
4121
            $user_course_category = $course_info['user_course_cat'];
4122
        }
4123
        $output = [
4124
                $user_course_category,
4125
                $html,
4126
                $course_info['id_session'],
4127
                $sessionInfo,
4128
                'active' => $active,
4129
                'session_category_id' => $session_category_id,
4130
            ];
4131
4132
        if (SkillModel::isAllowed($user_id, false)) {
4133
            $em = Database::getManager();
4134
            $objUser = api_get_user_entity($user_id);
4135
            $objCourse = api_get_course_entity($course['real_id']);
4136
            $objSession = api_get_session_entity($session_id);
4137
            $skill = $em->getRepository(\Chamilo\CoreBundle\Entity\Skill::class)->getLastByUser($objUser, $objCourse, $objSession);
4138
4139
            $output['skill'] = null;
4140
            if ($skill) {
4141
                $output['skill']['name'] = $skill->getTitle();
4142
                $output['skill']['icon'] = $skill->getIcon();
4143
            }
4144
        }
4145
4146
        return $output;
4147
    }
4148
4149
    /**
4150
     * @param string $source_course_code
4151
     * @param int    $source_session_id
4152
     * @param string $destination_course_code
4153
     * @param int    $destination_session_id
4154
     * @param array  $params
4155
     *
4156
     * @return bool
4157
     */
4158
    public static function copy_course(
4159
        $source_course_code,
4160
        $source_session_id,
4161
        $destination_course_code,
4162
        $destination_session_id,
4163
        $params = [],
4164
        $withBaseContent = true
4165
    ) {
4166
        $course_info = api_get_course_info($source_course_code);
4167
4168
        if (!empty($course_info)) {
4169
            $cb = new CourseBuilder('', $course_info);
4170
            $course = $cb->build($source_session_id, $source_course_code, $withBaseContent);
4171
            $restorer = new CourseRestorer($course);
4172
            $restorer->skip_content = $params;
4173
            $restorer->restore(
4174
                $destination_course_code,
4175
                $destination_session_id,
4176
                true,
4177
                $withBaseContent
4178
            );
4179
4180
            return true;
4181
        }
4182
4183
        return false;
4184
    }
4185
4186
    /**
4187
     * A simpler version of the copy_course, the function creates an empty course with an autogenerated course code.
4188
     *
4189
     * @param string $new_title new course title
4190
     * @param string source course code
4191
     * @param int source session id
4192
     * @param int destination session id
4193
     * @param array $params
4194
     * @param bool  $copySessionContent
4195
     *
4196
     * @return Course|null
4197
     */
4198
    public static function copy_course_simple(
4199
        $new_title,
4200
        $source_course_code,
4201
        $source_session_id = 0,
4202
        $destination_session_id = 0,
4203
        $params = [],
4204
        $copySessionContent = false
4205
    ) {
4206
        $source_course_info = api_get_course_info($source_course_code);
4207
        if (!empty($source_course_info)) {
4208
            $new_course_code = self::generate_nice_next_course_code($source_course_code);
4209
            if ($new_course_code) {
4210
                $newCourse = self::create_course(
4211
                    $new_title,
4212
                    $new_course_code,
4213
                    false
4214
                );
4215
                if (null !== $newCourse) {
4216
                    $result = self::copy_course(
4217
                        $source_course_code,
4218
                        $source_session_id,
4219
                        $newCourse->getCode(),
4220
                        $destination_session_id,
4221
                        $params,
4222
                        true
4223
                    );
4224
                    if ($result) {
4225
                        return $newCourse;
4226
                    }
4227
                }
4228
            }
4229
        }
4230
4231
        return false;
4232
    }
4233
4234
    /**
4235
     * Creates a new course code based in a given code.
4236
     *
4237
     * @param string    wanted code
4238
     * <code>    $wanted_code = 'curse' if there are in the DB codes like curse1 curse2 the function will return:
4239
     * course3</code> if the course code doest not exist in the DB the same course code will be returned
4240
     *
4241
     * @return string wanted unused code
4242
     */
4243
    public static function generate_nice_next_course_code($wanted_code)
4244
    {
4245
        $course_code_ok = !self::course_code_exists($wanted_code);
4246
        if (!$course_code_ok) {
4247
            $wanted_code = self::generate_course_code($wanted_code);
4248
            $table = Database::get_main_table(TABLE_MAIN_COURSE);
4249
            $wanted_code = Database::escape_string($wanted_code);
4250
            $sql = "SELECT count(id) as count
4251
                    FROM $table
4252
                    WHERE code LIKE '$wanted_code%'";
4253
            $result = Database::query($sql);
4254
            if (Database::num_rows($result) > 0) {
4255
                $row = Database::fetch_array($result);
4256
                $count = $row['count'] + 1;
4257
                $wanted_code = $wanted_code.'_'.$count;
4258
                $result = api_get_course_info($wanted_code);
4259
                if (empty($result)) {
4260
                    return $wanted_code;
4261
                }
4262
            }
4263
4264
            return false;
4265
        }
4266
4267
        return $wanted_code;
4268
    }
4269
4270
    /**
4271
     * Gets the status of the users agreement in a course course-session.
4272
     *
4273
     * @param int    $user_id
4274
     * @param string $course_code
4275
     * @param int    $session_id
4276
     *
4277
     * @return bool
4278
     */
4279
    public static function is_user_accepted_legal($user_id, $course_code, $session_id = 0)
4280
    {
4281
        $user_id = (int) $user_id;
4282
        $session_id = (int) $session_id;
4283
        $course_code = Database::escape_string($course_code);
4284
4285
        $courseInfo = api_get_course_info($course_code);
4286
        $courseId = $courseInfo['real_id'];
4287
4288
        // Course legal
4289
        $enabled = api_get_plugin_setting('courselegal', 'tool_enable');
4290
4291
        if ('true' == $enabled) {
4292
            require_once api_get_path(SYS_PLUGIN_PATH).'courselegal/config.php';
4293
            $plugin = CourseLegalPlugin::create();
4294
4295
            return $plugin->isUserAcceptedLegal($user_id, $course_code, $session_id);
4296
        }
4297
4298
        if (empty($session_id)) {
4299
            $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4300
            $sql = "SELECT legal_agreement FROM $table
4301
                    WHERE user_id = $user_id AND c_id = $courseId ";
4302
            $result = Database::query($sql);
4303
            if (Database::num_rows($result) > 0) {
4304
                $result = Database::fetch_array($result);
4305
                if (1 == $result['legal_agreement']) {
4306
                    return true;
4307
                }
4308
            }
4309
4310
            return false;
4311
        } else {
4312
            $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4313
            $sql = "SELECT legal_agreement FROM $table
4314
                    WHERE user_id = $user_id AND c_id = $courseId AND session_id = $session_id";
4315
            $result = Database::query($sql);
4316
            if (Database::num_rows($result) > 0) {
4317
                $result = Database::fetch_array($result);
4318
                if (1 == $result['legal_agreement']) {
4319
                    return true;
4320
                }
4321
            }
4322
4323
            return false;
4324
        }
4325
    }
4326
4327
    /**
4328
     * Saves the user-course legal agreement.
4329
     *
4330
     * @param   int user id
4331
     * @param   string course code
4332
     * @param   int session id
4333
     *
4334
     * @return bool
4335
     */
4336
    public static function save_user_legal($user_id, $courseInfo, $session_id = 0)
4337
    {
4338
        if (empty($courseInfo)) {
4339
            return false;
4340
        }
4341
        $course_code = $courseInfo['code'];
4342
4343
        // Course plugin legal
4344
        $enabled = api_get_plugin_setting('courselegal', 'tool_enable');
4345
        if ('true' == $enabled) {
4346
            require_once api_get_path(SYS_PLUGIN_PATH).'courselegal/config.php';
4347
            $plugin = CourseLegalPlugin::create();
4348
4349
            return $plugin->saveUserLegal($user_id, $course_code, $session_id);
4350
        }
4351
4352
        $user_id = (int) $user_id;
4353
        $session_id = (int) $session_id;
4354
        $courseId = $courseInfo['real_id'];
4355
4356
        if (empty($session_id)) {
4357
            $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4358
            $sql = "UPDATE $table SET legal_agreement = '1'
4359
                    WHERE user_id = $user_id AND c_id  = $courseId ";
4360
            Database::query($sql);
4361
        } else {
4362
            $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4363
            $sql = "UPDATE  $table SET legal_agreement = '1'
4364
                    WHERE user_id = $user_id AND c_id = $courseId AND session_id = $session_id";
4365
            Database::query($sql);
4366
        }
4367
4368
        return true;
4369
    }
4370
4371
    /**
4372
     * @param int $user_id
4373
     * @param int $course_id
4374
     * @param int $session_id
4375
     * @param int $url_id
4376
     *
4377
     * @return bool
4378
     */
4379
    public static function get_user_course_vote($user_id, $course_id, $session_id = 0, $url_id = 0)
4380
    {
4381
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4382
        $session_id = !isset($session_id) ? api_get_session_id() : intval($session_id);
4383
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4384
        $user_id = intval($user_id);
4385
4386
        if (empty($user_id)) {
4387
            return false;
4388
        }
4389
4390
        $params = [
4391
            'user_id' => $user_id,
4392
            'c_id' => $course_id,
4393
            'session_id' => $session_id,
4394
            'url_id' => $url_id,
4395
        ];
4396
4397
        $result = Database::select(
4398
            'vote',
4399
            $table_user_course_vote,
4400
            [
4401
                'where' => [
4402
                    'user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params,
4403
                ],
4404
            ],
4405
            'first'
4406
        );
4407
        if (!empty($result)) {
4408
            return $result['vote'];
4409
        }
4410
4411
        return false;
4412
    }
4413
4414
    /**
4415
     * @param int $course_id
4416
     * @param int $session_id
4417
     * @param int $url_id
4418
     *
4419
     * @return array
4420
     */
4421
    public static function get_course_ranking(
4422
        $course_id,
4423
        $session_id = 0,
4424
        $url_id = 0
4425
    ) {
4426
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4427
4428
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4429
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4430
        $now = api_get_utc_datetime();
4431
4432
        $params = [
4433
            'c_id' => $course_id,
4434
            'session_id' => $session_id,
4435
            'url_id' => $url_id,
4436
            'creation_date' => $now,
4437
        ];
4438
4439
        $result = Database::select(
4440
            'c_id, accesses, total_score, users',
4441
            $table_course_ranking,
4442
            ['where' => ['c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4443
            'first'
4444
        );
4445
4446
        $point_average_in_percentage = 0;
4447
        $point_average_in_star = 0;
4448
        $users_who_voted = 0;
4449
4450
        if (!empty($result['users'])) {
4451
            $users_who_voted = $result['users'];
4452
            $point_average_in_percentage = round($result['total_score'] / $result['users'] * 100 / 5, 2);
4453
            $point_average_in_star = round($result['total_score'] / $result['users'], 1);
4454
        }
4455
4456
        $result['user_vote'] = false;
4457
        if (!api_is_anonymous()) {
4458
            $result['user_vote'] = self::get_user_course_vote(api_get_user_id(), $course_id, $session_id, $url_id);
4459
        }
4460
4461
        $result['point_average'] = $point_average_in_percentage;
4462
        $result['point_average_star'] = $point_average_in_star;
4463
        $result['users_who_voted'] = $users_who_voted;
4464
4465
        return $result;
4466
    }
4467
4468
    /**
4469
     * Updates the course ranking.
4470
     *
4471
     * @param int   course id
4472
     * @param int $session_id
4473
     * @param int    url id
4474
     * @param $points_to_add
4475
     * @param bool $add_access
4476
     * @param bool $add_user
4477
     *
4478
     * @return array
4479
     */
4480
    public static function update_course_ranking(
4481
        $course_id = 0,
4482
        $session_id = 0,
4483
        $url_id = 0,
4484
        $points_to_add = null,
4485
        $add_access = true,
4486
        $add_user = true
4487
    ) {
4488
        // Course catalog stats modifications see #4191
4489
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4490
        $now = api_get_utc_datetime();
4491
        $course_id = empty($course_id) ? api_get_course_int_id() : intval($course_id);
4492
        $session_id = empty($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
4495
        $params = [
4496
            'c_id' => $course_id,
4497
            'session_id' => $session_id,
4498
            'url_id' => $url_id,
4499
            'creation_date' => $now,
4500
            'total_score' => 0,
4501
            'users' => 0,
4502
        ];
4503
4504
        $result = Database::select(
4505
            'id, accesses, total_score, users',
4506
            $table_course_ranking,
4507
            ['where' => ['c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4508
            'first'
4509
        );
4510
4511
        // Problem here every time we load the courses/XXXX/index.php course home page we update the access
4512
        if (empty($result)) {
4513
            if ($add_access) {
4514
                $params['accesses'] = 1;
4515
            }
4516
            //The votes and users are empty
4517
            if (isset($points_to_add) && !empty($points_to_add)) {
4518
                $params['total_score'] = intval($points_to_add);
4519
            }
4520
            if ($add_user) {
4521
                $params['users'] = 1;
4522
            }
4523
            $result = Database::insert($table_course_ranking, $params);
4524
        } else {
4525
            $my_params = [];
4526
4527
            if ($add_access) {
4528
                $my_params['accesses'] = intval($result['accesses']) + 1;
4529
            }
4530
            if (isset($points_to_add) && !empty($points_to_add)) {
4531
                $my_params['total_score'] = $result['total_score'] + $points_to_add;
4532
            }
4533
            if ($add_user) {
4534
                $my_params['users'] = $result['users'] + 1;
4535
            }
4536
4537
            if (!empty($my_params)) {
4538
                $result = Database::update(
4539
                    $table_course_ranking,
4540
                    $my_params,
4541
                    ['c_id = ? AND session_id = ? AND url_id = ?' => $params]
4542
                );
4543
            }
4544
        }
4545
4546
        return $result;
4547
    }
4548
4549
    /**
4550
     * Add user vote to a course.
4551
     *
4552
     * @param   int user id
4553
     * @param   int vote [1..5]
4554
     * @param   int course id
4555
     * @param   int session id
4556
     * @param   int url id (access_url_id)
4557
     *
4558
     * @return false|string 'added', 'updated' or 'nothing'
4559
     */
4560
    public static function add_course_vote(
4561
        $user_id,
4562
        $vote,
4563
        $course_id,
4564
        $session_id = 0,
4565
        $url_id = 0
4566
    ) {
4567
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4568
        $course_id = empty($course_id) ? api_get_course_int_id() : intval($course_id);
4569
4570
        if (empty($course_id) || empty($user_id)) {
4571
            return false;
4572
        }
4573
4574
        if (!in_array($vote, [1, 2, 3, 4, 5])) {
4575
            return false;
4576
        }
4577
4578
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4579
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4580
        $vote = intval($vote);
4581
4582
        $params = [
4583
            'user_id' => intval($user_id),
4584
            'c_id' => $course_id,
4585
            'session_id' => $session_id,
4586
            'url_id' => $url_id,
4587
            'vote' => $vote,
4588
        ];
4589
4590
        $action_done = 'nothing';
4591
        $result = Database::select(
4592
            'id, vote',
4593
            $table_user_course_vote,
4594
            ['where' => ['user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4595
            'first'
4596
        );
4597
4598
        if (empty($result)) {
4599
            Database::insert($table_user_course_vote, $params);
4600
            $points_to_add = $vote;
4601
            $add_user = true;
4602
            $action_done = 'added';
4603
        } else {
4604
            $my_params = ['vote' => $vote];
4605
            $points_to_add = $vote - $result['vote'];
4606
            $add_user = false;
4607
4608
            Database::update(
4609
                $table_user_course_vote,
4610
                $my_params,
4611
                ['user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params]
4612
            );
4613
            $action_done = 'updated';
4614
        }
4615
4616
        // Current points
4617
        if (!empty($points_to_add)) {
4618
            self::update_course_ranking(
4619
                $course_id,
4620
                $session_id,
4621
                $url_id,
4622
                $points_to_add,
4623
                false,
4624
                $add_user
4625
            );
4626
        }
4627
4628
        return $action_done;
4629
    }
4630
4631
    /**
4632
     * Remove course ranking + user votes.
4633
     *
4634
     * @param int $course_id
4635
     * @param int $session_id
4636
     * @param int $url_id
4637
     */
4638
    public static function remove_course_ranking($course_id, $session_id, $url_id = null)
4639
    {
4640
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4641
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4642
4643
        if (!empty($course_id) && isset($session_id)) {
4644
            $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4645
            $params = [
4646
                'c_id' => $course_id,
4647
                'session_id' => $session_id,
4648
                'url_id' => $url_id,
4649
            ];
4650
            Database::delete($table_course_ranking, ['c_id = ? AND session_id = ? AND url_id = ?' => $params]);
4651
            Database::delete($table_user_course_vote, ['c_id = ? AND session_id = ? AND url_id = ?' => $params]);
4652
        }
4653
    }
4654
4655
    /**
4656
     * Returns an array with the hottest courses.
4657
     *
4658
     * @param int $days  number of days
4659
     * @param int $limit number of hottest courses
4660
     *
4661
     * @return array
4662
     */
4663
    public static function return_hot_courses($days = 30, $limit = 6)
4664
    {
4665
        if (api_is_invitee()) {
4666
            return [];
4667
        }
4668
4669
        $limit = (int) $limit;
4670
        $userId = api_get_user_id();
4671
4672
        // Getting my courses
4673
        $my_course_list = self::get_courses_list_by_user_id($userId);
4674
4675
        $codeList = [];
4676
        foreach ($my_course_list as $course) {
4677
            $codeList[$course['real_id']] = $course['real_id'];
4678
        }
4679
4680
        if (api_is_drh()) {
4681
            $courses = self::get_courses_followed_by_drh($userId);
4682
            foreach ($courses as $course) {
4683
                $codeList[$course['real_id']] = $course['real_id'];
4684
            }
4685
        }
4686
4687
        $table_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
4688
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
4689
        $table_course_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4690
        $urlId = api_get_current_access_url_id();
4691
        //$table_course_access table uses the now() and interval ...
4692
        $now = api_get_utc_datetime();
4693
        $sql = "SELECT COUNT(course_access_id) course_count, a.c_id, visibility
4694
                FROM $table_course c
4695
                INNER JOIN $table_course_access a
4696
                ON (c.id = a.c_id)
4697
                INNER JOIN $table_course_url u
4698
                ON u.c_id = c.id
4699
                WHERE
4700
                    u.access_url_id = $urlId AND
4701
                    login_course_date <= '$now' AND
4702
                    login_course_date > DATE_SUB('$now', INTERVAL $days DAY) AND
4703
                    visibility <> ".Course::CLOSED." AND
4704
                    visibility <> ".Course::HIDDEN."
4705
                GROUP BY a.c_id
4706
                ORDER BY course_count DESC
4707
                LIMIT $limit
4708
            ";
4709
4710
        $result = Database::query($sql);
4711
        $courses = [];
4712
        if (Database::num_rows($result)) {
4713
            $courses = Database::store_result($result, 'ASSOC');
4714
            $courses = self::processHotCourseItem($courses, $codeList);
4715
        }
4716
4717
        return $courses;
4718
    }
4719
4720
    /**
4721
     * Returns an array with the "hand picked" popular courses.
4722
     * Courses only appear in this list if their extra field 'popular_courses'
4723
     * has been selected in the admin page of the course.
4724
     *
4725
     * @return array
4726
     */
4727
    public static function returnPopularCoursesHandPicked()
4728
    {
4729
        if (api_is_invitee()) {
4730
            return [];
4731
        }
4732
4733
        $userId = api_get_user_id();
4734
4735
        // Getting my courses
4736
        $my_course_list = self::get_courses_list_by_user_id($userId);
4737
4738
        $codeList = [];
4739
        foreach ($my_course_list as $course) {
4740
            $codeList[$course['real_id']] = $course['real_id'];
4741
        }
4742
4743
        if (api_is_drh()) {
4744
            $courses = self::get_courses_followed_by_drh($userId);
4745
            foreach ($courses as $course) {
4746
                $codeList[$course['real_id']] = $course['real_id'];
4747
            }
4748
        }
4749
4750
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
4751
        $tbl_course_field = Database::get_main_table(TABLE_EXTRA_FIELD);
4752
        $tbl_course_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
4753
4754
        //we filter the courses from the URL
4755
        $join_access_url = $where_access_url = '';
4756
        if (api_get_multiple_access_url()) {
4757
            $access_url_id = api_get_current_access_url_id();
4758
            if (-1 != $access_url_id) {
4759
                $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4760
                $join_access_url = "LEFT JOIN $tbl_url_course url_rel_course
4761
                ON url_rel_course.c_id = tcfv.item_id ";
4762
                $where_access_url = " AND access_url_id = $access_url_id ";
4763
            }
4764
        }
4765
4766
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
4767
4768
        // get course list auto-register
4769
        $sql = "SELECT DISTINCT(c.id) AS c_id
4770
                FROM $tbl_course_field_value tcfv
4771
                INNER JOIN $tbl_course_field tcf
4772
                ON tcfv.field_id =  tcf.id $join_access_url
4773
                INNER JOIN $courseTable c
4774
                ON (c.id = tcfv.item_id)
4775
                WHERE
4776
                    tcf.item_type = $extraFieldType AND
4777
                    tcf.variable = 'popular_courses' AND
4778
                    tcfv.field_value = 1 AND
4779
                    visibility <> ".Course::CLOSED." AND
4780
                    visibility <> ".Course::HIDDEN." $where_access_url";
4781
4782
        $result = Database::query($sql);
4783
        $courses = [];
4784
        if (Database::num_rows($result)) {
4785
            $courses = Database::store_result($result, 'ASSOC');
4786
            $courses = self::processHotCourseItem($courses, $codeList);
4787
        }
4788
4789
        return $courses;
4790
    }
4791
4792
    /**
4793
     * @param array $courses
4794
     * @param array $codeList
4795
     *
4796
     * @return mixed
4797
     */
4798
    public static function processHotCourseItem($courses, $codeList = [])
4799
    {
4800
        $hotCourses = [];
4801
        $ajax_url = api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=add_course_vote';
4802
        $stok = Security::get_existing_token();
4803
        $user_id = api_get_user_id();
4804
4805
        foreach ($courses as $courseId) {
4806
            $course_info = api_get_course_info_by_id($courseId['c_id']);
4807
            $courseCode = $course_info['code'];
4808
            $categoryCode = !empty($course_info['categoryCode']) ? $course_info['categoryCode'] : "";
4809
            $my_course = $course_info;
4810
            $my_course['go_to_course_button'] = '';
4811
            $my_course['register_button'] = '';
4812
4813
            $access_link = self::get_access_link_by_user(
4814
                $user_id,
4815
                $course_info,
4816
                $codeList
4817
            );
4818
4819
            $userRegisteredInCourse = self::is_user_subscribed_in_course($user_id, $course_info['code']);
4820
            $userRegisteredInCourseAsTeacher = self::isCourseTeacher($user_id, $courseId['c_id']);
4821
            $userRegistered = $userRegisteredInCourse && $userRegisteredInCourseAsTeacher;
4822
            $my_course['is_course_student'] = $userRegisteredInCourse;
4823
            $my_course['is_course_teacher'] = $userRegisteredInCourseAsTeacher;
4824
            $my_course['is_registered'] = $userRegistered;
4825
            $my_course['title_cut'] = cut($course_info['title'], 45);
4826
4827
            // Course visibility
4828
            if ($access_link && in_array('register', $access_link)) {
4829
                $my_course['register_button'] = Display::url(
4830
                    get_lang('Subscribe').' '.
4831
                    Display::getMdiIcon('login'),
4832
                    api_get_path(WEB_COURSE_PATH).$course_info['path'].
4833
                     '/index.php?action=subscribe&sec_token='.$stok,
4834
                    [
4835
                        'class' => 'btn btn--success btn-sm',
4836
                        'title' => get_lang('Subscribe'),
4837
                        'aria-label' => get_lang('Subscribe'),
4838
                    ]
4839
                );
4840
            }
4841
4842
            if ($access_link && in_array('enter', $access_link) ||
4843
                Course::OPEN_WORLD == $course_info['visibility']
4844
            ) {
4845
                $my_course['go_to_course_button'] = Display::url(
4846
                    get_lang('Go to the course').' '.
4847
                    Display::getMdiIcon('share'),
4848
                    api_get_path(WEB_COURSE_PATH).$course_info['path'].'/index.php',
4849
                    [
4850
                        'class' => 'btn btn--plain btn-sm',
4851
                        'title' => get_lang('Go to the course'),
4852
                        'aria-label' => get_lang('Go to the course'),
4853
                    ]
4854
                );
4855
            }
4856
4857
            if ($access_link && in_array('unsubscribe', $access_link)) {
4858
                $my_course['unsubscribe_button'] = Display::url(
4859
                    get_lang('Unsubscribe').' '.
4860
                    Display::getMdiIcon('logout'),
4861
                    api_get_path(WEB_CODE_PATH).'auth/courses.php?action=unsubscribe&unsubscribe='.$courseCode
4862
                    .'&sec_token='.$stok.'&category_code='.$categoryCode,
4863
                    [
4864
                        'class' => 'btn btn--danger btn-sm',
4865
                        'title' => get_lang('Unsubscribe'),
4866
                        'aria-label' => get_lang('Unsubscribe'),
4867
                    ]
4868
                );
4869
            }
4870
4871
            // start buycourse validation
4872
            // display the course price and buy button if the buycourses plugin is enabled and this course is configured
4873
            $plugin = BuyCoursesPlugin::create();
4874
            $isThisCourseInSale = $plugin->buyCoursesForGridCatalogValidator(
4875
                $course_info['real_id'],
4876
                BuyCoursesPlugin::PRODUCT_TYPE_COURSE
4877
            );
4878
            if ($isThisCourseInSale) {
4879
                // set the price label
4880
                $my_course['price'] = $isThisCourseInSale['html'];
4881
                // set the Buy button instead register.
4882
                if ($isThisCourseInSale['verificator'] && !empty($my_course['register_button'])) {
4883
                    $my_course['register_button'] = $plugin->returnBuyCourseButton(
4884
                        $course_info['real_id'],
4885
                        BuyCoursesPlugin::PRODUCT_TYPE_COURSE
4886
                    );
4887
                }
4888
            }
4889
            // end buycourse validation
4890
4891
            // Description
4892
            $my_course['description_button'] = self::returnDescriptionButton($course_info);
4893
            $my_course['teachers'] = self::getTeachersFromCourse($course_info['real_id'], true);
4894
            $point_info = self::get_course_ranking($course_info['real_id'], 0);
4895
            $my_course['rating_html'] = '';
4896
            if (('false' === api_get_setting('course.hide_course_rating'))) {
4897
                $my_course['rating_html'] = Display::return_rating_system(
4898
                    'star_'.$course_info['real_id'],
4899
                    $ajax_url.'&course_id='.$course_info['real_id'],
4900
                    $point_info
4901
                );
4902
            }
4903
            $hotCourses[] = $my_course;
4904
        }
4905
4906
        return $hotCourses;
4907
    }
4908
4909
    public function totalSubscribedUsersInCourses($urlId)
4910
    {
4911
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
4912
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4913
        $courseUsers = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4914
4915
        $urlId = (int) $urlId;
4916
4917
        $sql = "SELECT count(cu.user_id) count
4918
                FROM $courseUsers cu
4919
                INNER JOIN $table_course_rel_access_url u
4920
                ON cu.c_id = u.c_id
4921
                WHERE
4922
                    relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
4923
                    u.access_url_id = $urlId AND
4924
                    visibility <> ".Course::CLOSED." AND
4925
                    visibility <> ".Course::HIDDEN."
4926
                     ";
4927
4928
        $res = Database::query($sql);
4929
        $row = Database::fetch_array($res);
4930
4931
        return $row['count'];
4932
    }
4933
4934
    /**
4935
     * Get courses count.
4936
     *
4937
     * @param int $access_url_id Access URL ID (optional)
4938
     * @param int $visibility
4939
     *
4940
     * @return int Number of courses
4941
     */
4942
    public static function count_courses($access_url_id = null, $visibility = null)
4943
    {
4944
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
4945
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4946
        $sql = "SELECT count(c.id) FROM $table_course c";
4947
        if (!empty($access_url_id) && $access_url_id == intval($access_url_id)) {
4948
            $sql .= ", $table_course_rel_access_url u
4949
                    WHERE c.id = u.c_id AND u.access_url_id = $access_url_id";
4950
            if (!empty($visibility)) {
4951
                $visibility = intval($visibility);
4952
                $sql .= " AND visibility = $visibility ";
4953
            }
4954
        } else {
4955
            if (!empty($visibility)) {
4956
                $visibility = intval($visibility);
4957
                $sql .= " WHERE visibility = $visibility ";
4958
            }
4959
        }
4960
4961
        $res = Database::query($sql);
4962
        $row = Database::fetch_row($res);
4963
4964
        return $row[0];
4965
    }
4966
4967
    /**
4968
     * Get active courses count.
4969
     * Active = all courses except the ones with hidden visibility.
4970
     *
4971
     * @param int $urlId Access URL ID (optional)
4972
     *
4973
     * @return int Number of courses
4974
     */
4975
    public static function countActiveCourses($urlId = null)
4976
    {
4977
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
4978
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4979
        $sql = "SELECT count(c.id) FROM $table_course c";
4980
        if (!empty($urlId)) {
4981
            $urlId = (int) $urlId;
4982
            $sql .= ", $table_course_rel_access_url u
4983
                    WHERE
4984
                        c.id = u.c_id AND
4985
                        u.access_url_id = $urlId AND
4986
                        visibility <> ".Course::HIDDEN;
4987
        } else {
4988
            $sql .= " WHERE visibility <> ".Course::HIDDEN;
4989
        }
4990
        $res = Database::query($sql);
4991
        $row = Database::fetch_row($res);
4992
4993
        return $row[0];
4994
    }
4995
4996
    /**
4997
     * Returns the SQL conditions to filter course only visible by the user in the catalogue.
4998
     *
4999
     * @param string $courseTableAlias Alias of the course table
5000
     * @param bool   $hideClosed       Whether to hide closed and hidden courses
5001
     * @param bool   $checkHidePrivate
5002
     *
5003
     * @return string SQL conditions
5004
     */
5005
    public static function getCourseVisibilitySQLCondition($courseTableAlias, $hideClosed = false, $checkHidePrivate = true)
5006
    {
5007
        $visibilityCondition = '';
5008
        if ($checkHidePrivate) {
5009
            $hidePrivateSetting = api_get_setting('course_catalog_hide_private');
5010
            if ('true' === $hidePrivateSetting) {
5011
                $visibilityCondition .= " AND $courseTableAlias.visibility <> ".Course::REGISTERED;
5012
            }
5013
        }
5014
        if ($hideClosed) {
5015
            $visibilityCondition .= " AND $courseTableAlias.visibility NOT IN (".Course::CLOSED.','.Course::HIDDEN.')';
5016
        }
5017
5018
        // Check if course have users allowed to see it in the catalogue, then show only if current user is allowed to see it
5019
        $currentUserId = api_get_user_id();
5020
        $restrictedCourses = self::getCatalogCourseList(true);
5021
        $allowedCoursesToCurrentUser = self::getCatalogCourseList(true, $currentUserId);
5022
        if (!empty($restrictedCourses)) {
5023
            $visibilityCondition .= ' AND ('.$courseTableAlias.'.code NOT IN ("'.implode('","', $restrictedCourses).'")';
5024
            $visibilityCondition .= ' OR '.$courseTableAlias.'.code IN ("'.implode('","', $allowedCoursesToCurrentUser).'"))';
5025
        }
5026
5027
        // Check if course have users denied to see it in the catalogue, then show only if current user is not denied to see it
5028
        $restrictedCourses = self::getCatalogCourseList(false);
5029
        $notAllowedCoursesToCurrentUser = self::getCatalogCourseList(false, $currentUserId);
5030
        if (!empty($restrictedCourses)) {
5031
            $visibilityCondition .= ' AND ('.$courseTableAlias.'.code NOT IN ("'.implode('","', $restrictedCourses).'")';
5032
            $visibilityCondition .= ' OR '.$courseTableAlias.'.code NOT IN ("'.implode('","', $notAllowedCoursesToCurrentUser).'"))';
5033
        }
5034
5035
        return $visibilityCondition;
5036
    }
5037
5038
    /**
5039
     * Return a link to go to the course, validating the visibility of the
5040
     * course and the user status.
5041
     *
5042
     * @param int $uid User ID
5043
     * @param array Course details array
5044
     * @param array  List of courses to which the user is subscribed (if not provided, will be generated)
5045
     *
5046
     * @return mixed 'enter' for a link to go to the course or 'register' for a link to subscribe, or false if no access
5047
     */
5048
    public static function get_access_link_by_user($uid, $course, $user_courses = [])
5049
    {
5050
        if (empty($uid) || empty($course)) {
5051
            return false;
5052
        }
5053
5054
        if (empty($user_courses)) {
5055
            // get the array of courses to which the user is subscribed
5056
            $user_courses = self::get_courses_list_by_user_id($uid);
5057
            foreach ($user_courses as $k => $v) {
5058
                $user_courses[$k] = $v['real_id'];
5059
            }
5060
        }
5061
5062
        if (!isset($course['real_id']) && empty($course['real_id'])) {
5063
            $course = api_get_course_info($course['code']);
5064
        }
5065
5066
        if (Course::HIDDEN == $course['visibility']) {
5067
            return [];
5068
        }
5069
5070
        $is_admin = api_is_platform_admin_by_id($uid);
5071
        $options = [];
5072
        // Register button
5073
        if (!api_is_anonymous($uid) &&
5074
            (
5075
            (Course::OPEN_WORLD == $course['visibility'] || Course::OPEN_PLATFORM == $course['visibility'])
5076
                //$course['visibility'] == Course::REGISTERED && $course['subscribe'] == SUBSCRIBE_ALLOWED
5077
            ) &&
5078
            SUBSCRIBE_ALLOWED == $course['subscribe'] &&
5079
            (!in_array($course['real_id'], $user_courses) || empty($user_courses))
5080
        ) {
5081
            $options[] = 'register';
5082
        }
5083
5084
        $isLogin = !api_is_anonymous();
5085
5086
        // Go To Course button (only if admin, if course public or if student already subscribed)
5087
        if ($is_admin ||
5088
            Course::OPEN_WORLD == $course['visibility'] && empty($course['registration_code']) ||
5089
            ($isLogin && Course::OPEN_PLATFORM == $course['visibility'] && empty($course['registration_code'])) ||
5090
            (in_array($course['real_id'], $user_courses) && Course::CLOSED != $course['visibility'])
5091
        ) {
5092
            $options[] = 'enter';
5093
        }
5094
5095
        if ($is_admin ||
5096
            Course::OPEN_WORLD == $course['visibility'] && empty($course['registration_code']) ||
5097
            ($isLogin && Course::OPEN_PLATFORM == $course['visibility'] && empty($course['registration_code'])) ||
5098
            (in_array($course['real_id'], $user_courses) && Course::CLOSED != $course['visibility'])
5099
        ) {
5100
            $options[] = 'enter';
5101
        }
5102
5103
        if (Course::HIDDEN != $course['visibility'] &&
5104
            empty($course['registration_code']) &&
5105
            UNSUBSCRIBE_ALLOWED == $course['unsubscribe'] &&
5106
            $isLogin &&
5107
            in_array($course['real_id'], $user_courses)
5108
        ) {
5109
            $options[] = 'unsubscribe';
5110
        }
5111
5112
        return $options;
5113
    }
5114
5115
    /**
5116
     * @param array          $courseInfo
5117
     * @param array          $teachers
5118
     * @param bool           $deleteTeachersNotInList
5119
     * @param bool           $editTeacherInSessions
5120
     * @param bool           $deleteSessionTeacherNotInList
5121
     * @param array          $teacherBackup
5122
     * @param Monolog\Logger $logger
5123
     *
5124
     * @return false|null
5125
     */
5126
    public static function updateTeachers(
5127
        $courseInfo,
5128
        $teachers,
5129
        $deleteTeachersNotInList = true,
5130
        $editTeacherInSessions = false,
5131
        $deleteSessionTeacherNotInList = false,
5132
        $teacherBackup = [],
5133
        $logger = null
5134
    ) {
5135
        if (!is_array($teachers)) {
5136
            $teachers = [$teachers];
5137
        }
5138
5139
        if (empty($courseInfo) || !isset($courseInfo['real_id'])) {
5140
            return false;
5141
        }
5142
5143
        $teachers = array_filter($teachers);
5144
        $courseId = $courseInfo['real_id'];
5145
        $course_code = $courseInfo['code'];
5146
5147
        $course_user_table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5148
        $alreadyAddedTeachers = self::get_teacher_list_from_course_code($course_code);
5149
5150
        if ($deleteTeachersNotInList) {
5151
            // Delete only teacher relations that doesn't match the selected teachers
5152
            $cond = null;
5153
            if (count($teachers) > 0) {
5154
                foreach ($teachers as $key) {
5155
                    $key = Database::escape_string($key);
5156
                    $cond .= " AND user_id <> '".$key."'";
5157
                }
5158
            }
5159
5160
            // Recover user categories
5161
            $sql = "SELECT * FROM $course_user_table
5162
                    WHERE c_id = $courseId AND status = 1 AND relation_type = 0 ".$cond;
5163
            $result = Database::query($sql);
5164
            if (Database::num_rows($result)) {
5165
                $teachersToDelete = Database::store_result($result, 'ASSOC');
5166
                foreach ($teachersToDelete as $data) {
5167
                    $userId = $data['user_id'];
5168
                    $teacherBackup[$userId][$course_code] = $data;
5169
                }
5170
            }
5171
5172
            $sql = "DELETE FROM $course_user_table
5173
                    WHERE c_id = $courseId AND status = 1 AND relation_type = 0 ".$cond;
5174
5175
            Database::query($sql);
5176
        }
5177
5178
        if (count($teachers) > 0) {
5179
            foreach ($teachers as $userId) {
5180
                $userId = intval($userId);
5181
                // We check if the teacher is already subscribed in this course
5182
                $sql = "SELECT 1 FROM $course_user_table
5183
                        WHERE user_id = $userId AND c_id = $courseId";
5184
                $result = Database::query($sql);
5185
                if (Database::num_rows($result)) {
5186
                    $sql = "UPDATE $course_user_table
5187
                            SET status = 1
5188
                            WHERE c_id = $courseId AND user_id = $userId ";
5189
                } else {
5190
                    $userCourseCategory = '0';
5191
                    if (isset($teacherBackup[$userId]) &&
5192
                        isset($teacherBackup[$userId][$course_code])
5193
                    ) {
5194
                        $courseUserData = $teacherBackup[$userId][$course_code];
5195
                        $userCourseCategory = $courseUserData['user_course_cat'];
5196
                        if ($logger) {
5197
                            $logger->debug("Recovering user_course_cat: $userCourseCategory");
5198
                        }
5199
                    }
5200
5201
                    $sql = "INSERT INTO $course_user_table SET
5202
                            c_id = $courseId,
5203
                            user_id = $userId,
5204
                            status = 1,
5205
                            is_tutor = 0,
5206
                            sort = 0,
5207
                            relation_type = 0,
5208
                            user_course_cat = $userCourseCategory,
5209
                            progress = 0
5210
                    ";
5211
                }
5212
                Database::query($sql);
5213
            }
5214
        }
5215
5216
        if ($editTeacherInSessions) {
5217
            $sessions = SessionManager::get_session_by_course($courseId);
5218
            if (!empty($sessions)) {
5219
                if ($logger) {
5220
                    $logger->debug("Edit teachers in sessions");
5221
                }
5222
                foreach ($sessions as $session) {
5223
                    $sessionId = $session['id'];
5224
                    // Remove old and add new
5225
                    if ($deleteSessionTeacherNotInList) {
5226
                        foreach ($teachers as $userId) {
5227
                            if ($logger) {
5228
                                $logger->debug("Set coach #$userId in session #$sessionId of course #$courseId ");
5229
                            }
5230
                            SessionManager::set_coach_to_course_session(
5231
                                $userId,
5232
                                $sessionId,
5233
                                $courseId
5234
                            );
5235
                        }
5236
5237
                        $teachersToDelete = [];
5238
                        if (!empty($alreadyAddedTeachers)) {
5239
                            $teachersToDelete = array_diff(array_keys($alreadyAddedTeachers), $teachers);
5240
                        }
5241
5242
                        if (!empty($teachersToDelete)) {
5243
                            foreach ($teachersToDelete as $userId) {
5244
                                if ($logger) {
5245
                                    $logger->debug("Delete coach #$userId in session #$sessionId of course #$courseId ");
5246
                                }
5247
                                SessionManager::set_coach_to_course_session(
5248
                                    $userId,
5249
                                    $sessionId,
5250
                                    $courseId,
5251
                                    true
5252
                                );
5253
                            }
5254
                        }
5255
                    } else {
5256
                        // Add new teachers only
5257
                        foreach ($teachers as $userId) {
5258
                            if ($logger) {
5259
                                $logger->debug("Add coach #$userId in session #$sessionId of course #$courseId ");
5260
                            }
5261
                            SessionManager::set_coach_to_course_session(
5262
                                $userId,
5263
                                $sessionId,
5264
                                $courseId
5265
                            );
5266
                        }
5267
                    }
5268
                }
5269
            }
5270
        }
5271
    }
5272
5273
    /**
5274
     * Course available settings variables see c_course_setting table.
5275
     *
5276
     * @return array
5277
     */
5278
    public static function getCourseSettingVariables(AppPlugin $appPlugin = null)
5279
    {
5280
        $pluginCourseSettings = [];
5281
        if ($appPlugin) {
5282
            $pluginCourseSettings = $appPlugin->getAllPluginCourseSettings();
5283
        }
5284
        $courseSettings = [
5285
            // Get allow_learning_path_theme from table
5286
            'allow_learning_path_theme',
5287
            // Get allow_open_chat_window from table
5288
            'allow_open_chat_window',
5289
            'allow_public_certificates',
5290
            // Get allow_user_edit_agenda from table
5291
            'allow_user_edit_agenda',
5292
            // Get allow_user_edit_announcement from table
5293
            'allow_user_edit_announcement',
5294
            // Get allow_user_image_forum from table
5295
            'allow_user_image_forum',
5296
            //Get allow show user list
5297
            'allow_user_view_user_list',
5298
            // Get course_theme from table
5299
            'course_theme',
5300
            //Get allow show user list
5301
            'display_info_advance_inside_homecourse',
5302
            'documents_default_visibility',
5303
            // Get send_mail_setting (work)from table
5304
            'email_alert_manager_on_new_doc',
5305
            // Get send_mail_setting (work)from table
5306
            'email_alert_manager_on_new_quiz',
5307
            // Get send_mail_setting (dropbox) from table
5308
            'email_alert_on_new_doc_dropbox',
5309
            'email_alert_students_on_new_homework',
5310
            // Get send_mail_setting (auth)from table
5311
            'email_alert_to_teacher_on_new_user_in_course',
5312
            'enable_lp_auto_launch',
5313
            'enable_exercise_auto_launch',
5314
            'enable_document_auto_launch',
5315
            'pdf_export_watermark_text',
5316
            'show_system_folders',
5317
            'exercise_invisible_in_session',
5318
            'enable_forum_auto_launch',
5319
            'show_course_in_user_language',
5320
            'email_to_teachers_on_new_work_feedback',
5321
            'student_delete_own_publication',
5322
            'hide_forum_notifications',
5323
            'quiz_question_limit_per_day',
5324
            'subscribe_users_to_forum_notifications',
5325
        ];
5326
5327
        $courseModels = ExerciseLib::getScoreModels();
5328
        if (!empty($courseModels)) {
5329
            $courseSettings[] = 'score_model_id';
5330
        }
5331
5332
        $allowLPReturnLink = api_get_setting('allow_lp_return_link');
5333
        if ('true' === $allowLPReturnLink) {
5334
            $courseSettings[] = 'lp_return_link';
5335
        }
5336
5337
        if (!empty($pluginCourseSettings)) {
5338
            $courseSettings = array_merge(
5339
                $courseSettings,
5340
                $pluginCourseSettings
5341
            );
5342
        }
5343
5344
        return $courseSettings;
5345
    }
5346
5347
    /**
5348
     * @param string       $variable
5349
     * @param string|array $value
5350
     * @param int          $courseId
5351
     *
5352
     * @return bool
5353
     */
5354
    public static function saveCourseConfigurationSetting($variable, $value, $courseId, AppPlugin $appPlugin = null)
5355
    {
5356
        $settingList = self::getCourseSettingVariables($appPlugin);
5357
5358
        if (!in_array($variable, $settingList)) {
5359
            return false;
5360
        }
5361
5362
        $courseSettingTable = Database::get_course_table(TABLE_COURSE_SETTING);
5363
5364
        if (is_array($value)) {
5365
            $value = implode(',', $value);
5366
        }
5367
5368
        $settingFromDatabase = self::getCourseSetting($variable, $courseId);
5369
5370
        if (!empty($settingFromDatabase)) {
5371
            // Update
5372
            Database::update(
5373
                $courseSettingTable,
5374
                ['value' => $value],
5375
                ['variable = ? AND c_id = ?' => [$variable, $courseId]]
5376
            );
5377
5378
            /*if ($settingFromDatabase['value'] != $value) {
5379
                Event::addEvent(
5380
                    LOG_COURSE_SETTINGS_CHANGED,
5381
                    $variable,
5382
                    $settingFromDatabase['value']." -> $value"
5383
                );
5384
            }*/
5385
        } else {
5386
            // Create
5387
            Database::insert(
5388
                $courseSettingTable,
5389
                [
5390
                    'title' => $variable,
5391
                    'value' => $value,
5392
                    'c_id' => $courseId,
5393
                    'variable' => $variable,
5394
                ]
5395
            );
5396
5397
            /*Event::addEvent(
5398
                LOG_COURSE_SETTINGS_CHANGED,
5399
                $variable,
5400
                $value
5401
            );*/
5402
        }
5403
5404
        return true;
5405
    }
5406
5407
    /**
5408
     * Get course setting.
5409
     *
5410
     * @param string $variable
5411
     * @param int    $courseId
5412
     *
5413
     * @return array
5414
     */
5415
    public static function getCourseSetting($variable, $courseId)
5416
    {
5417
        $courseSetting = Database::get_course_table(TABLE_COURSE_SETTING);
5418
        $courseId = (int) $courseId;
5419
        $variable = Database::escape_string($variable);
5420
        $sql = "SELECT variable, value FROM $courseSetting
5421
                WHERE c_id = $courseId AND variable = '$variable'";
5422
        $result = Database::query($sql);
5423
5424
        return Database::fetch_array($result);
5425
    }
5426
5427
    public static function saveSettingChanges($courseInfo, $params)
5428
    {
5429
        if (empty($courseInfo) || empty($params)) {
5430
            return false;
5431
        }
5432
5433
        $userId = api_get_user_id();
5434
        $now = api_get_utc_datetime();
5435
5436
        foreach ($params as $name => $value) {
5437
            $emptyValue = ' - ';
5438
            if (isset($courseInfo[$name]) && $courseInfo[$name] != $value) {
5439
                if ('' !== $courseInfo[$name]) {
5440
                    $emptyValue = $courseInfo[$name];
5441
                }
5442
5443
                $changedTo = $emptyValue.' -> '.$value;
5444
5445
                Event::addEvent(
5446
                    LOG_COURSE_SETTINGS_CHANGED,
5447
                    $name,
5448
                    $changedTo,
5449
                    $now,
5450
                    $userId,
5451
                    $courseInfo['real_id']
5452
                );
5453
            }
5454
        }
5455
5456
        return true;
5457
    }
5458
5459
    /**
5460
     * Get information from the track_e_course_access table.
5461
     *
5462
     * @param int    $courseId
5463
     * @param int    $sessionId
5464
     * @param string $startDate
5465
     * @param string $endDate
5466
     *
5467
     * @return array
5468
     */
5469
    public static function getCourseAccessPerCourseAndSession(
5470
        $courseId,
5471
        $sessionId,
5472
        $startDate,
5473
        $endDate
5474
    ) {
5475
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5476
        $courseId = (int) $courseId;
5477
        $sessionId = (int) $sessionId;
5478
        $startDate = Database::escape_string($startDate);
5479
        $endDate = Database::escape_string($endDate);
5480
5481
        $sql = "SELECT * FROM $table
5482
                WHERE
5483
                    c_id = $courseId AND
5484
                    session_id = $sessionId AND
5485
                    login_course_date BETWEEN '$startDate' AND '$endDate'
5486
                ";
5487
5488
        $result = Database::query($sql);
5489
5490
        return Database::store_result($result);
5491
    }
5492
5493
    /**
5494
     * Get login information from the track_e_course_access table, for any
5495
     * course in the given session.
5496
     *
5497
     * @param int $sessionId
5498
     * @param int $userId
5499
     *
5500
     * @return array
5501
     */
5502
    public static function getFirstCourseAccessPerSessionAndUser($sessionId, $userId)
5503
    {
5504
        $sessionId = (int) $sessionId;
5505
        $userId = (int) $userId;
5506
5507
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5508
        $sql = "SELECT * FROM $table
5509
                WHERE session_id = $sessionId AND user_id = $userId
5510
                ORDER BY login_course_date ASC
5511
                LIMIT 1";
5512
5513
        $result = Database::query($sql);
5514
        $courseAccess = [];
5515
        if (Database::num_rows($result)) {
5516
            $courseAccess = Database::fetch_assoc($result);
5517
        }
5518
5519
        return $courseAccess;
5520
    }
5521
5522
    /**
5523
     * @param int  $courseId
5524
     * @param int  $sessionId
5525
     * @param bool $getAllSessions
5526
     *
5527
     * @return mixed
5528
     */
5529
    public static function getCountForum(
5530
        $courseId,
5531
        $sessionId = 0,
5532
        $getAllSessions = false
5533
    ) {
5534
        $forum = Database::get_course_table(TABLE_FORUM);
5535
        if ($getAllSessions) {
5536
            $sql = "SELECT count(*) as count
5537
                    FROM $forum f
5538
                    WHERE f.c_id = %s";
5539
        } else {
5540
            $sql = "SELECT count(*) as count
5541
                    FROM $forum f
5542
                    WHERE f.c_id = %s and f.session_id = %s";
5543
        }
5544
5545
        $sql = sprintf($sql, intval($courseId), intval($sessionId));
5546
        $result = Database::query($sql);
5547
        $row = Database::fetch_array($result);
5548
5549
        return $row['count'];
5550
    }
5551
5552
    /**
5553
     * @param int $userId
5554
     * @param int $courseId
5555
     * @param int $sessionId
5556
     *
5557
     * @return mixed
5558
     */
5559
    public static function getCountPostInForumPerUser(
5560
        $userId,
5561
        $courseId,
5562
        $sessionId = 0
5563
    ) {
5564
        $forum = Database::get_course_table(TABLE_FORUM);
5565
        $forum_post = Database::get_course_table(TABLE_FORUM_POST);
5566
5567
        $sql = "SELECT count(distinct post_id) as count
5568
                FROM $forum_post p
5569
                INNER JOIN $forum f
5570
                ON f.forum_id = p.forum_id AND f.c_id = p.c_id
5571
                WHERE p.poster_id = %s and f.session_id = %s and p.c_id = %s";
5572
5573
        $sql = sprintf(
5574
            $sql,
5575
            intval($userId),
5576
            intval($sessionId),
5577
            intval($courseId)
5578
        );
5579
5580
        $result = Database::query($sql);
5581
        $row = Database::fetch_array($result);
5582
5583
        return $row['count'];
5584
    }
5585
5586
    /**
5587
     * @param int $userId
5588
     * @param int $courseId
5589
     * @param int $sessionId
5590
     *
5591
     * @return mixed
5592
     */
5593
    public static function getCountForumPerUser(
5594
        $userId,
5595
        $courseId,
5596
        $sessionId = 0
5597
    ) {
5598
        $forum = Database::get_course_table(TABLE_FORUM);
5599
        $forum_post = Database::get_course_table(TABLE_FORUM_POST);
5600
5601
        $sql = "SELECT count(distinct f.forum_id) as count
5602
                FROM $forum_post p
5603
                INNER JOIN $forum f
5604
                ON f.forum_id = p.forum_id AND f.c_id = p.c_id
5605
                WHERE p.poster_id = %s and f.session_id = %s and p.c_id = %s";
5606
5607
        $sql = sprintf(
5608
            $sql,
5609
            intval($userId),
5610
            intval($sessionId),
5611
            intval($courseId)
5612
        );
5613
5614
        $result = Database::query($sql);
5615
        $row = Database::fetch_array($result);
5616
5617
        return $row['count'];
5618
    }
5619
5620
    /**
5621
     * Returns the course name from a given code.
5622
     *
5623
     * @param string $code
5624
     *
5625
     * @return string
5626
     */
5627
    public static function getCourseNameFromCode($code)
5628
    {
5629
        $tbl_main_categories = Database::get_main_table(TABLE_MAIN_COURSE);
5630
        $code = Database::escape_string($code);
5631
        $sql = "SELECT title
5632
                FROM $tbl_main_categories
5633
                WHERE code = '$code'";
5634
        $result = Database::query($sql);
5635
        if ($col = Database::fetch_array($result)) {
5636
            return $col['title'];
5637
        }
5638
    }
5639
5640
    /**
5641
     * Generates a course code from a course title.
5642
     *
5643
     * @todo Such a function might be useful in other places too. It might be moved in the CourseManager class.
5644
     * @todo the function might be upgraded for avoiding code duplications (currently,
5645
     * it might suggest a code that is already in use)
5646
     *
5647
     * @param string $title A course title
5648
     *
5649
     * @return string A proposed course code
5650
     *                +
5651
     * @assert (null,null) === false
5652
     * @assert ('ABC_DEF', null) === 'ABCDEF'
5653
     * @assert ('ABC09*^[%A', null) === 'ABC09A'
5654
     */
5655
    public static function generate_course_code($title)
5656
    {
5657
        return substr(
5658
            preg_replace('/[^A-Z0-9]/', '', strtoupper(api_replace_dangerous_char($title))),
5659
            0,
5660
            self::MAX_COURSE_LENGTH_CODE
5661
        );
5662
    }
5663
5664
    /**
5665
     * this function gets all the users of the course,
5666
     * including users from linked courses.
5667
     *
5668
     * @param $filterByActive
5669
     *
5670
     * @return array
5671
     */
5672
    public static function getCourseUsers($filterByActive = null)
5673
    {
5674
        // This would return only the users from real courses:
5675
        return self::get_user_list_from_course_code(
5676
            api_get_course_id(),
5677
            api_get_session_id(),
5678
            null,
5679
            null,
5680
            null,
5681
            null,
5682
            false,
5683
            false,
5684
            [],
5685
            [],
5686
            [],
5687
            $filterByActive
5688
        );
5689
    }
5690
5691
    /**
5692
     * this function gets all the groups of the course,
5693
     * not including linked courses.
5694
     *
5695
     * @return CGroup[]
5696
     */
5697
    public static function getCourseGroups()
5698
    {
5699
        $sessionId = api_get_session_id();
5700
        $courseCode = api_get_course_id();
5701
        if (0 != $sessionId) {
5702
            $groupList = self::get_group_list_of_course(
5703
                $courseCode,
5704
                $sessionId,
5705
                1
5706
            );
5707
        } else {
5708
            $groupList = self::get_group_list_of_course(
5709
                $courseCode,
5710
                0,
5711
                1
5712
            );
5713
        }
5714
5715
        return $groupList;
5716
    }
5717
5718
    /**
5719
     * @param FormValidator $form
5720
     * @param array         $alreadySelected
5721
     *
5722
     * @return HTML_QuickForm_element
5723
     */
5724
    public static function addUserGroupMultiSelect(&$form, $alreadySelected, $addShortCut = false)
5725
    {
5726
        $userList = self::getCourseUsers(true);
5727
        $groupList = self::getCourseGroups();
5728
5729
        $array = self::buildSelectOptions(
5730
            $groupList,
5731
            $userList,
5732
            $alreadySelected
5733
        );
5734
5735
        $result = [];
5736
        foreach ($array as $content) {
5737
            $result[$content['value']] = $content['content'];
5738
        }
5739
5740
        $multiple = $form->addMultiSelect(
5741
            'users',
5742
            get_lang('Users'),
5743
            $result,
5744
            ['select_all_checkbox' => true, 'id' => 'users']
5745
        );
5746
5747
        $sessionId = api_get_session_id();
5748
        if ($addShortCut && empty($sessionId)) {
5749
            $addStudents = [];
5750
            foreach ($userList as $user) {
5751
                if (STUDENT == $user['status_rel']) {
5752
                    $addStudents[] = $user['user_id'];
5753
                }
5754
            }
5755
            if (!empty($addStudents)) {
5756
                $form->addHtml(
5757
                    '<script>
5758
                    $(function() {
5759
                        $("#add_students").on("click", function() {
5760
                            var addStudents = '.json_encode($addStudents).';
5761
                            $.each(addStudents, function( index, value ) {
5762
                                var option = $("#users option[value=\'USER:"+value+"\']");
5763
                                if (option.val()) {
5764
                                    $("#users_to").append(new Option(option.text(), option.val()))
5765
                                    option.remove();
5766
                                }
5767
                            });
5768
5769
                            return false;
5770
                        });
5771
                    });
5772
                    </script>'
5773
                );
5774
5775
                $form->addLabel(
5776
                    '',
5777
                    Display::url(get_lang('Add learners'), '#', ['id' => 'add_students', 'class' => 'btn btn--primary'])
5778
                );
5779
            }
5780
        }
5781
5782
        return $multiple;
5783
    }
5784
5785
    /**
5786
     * This function separates the users from the groups
5787
     * users have a value USER:XXX (with XXX the groups id have a value
5788
     *  GROUP:YYY (with YYY the group id).
5789
     *
5790
     * @param array $to Array of strings that define the type and id of each destination
5791
     *
5792
     * @return array Array of groups and users (each an array of IDs)
5793
     */
5794
    public static function separateUsersGroups($to)
5795
    {
5796
        $groupList = [];
5797
        $userList = [];
5798
5799
        foreach ($to as $to_item) {
5800
            if (!empty($to_item)) {
5801
                $parts = explode(':', $to_item);
5802
                $type = isset($parts[0]) ? $parts[0] : '';
5803
                $id = isset($parts[1]) ? $parts[1] : '';
5804
5805
                switch ($type) {
5806
                    case 'GROUP':
5807
                        $groupList[] = (int) $id;
5808
                        break;
5809
                    case 'USER':
5810
                        $userList[] = (int) $id;
5811
                        break;
5812
                }
5813
            }
5814
        }
5815
5816
        $send_to['groups'] = $groupList;
5817
        $send_to['users'] = $userList;
5818
5819
        return $send_to;
5820
    }
5821
5822
    /**
5823
     * Shows the form for sending a message to a specific group or user.
5824
     *
5825
     * @return HTML_QuickForm_element
5826
     */
5827
    public static function addGroupMultiSelect(FormValidator $form, CGroup $group, $to = [])
5828
    {
5829
        $groupUsers = GroupManager::get_subscribed_users($group);
5830
        $array = self::buildSelectOptions([$group], $groupUsers, $to);
5831
5832
        $result = [];
5833
        foreach ($array as $content) {
5834
            $result[$content['value']] = $content['content'];
5835
        }
5836
5837
        return $form->addMultiSelect('users', get_lang('Users'), $result);
5838
    }
5839
5840
    /**
5841
     * this function shows the form for sending a message to a specific group or user.
5842
     *
5843
     * @param CGroup[] $groupList
5844
     * @param array    $userList
5845
     * @param array    $alreadySelected
5846
     *
5847
     * @return array
5848
     */
5849
    public static function buildSelectOptions($groupList = [], $userList = [], $alreadySelected = [])
5850
    {
5851
        if (empty($alreadySelected)) {
5852
            $alreadySelected = [];
5853
        }
5854
5855
        $result = [];
5856
        // adding the groups to the select form
5857
        if ($groupList) {
5858
            foreach ($groupList as $thisGroup) {
5859
                $groupId = $thisGroup->getIid();
5860
                if (is_array($alreadySelected)) {
5861
                    if (!in_array(
5862
                        "GROUP:".$groupId,
5863
                        $alreadySelected
5864
                    )
5865
                    ) {
5866
                        $userCount = $thisGroup->getMembers()->count();
5867
5868
                        // $alreadySelected is the array containing the groups (and users) that are already selected
5869
                        $userLabel = ($userCount > 0) ? get_lang('Users') : get_lang('user');
5870
                        $userDisabled = ($userCount > 0) ? "" : "disabled=disabled";
5871
                        $result[] = [
5872
                            'disabled' => $userDisabled,
5873
                            'value' => "GROUP:".$groupId,
5874
                            // The space before "G" is needed in order to advmultiselect.php js puts groups first
5875
                            'content' => " G: ".$thisGroup->getTitle()." - ".$userCount." ".$userLabel,
5876
                        ];
5877
                    }
5878
                }
5879
            }
5880
        }
5881
5882
        // adding the individual users to the select form
5883
        if ($userList) {
5884
            foreach ($userList as $user) {
5885
                if (is_array($alreadySelected)) {
5886
                    if (!in_array(
5887
                        "USER:".$user['user_id'],
5888
                        $alreadySelected
5889
                    )
5890
                    ) {
5891
                        // $alreadySelected is the array containing the users (and groups) that are already selected
5892
                        $result[] = [
5893
                            'value' => "USER:".$user['user_id'],
5894
                            'content' => api_get_person_name($user['firstname'], $user['lastname']),
5895
                        ];
5896
                    }
5897
                }
5898
            }
5899
        }
5900
5901
        return $result;
5902
    }
5903
5904
    /**
5905
     * @return array a list (array) of all courses
5906
     */
5907
    public static function get_course_list()
5908
    {
5909
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
5910
5911
        return Database::store_result(Database::query("SELECT *, id as real_id FROM $table"));
5912
    }
5913
5914
    /**
5915
     * Returns course code from a given gradebook category's id.
5916
     *
5917
     * @param int $category_id Category ID
5918
     *
5919
     * @return ?int Course ID
5920
     * @throws Exception
5921
     */
5922
    public static function get_course_by_category(int $category_id): ?int
5923
    {
5924
        $category_id = (int) $category_id;
5925
        $sql = 'SELECT c_id FROM '.Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY).'
5926
                WHERE id='.$category_id;
5927
        $info = Database::fetch_array(Database::query($sql));
5928
5929
        return $info ? $info['c_id'] : null;
5930
    }
5931
5932
    /**
5933
     * This function gets all the courses that are not in a session.
5934
     *
5935
     * @param date Start date
5936
     * @param date End date
5937
     * @param bool $includeClosed Whether to include closed and hidden courses
5938
     *
5939
     * @return array Not-in-session courses
5940
     */
5941
    public static function getCoursesWithoutSession(
5942
        $startDate = null,
5943
        $endDate = null,
5944
        $includeClosed = false
5945
    ) {
5946
        $dateConditional = ($startDate && $endDate) ?
5947
            " WHERE session_id IN (SELECT id FROM ".Database::get_main_table(TABLE_MAIN_SESSION).
5948
            " WHERE access_start_date = '$startDate' AND access_end_date = '$endDate')" : null;
5949
        $visibility = ($includeClosed ? '' : 'visibility NOT IN (0, 4) AND ');
5950
5951
        $sql = "SELECT id, code, title
5952
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
5953
                WHERE $visibility code NOT IN (
5954
                    SELECT DISTINCT course_code
5955
                    FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE).$dateConditional."
5956
                )
5957
                ORDER BY id";
5958
5959
        $result = Database::query($sql);
5960
        $courses = [];
5961
        while ($row = Database::fetch_array($result)) {
5962
            $courses[] = $row;
5963
        }
5964
5965
        return $courses;
5966
    }
5967
5968
    /**
5969
     * Get list of courses based on users of a group for a group admin.
5970
     *
5971
     * @param int $userId The user id
5972
     *
5973
     * @return array
5974
     */
5975
    public static function getCoursesFollowedByGroupAdmin($userId)
5976
    {
5977
        $coursesList = [];
5978
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
5979
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5980
        $userGroup = new UserGroupModel();
5981
        $userIdList = $userGroup->getGroupUsersByUser($userId);
5982
5983
        if (empty($userIdList)) {
5984
            return [];
5985
        }
5986
5987
        $sql = "SELECT DISTINCT(c.id), c.title
5988
                FROM $courseTable c
5989
                INNER JOIN $courseUserTable cru ON c.id = cru.c_id
5990
                WHERE (
5991
                    cru.user_id IN (".implode(', ', $userIdList).")
5992
                    AND cru.relation_type = 0
5993
                )";
5994
5995
        if (api_is_multiple_url_enabled()) {
5996
            $courseAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5997
            $accessUrlId = api_get_current_access_url_id();
5998
5999
            if (-1 != $accessUrlId) {
6000
                $sql = "SELECT DISTINCT(c.id), c.title
6001
                        FROM $courseTable c
6002
                        INNER JOIN $courseUserTable cru ON c.id = cru.c_id
6003
                        INNER JOIN $courseAccessUrlTable crau ON c.id = crau.c_id
6004
                        WHERE crau.access_url_id = $accessUrlId
6005
                            AND (
6006
                            cru.id_user IN (".implode(', ', $userIdList).") AND
6007
                            cru.relation_type = 0
6008
                        )";
6009
            }
6010
        }
6011
6012
        $result = Database::query($sql);
6013
        while ($row = Database::fetch_assoc($result)) {
6014
            $coursesList[] = $row;
6015
        }
6016
6017
        return $coursesList;
6018
    }
6019
6020
    /**
6021
     * Direct course link see #5299.
6022
     *
6023
     * You can send to your students an URL like this
6024
     * http://chamilodev.beeznest.com/main/auth/inscription.php?c=ABC&e=3
6025
     * Where "c" is the course code and "e" is the exercise Id, after a successful
6026
     * registration the user will be sent to the course or exercise
6027
     *
6028
     * @param array $form_data
6029
     *
6030
     * @return array
6031
     */
6032
    public static function redirectToCourse($form_data)
6033
    {
6034
        $course_code_redirect = Session::read('course_redirect');
6035
        $_user = api_get_user_info();
6036
        $userId = api_get_user_id();
6037
6038
        if (!empty($course_code_redirect)) {
6039
            $course_info = api_get_course_info($course_code_redirect);
6040
            if (!empty($course_info)) {
6041
                if (in_array(
6042
                    $course_info['visibility'],
6043
                    [Course::OPEN_PLATFORM, Course::OPEN_WORLD]
6044
                )
6045
                ) {
6046
                    if (self::is_user_subscribed_in_course($userId, $course_info['code'])) {
6047
                        $form_data['action'] = $course_info['course_public_url'];
6048
                        $form_data['message'] = sprintf(get_lang('You have been registered to course %s'), $course_info['title']);
6049
                        $form_data['button'] = Display::button(
6050
                            'next',
6051
                            get_lang('Go to the course', null, $_user['language']),
6052
                            ['class' => 'btn btn--primary btn-large']
6053
                        );
6054
6055
                        $exercise_redirect = (int) Session::read('exercise_redirect');
6056
                        // Specify the course id as the current context does not
6057
                        // hold a global $_course array
6058
                        $objExercise = new Exercise($course_info['real_id']);
6059
                        $result = $objExercise->read($exercise_redirect);
6060
6061
                        if (!empty($exercise_redirect) && !empty($result)) {
6062
                            $form_data['action'] = api_get_path(WEB_CODE_PATH).
6063
                                'exercise/overview.php?exerciseId='.$exercise_redirect.'&cid='.$course_info['real_id'];
6064
                            $form_data['message'] .= '<br />'.get_lang('Go to the test');
6065
                            $form_data['button'] = Display::button(
6066
                                'next',
6067
                                get_lang('Go', null, $_user['language']),
6068
                                ['class' => 'btn btn--primary btn-large']
6069
                            );
6070
                        }
6071
6072
                        if (!empty($form_data['action'])) {
6073
                            header('Location: '.$form_data['action']);
6074
                            exit;
6075
                        }
6076
                    }
6077
                }
6078
            }
6079
        }
6080
6081
        return $form_data;
6082
    }
6083
6084
    /**
6085
     * Return tab of params to display a course title in the My Courses tab
6086
     * Check visibility, right, and notification icons, and load_dirs option
6087
     * get html course params.
6088
     *
6089
     * @param $courseId
6090
     * @param bool $loadDirs
6091
     *
6092
     * @return array with keys ['right_actions'] ['teachers'] ['notifications']
6093
     */
6094
    public static function getCourseParamsForDisplay($courseId, $loadDirs = false)
6095
    {
6096
        $userId = api_get_user_id();
6097
        $courseId = intval($courseId);
6098
        // Table definitions
6099
        $TABLECOURS = Database::get_main_table(TABLE_MAIN_COURSE);
6100
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6101
        $TABLE_ACCESS_URL_REL_COURSE = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
6102
        $current_url_id = api_get_current_access_url_id();
6103
6104
        // Get course list auto-register
6105
        $special_course_list = self::get_special_course_list();
6106
6107
        $without_special_courses = '';
6108
        if (!empty($special_course_list)) {
6109
            $without_special_courses = ' AND course.id NOT IN ("'.implode('","', $special_course_list).'")';
6110
        }
6111
6112
        //AND course_rel_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
6113
        $sql = "SELECT
6114
                    course.id,
6115
                    course.title,
6116
                    course.code,
6117
                    course.subscribe subscr,
6118
                    course.unsubscribe unsubscr,
6119
                    course_rel_user.status status,
6120
                    course_rel_user.sort sort,
6121
                    course_rel_user.user_course_cat user_course_cat
6122
                FROM
6123
                $TABLECOURS course
6124
                INNER JOIN $TABLECOURSUSER course_rel_user
6125
                ON (course.id = course_rel_user.c_id)
6126
                INNER JOIN $TABLE_ACCESS_URL_REL_COURSE url
6127
                ON (url.c_id = course.id)
6128
                WHERE
6129
                    course.id = $courseId AND
6130
                    course_rel_user.user_id = $userId
6131
                    $without_special_courses
6132
                ";
6133
6134
        // If multiple URL access mode is enabled, only fetch courses
6135
        // corresponding to the current URL.
6136
        if (api_get_multiple_access_url() && -1 != $current_url_id) {
6137
            $sql .= " AND url.c_id = course.id AND access_url_id = $current_url_id";
6138
        }
6139
        // Use user's classification for courses (if any).
6140
        $sql .= " ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC";
6141
6142
        $result = Database::query($sql);
6143
6144
        // Browse through all courses. We can only have one course because
6145
        // of the  course.id=".intval($courseId) in sql query
6146
        $course = Database::fetch_array($result);
6147
        $course_info = api_get_course_info_by_id($courseId);
6148
        if (empty($course_info)) {
6149
            return '';
6150
        }
6151
6152
        //$course['id_session'] = null;
6153
        $course_info['id_session'] = null;
6154
        $course_info['status'] = $course['status'];
6155
6156
        // New code displaying the user's status in respect to this course.
6157
        $status_icon = Display::getMdiIcon(
6158
            'account-key',
6159
            'ch-tool-icon',
6160
            null,
6161
            ICON_SIZE_LARGE,
6162
            $course_info['title']
6163
        );
6164
6165
        $params = [];
6166
        $params['right_actions'] = '';
6167
6168
        if (api_is_platform_admin()) {
6169
            if ($loadDirs) {
6170
                $params['right_actions'] .= '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview" href="javascript:void(0);">'.Display::getMdiIcon(ObjectIcon::FOLDER, 'ch-tool-icon', 'align: absmiddle;', ICON_SIZE_SMALL, get_lang('Documents')).'</a>';
6171
                $params['right_actions'] .= '<a href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'].'">'.
6172
                    Display::getMdiIcon(ActionIcon::EDIT, 'ch-tool-icon', 'align: absmiddle;', ICON_SIZE_SMALL, get_lang('Edit')).
6173
                    '</a>';
6174
                $params['right_actions'] .= Display::div(
6175
                    '',
6176
                    [
6177
                        'id' => 'document_result_'.$course_info['real_id'].'_0',
6178
                        'class' => 'document_preview_container',
6179
                    ]
6180
                );
6181
            } else {
6182
                $params['right_actions'] .=
6183
                    '<a class="btn btn--plain btn-sm" title="'.get_lang('Edit').'" href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'].'">'.
6184
                    Display::getMdiIcon('pencil').'</a>';
6185
            }
6186
        } else {
6187
            if (Course::CLOSED != $course_info['visibility']) {
6188
                if ($loadDirs) {
6189
                    $params['right_actions'] .= '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview" href="javascript:void(0);">'.
6190
                        Display::getMdiIcon(ObjectIcon::FOLDER, 'ch-tool-icon', 'align: absmiddle;', ICON_SIZE_SMALL, get_lang('Documents')).'</a>';
6191
                    $params['right_actions'] .= Display::div(
6192
                        '',
6193
                        [
6194
                            'id' => 'document_result_'.$course_info['real_id'].'_0',
6195
                            'class' => 'document_preview_container',
6196
                        ]
6197
                    );
6198
                } else {
6199
                    if (COURSEMANAGER == $course_info['status']) {
6200
                        $params['right_actions'] .= '<a
6201
                            class="btn btn--plain btn-sm" title="'.get_lang('Edit').'" href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'].'">'.
6202
                            Display::getMdiIcon('pencil').'</a>';
6203
                    }
6204
                }
6205
            }
6206
        }
6207
6208
        $course_title_url = '';
6209
        if (Course::CLOSED != $course_info['visibility'] || COURSEMANAGER == $course['status']) {
6210
            $course_title_url = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/?id_session=0';
6211
            $course_title = Display::url($course_info['title'], $course_title_url);
6212
        } else {
6213
            $course_title = $course_info['title'].' '.Display::tag(
6214
                'span',
6215
                get_lang('(the course is currently closed)'),
6216
                ['class' => 'item_closed']
6217
            );
6218
        }
6219
6220
        // Start displaying the course block itself
6221
        if ('true' === api_get_setting('display_coursecode_in_courselist')) {
6222
            $course_title .= ' ('.$course_info['visual_code'].') ';
6223
        }
6224
        $teachers = '';
6225
        if ('true' === api_get_setting('display_teacher_in_courselist')) {
6226
            $teachers = self::getTeacherListFromCourseCodeToString(
6227
                $course['code'],
6228
                self::USER_SEPARATOR,
6229
                true
6230
            );
6231
        }
6232
        $params['link'] = $course_title_url;
6233
        $params['icon'] = $status_icon;
6234
        $params['title'] = $course_title;
6235
        $params['teachers'] = $teachers;
6236
6237
        return $params;
6238
    }
6239
6240
    /**
6241
     * Get the course id based on the original id and field name in the extra fields.
6242
     * Returns 0 if course was not found.
6243
     *
6244
     * @param string $original_course_id_value Original course id
6245
     * @param string $original_course_id_name  Original field name
6246
     *
6247
     * @return int Course id
6248
     */
6249
    public static function get_course_id_from_original_id($original_course_id_value, $original_course_id_name)
6250
    {
6251
        $extraFieldValue = new ExtraFieldValue('course');
6252
        $value = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
6253
            $original_course_id_name,
6254
            $original_course_id_value
6255
        );
6256
6257
        if ($value) {
6258
            return $value['item_id'];
6259
        }
6260
6261
        return 0;
6262
    }
6263
6264
    /**
6265
     * Helper function to create a default gradebook (if necessary) upon course creation.
6266
     *
6267
     * @param int $modelId  The gradebook model ID
6268
     * @param int $courseId Course ID
6269
     * @return void
6270
     * @throws Exception
6271
     */
6272
    public static function createDefaultGradebook(int $modelId, int $courseId): void
6273
    {
6274
        if ('true' === api_get_setting('gradebook_enable_grade_model')) {
6275
            //Create gradebook_category for the new course and add
6276
            // a gradebook model for the course
6277
            if ('-1' != $modelId) {
6278
                GradebookUtils::create_default_course_gradebook(
6279
                    $courseId,
6280
                    $modelId
6281
                );
6282
            }
6283
        }
6284
    }
6285
6286
    /**
6287
     * Helper function to check if there is a course template and, if so, to
6288
     * copy the template as basis for the new course.
6289
     *
6290
     * @param string $courseCode     Course code
6291
     * @param int    $courseTemplate 0 if no course template is defined
6292
     */
6293
    public static function useTemplateAsBasisIfRequired($courseCode, $courseTemplate)
6294
    {
6295
        $template = api_get_setting('course_creation_use_template');
6296
        $teacherCanSelectCourseTemplate = 'true' === api_get_setting('teacher_can_select_course_template');
6297
        $courseTemplate = isset($courseTemplate) ? intval($courseTemplate) : 0;
6298
6299
        $useTemplate = false;
6300
6301
        if ($teacherCanSelectCourseTemplate && $courseTemplate) {
6302
            $useTemplate = true;
6303
            $originCourse = api_get_course_info_by_id($courseTemplate);
6304
        } elseif (!empty($template)) {
6305
            $useTemplate = true;
6306
            $originCourse = api_get_course_info_by_id($template);
6307
        }
6308
6309
        if ($useTemplate) {
6310
            // Include the necessary libraries to generate a course copy
6311
            // Call the course copy object
6312
            $originCourse['official_code'] = $originCourse['code'];
6313
            $cb = new CourseBuilder(null, $originCourse);
6314
            $course = $cb->build(null, $originCourse['code']);
6315
            $cr = new CourseRestorer($course);
6316
            $cr->set_file_option();
6317
            $cr->restore($courseCode);
6318
        }
6319
    }
6320
6321
    /**
6322
     * Helper method to get the number of users defined with a specific course extra field.
6323
     *
6324
     * @param string $name                 Field title
6325
     * @param string $tableExtraFields     The extra fields table name
6326
     * @param string $tableUserFieldValues The user extra field value table name
6327
     *
6328
     * @return int The number of users with this extra field with a specific value
6329
     */
6330
    public static function getCountRegisteredUsersWithCourseExtraField(
6331
        $name,
6332
        $tableExtraFields = '',
6333
        $tableUserFieldValues = ''
6334
    ) {
6335
        if (empty($tableExtraFields)) {
6336
            $tableExtraFields = Database::get_main_table(TABLE_EXTRA_FIELD);
6337
        }
6338
        if (empty($tableUserFieldValues)) {
6339
            $tableUserFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
6340
        }
6341
6342
        $registered_users_with_extra_field = 0;
6343
        if (!empty($name) && '-' != $name) {
6344
            $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
6345
            $name = Database::escape_string($name);
6346
            $sql = "SELECT count(v.item_id) as count
6347
                    FROM $tableUserFieldValues v
6348
                    INNER JOIN $tableExtraFields f
6349
                    ON (f.id = v.field_id)
6350
                    WHERE value = '$name' AND item_type = $extraFieldType";
6351
            $result_count = Database::query($sql);
6352
            if (Database::num_rows($result_count)) {
6353
                $row_count = Database::fetch_array($result_count);
6354
                $registered_users_with_extra_field = $row_count['count'];
6355
            }
6356
        }
6357
6358
        return $registered_users_with_extra_field;
6359
    }
6360
6361
    /**
6362
     * Get the course categories form a course list.
6363
     *
6364
     * @return array
6365
     */
6366
    public static function getCourseCategoriesFromCourseList(array $courseList)
6367
    {
6368
        $allCategories = array_column($courseList, 'category');
6369
        $categories = array_unique($allCategories);
6370
6371
        sort($categories);
6372
6373
        return $categories;
6374
    }
6375
6376
    /**
6377
     * Display the description button of a course in the course catalog.
6378
     *
6379
     * @param array  $course
6380
     * @param string $url
6381
     *
6382
     * @return string HTML string
6383
     */
6384
    public static function returnDescriptionButton($course, $url = '')
6385
    {
6386
        if (empty($course)) {
6387
            return '';
6388
        }
6389
6390
        $class = '';
6391
        if ('true' === api_get_setting('show_courses_descriptions_in_catalog')) {
6392
            $title = $course['title'];
6393
            if (empty($url)) {
6394
                $class = 'ajax';
6395
                $url = api_get_path(WEB_CODE_PATH).
6396
                    'inc/ajax/course_home.ajax.php?a=show_course_information&code='.$course['code'];
6397
            } else {
6398
                if (false !== strpos($url, 'ajax')) {
6399
                    $class = 'ajax';
6400
                }
6401
            }
6402
6403
            return Display::url(
6404
                Display::getMdiIcon('information'),
6405
                $url,
6406
                [
6407
                    'class' => "$class btn btn--plain btn-sm",
6408
                    'data-title' => $title,
6409
                    'title' => get_lang('Description'),
6410
                    'aria-label' => get_lang('Description'),
6411
                    'data-size' => 'lg',
6412
                ]
6413
            );
6414
        }
6415
6416
        return '';
6417
    }
6418
6419
    /**
6420
     * @return int
6421
     */
6422
    public static function getCountOpenCourses()
6423
    {
6424
        $visibility = [
6425
            Course::REGISTERED,
6426
            Course::OPEN_PLATFORM,
6427
            Course::OPEN_WORLD,
6428
        ];
6429
6430
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
6431
        $sql = "SELECT count(id) count
6432
                FROM $table
6433
                WHERE visibility IN (".implode(',', $visibility).")";
6434
        $result = Database::query($sql);
6435
        $row = Database::fetch_array($result);
6436
6437
        return (int) $row['count'];
6438
    }
6439
6440
    /**
6441
     * @return int
6442
     */
6443
    public static function getCountExercisesFromOpenCourse()
6444
    {
6445
        $visibility = [
6446
            Course::REGISTERED,
6447
            Course::OPEN_PLATFORM,
6448
            Course::OPEN_WORLD,
6449
        ];
6450
6451
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
6452
        $tableExercise = Database::get_course_table(TABLE_QUIZ_TEST);
6453
        $sql = "SELECT count(e.iid) count
6454
                FROM $table c
6455
                INNER JOIN $tableExercise e
6456
                ON (c.id = e.c_id)
6457
                WHERE e.active <> -1 AND visibility IN (".implode(',', $visibility).")";
6458
        $result = Database::query($sql);
6459
        $row = Database::fetch_array($result);
6460
6461
        return (int) $row['count'];
6462
    }
6463
6464
    /**
6465
     * retrieves all the courses that the user has already subscribed to.
6466
     *
6467
     * @param int $user_id
6468
     *
6469
     * @return array an array containing all the information of the courses of the given user
6470
     */
6471
    public static function getCoursesByUserCourseCategory($user_id)
6472
    {
6473
        $course = Database::get_main_table(TABLE_MAIN_COURSE);
6474
        $courseRelUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6475
        $avoidCoursesCondition = CoursesAndSessionsCatalog::getAvoidCourseCondition();
6476
        $visibilityCondition = self::getCourseVisibilitySQLCondition('course', true);
6477
6478
        // Secondly we select the courses that are in a category (user_course_cat<>0) and
6479
        // sort these according to the sort of the category
6480
        $user_id = (int) $user_id;
6481
        $sql = "SELECT
6482
                    course.code k,
6483
                    course.visual_code vc,
6484
                    course.subscribe subscr,
6485
                    course.unsubscribe unsubscr,
6486
                    course.title i,
6487
                    course.tutor_name t,
6488
                    course.category_code cat,
6489
                    course.directory dir,
6490
                    course_rel_user.status status,
6491
                    course_rel_user.sort sort,
6492
                    course_rel_user.user_course_cat user_course_cat
6493
                FROM $course course, $courseRelUser course_rel_user
6494
                WHERE
6495
                    course.id = course_rel_user.c_id AND
6496
                    course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
6497
                    course_rel_user.user_id = '".$user_id."'
6498
                    $avoidCoursesCondition
6499
                    $visibilityCondition
6500
                ORDER BY course_rel_user.sort ASC";
6501
6502
        $result = Database::query($sql);
6503
        $courses = [];
6504
        while ($row = Database::fetch_array($result, 'ASOC')) {
6505
            $courses[] = [
6506
                'code' => $row['k'],
6507
                'visual_code' => $row['vc'],
6508
                'title' => $row['i'],
6509
                'directory' => $row['dir'],
6510
                'status' => $row['status'],
6511
                'tutor' => $row['t'],
6512
                'subscribe' => $row['subscr'],
6513
                'category' => $row['cat'],
6514
                'unsubscribe' => $row['unsubscr'],
6515
                'sort' => $row['sort'],
6516
                'user_course_category' => $row['user_course_cat'],
6517
            ];
6518
        }
6519
6520
        return $courses;
6521
    }
6522
6523
    /**
6524
     * @param string $listType
6525
     *
6526
     * @return string
6527
     */
6528
    public static function getCourseListTabs($listType)
6529
    {
6530
        $tabs = [
6531
            [
6532
                'content' => get_lang('Standard list'),
6533
                'url' => api_get_path(WEB_CODE_PATH).'admin/course_list.php',
6534
            ],
6535
            [
6536
                'content' => get_lang('Management List'),
6537
                'url' => api_get_path(WEB_CODE_PATH).'admin/course_list_admin.php',
6538
            ],
6539
        ];
6540
6541
        $default = 1;
6542
        switch ($listType) {
6543
            case 'simple':
6544
                $default = 1;
6545
                break;
6546
            case 'admin':
6547
                $default = 2;
6548
                break;
6549
        }
6550
6551
        return Display::tabsOnlyLink($tabs, $default);
6552
    }
6553
6554
    public static function getUrlMarker($courseId)
6555
    {
6556
        if (UrlManager::getCountAccessUrlFromCourse($courseId) > 1) {
6557
            return '&nbsp;'.Display::getMdiIcon(
6558
                'link',
6559
                null,
6560
                null,
6561
                null,
6562
                get_lang('CourseUsedInOtherURL')
6563
            );
6564
        }
6565
6566
        return '';
6567
    }
6568
6569
    /**
6570
     * @throws \Doctrine\ORM\ORMException
6571
     * @throws \Doctrine\ORM\OptimisticLockException
6572
     */
6573
    public static function insertUserInCourse(User $user, Course $course, array $relationInfo = []): ?int
6574
    {
6575
        $relationInfo = array_merge(
6576
            ['relation_type' => 0, 'status' => STUDENT, 'sort' => 0, 'user_course_cat' => 0],
6577
            $relationInfo
6578
        );
6579
6580
        $courseRelUser = (new CourseRelUser())
6581
            ->setCourse($course)
6582
            ->setUser($user)
6583
            ->setStatus($relationInfo['status'])
6584
            ->setSort($relationInfo['sort'])
6585
            ->setUserCourseCat($relationInfo['user_course_cat']);
6586
6587
        $course->addSubscription($courseRelUser);
6588
6589
        $em = Database::getManager();
6590
        $em->persist($course);
6591
        $em->flush();
6592
6593
        $insertId = $courseRelUser->getId();
6594
6595
        Event::logSubscribedUserInCourse($user, $course);
6596
6597
        return $insertId;
6598
    }
6599
6600
    public static function addVisibilityOptions(FormValidator $form): void
6601
    {
6602
        $group = [];
6603
        $group[] = $form->createElement(
6604
            'radio',
6605
            'visibility',
6606
            get_lang('Course access'),
6607
            get_lang('Public - access allowed for the whole world'),
6608
            Course::OPEN_WORLD
6609
        );
6610
        $group[] = $form->createElement(
6611
            'radio',
6612
            'visibility',
6613
            null,
6614
            get_lang(' Open - access allowed for users registered on the platform'),
6615
            Course::OPEN_PLATFORM
6616
        );
6617
        $group[] = $form->createElement(
6618
            'radio',
6619
            'visibility',
6620
            null,
6621
            get_lang('Private access (access authorized to group members only)'),
6622
            Course::REGISTERED
6623
        );
6624
        $group[] = $form->createElement(
6625
            'radio',
6626
            'visibility',
6627
            null,
6628
            get_lang('Closed - the course is only accessible to the teachers'),
6629
            Course::CLOSED
6630
        );
6631
        // The "hidden" visibility is only available to portal admins
6632
        if (api_is_platform_admin()) {
6633
            $group[] = $form->createElement(
6634
                'radio',
6635
                'visibility',
6636
                null,
6637
                get_lang('Hidden - Completely hidden to all users except the administrators'),
6638
                Course::HIDDEN
6639
            );
6640
        }
6641
        $form->addGroup($group, '', get_lang('Course access'));
6642
    }
6643
6644
    /**
6645
     * Check if a specific access-url-related setting is a problem or not.
6646
     *
6647
     * @param array  $_configuration The $_configuration array
6648
     * @param int    $accessUrlId    The access URL ID
6649
     * @param string $param
6650
     * @param string $msgLabel
6651
     *
6652
     * @return bool|string
6653
     */
6654
    private static function checkCreateCourseAccessUrlParam($_configuration, $accessUrlId, $param, $msgLabel)
6655
    {
6656
        if (isset($_configuration[$accessUrlId][$param]) && $_configuration[$accessUrlId][$param] > 0) {
6657
            $num = null;
6658
            switch ($param) {
6659
                case 'hosting_limit_courses':
6660
            $num = self::count_courses($accessUrlId);
6661
                    break;
6662
                case 'hosting_limit_active_courses':
6663
                    $num = self::countActiveCourses($accessUrlId);
6664
                    break;
6665
            }
6666
6667
            if ($num && $num >= $_configuration[$accessUrlId][$param]) {
6668
                api_warn_hosting_contact($param);
6669
6670
                Display::addFlash(
6671
                    Display::return_message($msgLabel)
6672
                );
6673
6674
                return true;
6675
            }
6676
        }
6677
6678
        return false;
6679
    }
6680
6681
    /**
6682
     * Fill course with all necessary items.
6683
     * @param Course $course
6684
     * @param array $params Parameters from the course creation form
6685
     * @param ?int   $authorId
6686
     * @throws Exception
6687
     */
6688
    private static function fillCourse(Course $course, array $params, ?int $authorId = 0)
6689
    {
6690
        $authorId = empty($authorId) ? api_get_user_id() : $authorId;
6691
6692
        AddCourse::fillCourse(
6693
            $course,
6694
            $params['exemplary_content'],
6695
            $authorId
6696
        );
6697
6698
        if (isset($params['gradebook_model_id'])) {
6699
            self::createDefaultGradebook(
6700
                $params['gradebook_model_id'],
6701
                $course->getId()
6702
            );
6703
        }
6704
6705
        // If parameter defined, copy the contents from a specific
6706
        // template course into this new course
6707
        if (isset($params['course_template'])) {
6708
            self::useTemplateAsBasisIfRequired(
6709
                $course->getCode(),
6710
                $params['course_template']
6711
            );
6712
        }
6713
        $params['course_code'] = $course->getCode();
6714
        $params['item_id'] = $course->getId();
6715
6716
        $courseFieldValue = new ExtraFieldValue('course');
6717
        //$courseFieldValue->saveFieldValues($params);
6718
    }
6719
}
6720