Passed
Push — master ( 89c993...0e8800 )
by Julito
11:28
created

CourseManager::create_course()   B

Complexity

Conditions 11
Paths 72

Size

Total Lines 65
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 11
eloc 24
nc 72
nop 3
dl 0
loc 65
rs 7.3166
c 1
b 0
f 1

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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

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

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

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

    return false;
}

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

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