Passed
Push — master ( 099693...6fec2b )
by Julito
09:41
created

CourseManager::getCoursesFollowedByUser()   F

Complexity

Conditions 14
Paths 480

Size

Total Lines 107
Code Lines 64

Duplication

Lines 0
Ratio 0 %

Importance

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