Passed
Push — 1.11.x ( 770413...0d4854 )
by Angel Fernando Quiroz
10:34 queued 28s
created

CourseManager::get_courses_list()   F

Complexity

Conditions 23
Paths 10368

Size

Total Lines 115
Code Lines 71

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 23
eloc 71
nc 10368
nop 10
dl 0
loc 115
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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