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