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

CourseManager::createDefaultGradebook()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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