Completed
Push — 1.11.x ( a5874c...fde968 )
by Angel Fernando Quiroz
01:37 queued 59s
created

CoursesAndSessionsCatalog::getPageNumberItem()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 29
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 11
nc 6
nop 8
dl 0
loc 29
rs 9.2222
c 0
b 0
f 0

How to fix   Many Parameters   

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\ExtraField;
6
use Chamilo\CoreBundle\Entity\Repository\SequenceResourceRepository;
7
use Chamilo\CoreBundle\Entity\SequenceResource;
8
use Chamilo\CoreBundle\Entity\SessionRelCourse;
9
use Chamilo\CoreBundle\Entity\Tag;
10
use Doctrine\ORM\Query\Expr\Join;
11
use ExtraField as ExtraFieldModel;
12
13
/**
14
 * @todo change class name
15
 */
16
class CoursesAndSessionsCatalog
17
{
18
    public const PAGE_LENGTH = 12;
19
20
    /**
21
     * Check the configuration for the courses and sessions catalog.
22
     */
23
    public static function is(int $value = CATALOG_COURSES): bool
24
    {
25
        $showCoursesSessions = (int) api_get_setting('catalog_show_courses_sessions');
26
27
        return $showCoursesSessions == $value;
28
    }
29
30
    /**
31
     * Check whether to display the sessions list.
32
     */
33
    public static function showSessions(): bool
34
    {
35
        $catalogShow = (int) api_get_setting('catalog_show_courses_sessions');
36
37
        return $catalogShow == CATALOG_SESSIONS || $catalogShow == CATALOG_COURSES_SESSIONS;
38
    }
39
40
    /**
41
     * Check whether to display the courses list.
42
     */
43
    public static function showCourses(): bool
44
    {
45
        $catalogShow = (int) api_get_setting('catalog_show_courses_sessions');
46
47
        return $catalogShow == CATALOG_COURSES || $catalogShow == CATALOG_COURSES_SESSIONS;
48
    }
49
50
    /**
51
     * @return array
52
     */
53
    public static function getCoursesToAvoid()
54
    {
55
        $TABLE_COURSE_FIELD = Database::get_main_table(TABLE_EXTRA_FIELD);
56
        $TABLE_COURSE_FIELD_VALUE = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
57
58
        // Check special courses
59
        $courseListToAvoid = CourseManager::get_special_course_list();
60
61
        $categoryToAvoid = api_get_configuration_value('course_category_code_to_use_as_model');
62
        if (!empty($categoryToAvoid) && api_is_student()) {
63
            $coursesInCategoryToAvoid = CourseCategory::getCoursesInCategory($categoryToAvoid, '', false);
64
            if (!empty($coursesInCategoryToAvoid)) {
65
                foreach ($coursesInCategoryToAvoid as $courseToAvoid) {
66
                    $courseListToAvoid[] = $courseToAvoid['id'];
67
                }
68
            }
69
        }
70
71
        // Checks "hide_from_catalog" extra field
72
        $extraFieldType = ExtraField::COURSE_FIELD_TYPE;
73
74
        $sql = "SELECT item_id FROM $TABLE_COURSE_FIELD_VALUE tcfv
75
                INNER JOIN $TABLE_COURSE_FIELD tcf
76
                ON tcfv.field_id =  tcf.id
77
                WHERE
78
                    tcf.extra_field_type = $extraFieldType AND
79
                    tcf.variable = 'hide_from_catalog' AND
80
                    tcfv.value = 1
81
                ";
82
83
        $result = Database::query($sql);
84
        if (Database::num_rows($result) > 0) {
85
            while ($row = Database::fetch_array($result)) {
86
                $courseListToAvoid[] = $row['item_id'];
87
            }
88
        }
89
90
        return $courseListToAvoid;
91
    }
92
93
    /**
94
     * @return string
95
     */
96
    public static function getAvoidCourseCondition()
97
    {
98
        $courseListToAvoid = self::getCoursesToAvoid();
99
        $condition = '';
100
        if (!empty($courseListToAvoid)) {
101
            $courses = [];
102
            foreach ($courseListToAvoid as $courseId) {
103
                $courses[] = '"'.$courseId.'"';
104
            }
105
            $condition = ' AND course.id NOT IN ('.implode(',', $courses).')';
106
        }
107
108
        return $condition;
109
    }
110
111
    /**
112
     * Get available le courses count.
113
     *
114
     * @param int $accessUrlId (optional)
115
     *
116
     * @return int Number of courses
117
     */
118
    public static function countAvailableCoursesToShowInCatalog($accessUrlId = 1)
119
    {
120
        $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
121
        $tableCourseRelAccessUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
122
        $courseToAvoidCondition = self::getAvoidCourseCondition();
123
        $visibilityCondition = CourseManager::getCourseVisibilitySQLCondition('course', true);
124
125
        $accessUrlId = (int) $accessUrlId;
126
        if (empty($accessUrlId)) {
127
            $accessUrlId = 1;
128
        }
129
130
        $sql = "SELECT count(course.id)
131
                FROM $tableCourse course
132
                INNER JOIN $tableCourseRelAccessUrl u
133
                ON (course.id = u.c_id)
134
                WHERE
135
                    u.access_url_id = $accessUrlId AND
136
                    course.visibility != 0 AND
137
                    course.visibility != 4
138
                    $courseToAvoidCondition
139
                    $visibilityCondition
140
                ";
141
142
        $res = Database::query($sql);
143
        $row = Database::fetch_row($res);
144
145
        return $row[0];
146
    }
147
148
    public static function getCourseCategoriesTree()
149
    {
150
        $urlId = 1;
151
        if (api_is_multiple_url_enabled()) {
152
            $urlId = api_get_current_access_url_id();
153
        }
154
155
        $countCourses = self::countAvailableCoursesToShowInCatalog($urlId);
156
        $categories = [];
157
        $list = [];
158
159
        $categories['ALL'] = [
160
            'id' => 0,
161
            'name' => get_lang('DisplayAll'),
162
            'code' => 'ALL',
163
            'parent_id' => null,
164
            'tree_pos' => 0,
165
            'number_courses' => $countCourses,
166
            'level' => 0,
167
        ];
168
169
        $allCategories = CourseCategory::getAllCategories();
170
        $categoryToAvoid = '';
171
        if (api_is_student()) {
172
            $categoryToAvoid = api_get_configuration_value('course_category_code_to_use_as_model');
173
        }
174
        foreach ($allCategories as $category) {
175
            $categoryCode = $category['code'];
176
            if (!empty($categoryToAvoid) && $categoryToAvoid == $categoryCode) {
177
                continue;
178
            }
179
180
            if (empty($category['parent_id'])) {
181
                $list[$categoryCode] = $category;
182
                $list[$categoryCode]['level'] = 0;
183
                list($subList, $childrenCount) = self::buildCourseCategoryTree($allCategories, $categoryCode, 0);
184
                foreach ($subList as $item) {
185
                    $list[$item['code']] = $item;
186
                }
187
                // Real course count
188
                $countCourses = CourseCategory::countCoursesInCategory($categoryCode);
189
                $list[$categoryCode]['number_courses'] = $childrenCount + $countCourses;
190
            }
191
        }
192
193
        // count courses that are in no category
194
        $countCourses = CourseCategory::countCoursesInCategory('NONE');
195
        $categories['NONE'] = [
196
            'id' => 0,
197
            'name' => get_lang('WithoutCategory'),
198
            'code' => 'NONE',
199
            'parent_id' => null,
200
            'tree_pos' => 0,
201
            'children_count' => 0,
202
            'auth_course_child' => true,
203
            'auth_cat_child' => true,
204
            'number_courses' => $countCourses,
205
            'level' => 0,
206
        ];
207
208
        return array_merge($list, $categories);
209
    }
210
211
    /**
212
     * Return LIMIT to filter SQL query.
213
     *
214
     * @param array $limit
215
     *
216
     * @return string
217
     */
218
    public static function getLimitFilterFromArray($limit)
219
    {
220
        $limitFilter = '';
221
        if (!empty($limit) && is_array($limit)) {
222
            $limitStart = isset($limit['start']) ? (int) $limit['start'] : 0;
223
            $limitLength = isset($limit['length']) ? (int) $limit['length'] : 12;
224
            $limitFilter = 'LIMIT '.$limitStart.', '.$limitLength;
225
        }
226
227
        return $limitFilter;
228
    }
229
230
    /**
231
     * @param string $categoryCode
232
     * @param int    $randomValue
233
     * @param array  $limit        will be used if $randomValue is not set.
234
     *                             This array should contains 'start' and 'length' keys
235
     *
236
     * @return array
237
     */
238
    public static function getCoursesInCategory($categoryCode, $randomValue = null, $limit = [])
239
    {
240
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
241
        $avoidCoursesCondition = self::getAvoidCourseCondition();
242
        $visibilityCondition = CourseManager::getCourseVisibilitySQLCondition('course', true);
243
244
        if (!empty($randomValue)) {
245
            $randomValue = (int) $randomValue;
246
247
            $sql = "SELECT COUNT(*) FROM $tbl_course";
248
            $result = Database::query($sql);
249
            list($num_records) = Database::fetch_row($result);
250
251
            if (api_is_multiple_url_enabled()) {
252
                $urlId = api_get_current_access_url_id();
253
                $tbl_url_rel_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
254
255
                $urlCondition = ' access_url_id = '.$urlId.' ';
256
                $allowBaseCategories = api_get_configuration_value('allow_base_course_category');
257
                if ($allowBaseCategories) {
258
                    $urlCondition = ' (access_url_id = '.$urlId.' OR access_url_id = 1)  ';
259
                }
260
261
                $sql = "SELECT COUNT(*)
262
                        FROM $tbl_course course
263
                        INNER JOIN $tbl_url_rel_course as url_rel_course
264
                        ON (url_rel_course.c_id = course.id)
265
                        WHERE access_url_id = $urlId";
266
                $result = Database::query($sql);
267
                list($num_records) = Database::fetch_row($result);
268
269
                $sql = "SELECT course.id, course.id as real_id
270
                        FROM $tbl_course course
271
                        INNER JOIN $tbl_url_rel_course as url_rel_course
272
                        ON (url_rel_course.c_id = course.id)
273
                        WHERE
274
                            $urlCondition AND
275
                            RAND()*$num_records< $randomValue
276
                            $avoidCoursesCondition
277
                            $visibilityCondition
278
                        ORDER BY RAND()
279
                        LIMIT 0, $randomValue";
280
            } else {
281
                $sql = "SELECT id, id as real_id
282
                        FROM $tbl_course course
283
                        WHERE
284
                            RAND()*$num_records< $randomValue
285
                            $avoidCoursesCondition
286
                            $visibilityCondition
287
                        ORDER BY RAND()
288
                        LIMIT 0, $randomValue";
289
            }
290
291
            $result = Database::query($sql);
292
            $id_in = null;
293
            while (list($id) = Database::fetch_row($result)) {
294
                if ($id_in) {
295
                    $id_in .= ",$id";
296
                } else {
297
                    $id_in = "$id";
298
                }
299
            }
300
            if (null === $id_in) {
301
                return [];
302
            }
303
            $sql = "SELECT *, id as real_id FROM $tbl_course WHERE id IN($id_in)";
304
        } else {
305
            $limitFilter = self::getLimitFilterFromArray($limit);
306
            $categoryCode = Database::escape_string($categoryCode);
307
            $listCode = self::childrenCategories($categoryCode);
308
            $conditionCode = ' ';
309
310
            if (empty($listCode)) {
311
                if ($categoryCode === 'NONE') {
312
                    $conditionCode .= " category_code='' ";
313
                } else {
314
                    $conditionCode .= " category_code='$categoryCode' ";
315
                }
316
            } else {
317
                foreach ($listCode as $code) {
318
                    $conditionCode .= " category_code='$code' OR ";
319
                }
320
                $conditionCode .= " category_code='$categoryCode' ";
321
            }
322
323
            if (empty($categoryCode) || $categoryCode === 'ALL') {
324
                $sql = "SELECT *, id as real_id
325
                        FROM $tbl_course course
326
                        WHERE
327
                          1=1
328
                          $avoidCoursesCondition
329
                          $visibilityCondition
330
                        ORDER BY title $limitFilter ";
331
            } else {
332
                $sql = "SELECT *, id as real_id FROM $tbl_course course
333
                        WHERE
334
                            $conditionCode
335
                            $avoidCoursesCondition
336
                            $visibilityCondition
337
                        ORDER BY title $limitFilter ";
338
            }
339
340
            // Showing only the courses of the current Chamilo access_url_id
341
            if (api_is_multiple_url_enabled()) {
342
                $urlId = api_get_current_access_url_id();
343
                $tbl_url_rel_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
344
345
                $urlCondition = ' access_url_id = '.$urlId.' ';
346
                if ($categoryCode !== 'ALL') {
347
                    $sql = "SELECT *, course.id real_id
348
                            FROM $tbl_course as course
349
                            INNER JOIN $tbl_url_rel_course as url_rel_course
350
                            ON (url_rel_course.c_id = course.id)
351
                            WHERE
352
                                $urlCondition AND
353
                                $conditionCode
354
                                $avoidCoursesCondition
355
                                $visibilityCondition
356
                            ORDER BY title $limitFilter";
357
                } else {
358
                    $sql = "SELECT *, course.id real_id FROM $tbl_course as course
359
                            INNER JOIN $tbl_url_rel_course as url_rel_course
360
                            ON (url_rel_course.c_id = course.id)
361
                            WHERE
362
                                $urlCondition
363
                                $avoidCoursesCondition
364
                                $visibilityCondition
365
                            ORDER BY title $limitFilter";
366
                }
367
            }
368
        }
369
370
        $result = Database::query($sql);
371
        $courses = [];
372
        while ($row = Database::fetch_array($result)) {
373
            $row['registration_code'] = !empty($row['registration_code']);
374
            $count_users = CourseManager::get_users_count_in_course($row['code']);
375
            $connectionsLastMonth = Tracking::get_course_connections_count(
376
                $row['id'],
377
                0,
378
                api_get_utc_datetime(time() - (30 * 86400))
379
            );
380
381
            if ($row['tutor_name'] == '0') {
382
                $row['tutor_name'] = get_lang('NoManager');
383
            }
384
385
            $courses[] = [
386
                'real_id' => $row['real_id'],
387
                'point_info' => CourseManager::get_course_ranking($row['id'], 0),
388
                'code' => $row['code'],
389
                'directory' => $row['directory'],
390
                'visual_code' => $row['visual_code'],
391
                'title' => $row['title'],
392
                'tutor' => $row['tutor_name'],
393
                'subscribe' => $row['subscribe'],
394
                'unsubscribe' => $row['unsubscribe'],
395
                'registration_code' => $row['registration_code'],
396
                'creation_date' => $row['creation_date'],
397
                'visibility' => $row['visibility'],
398
                'category' => $row['category_code'],
399
                'count_users' => $count_users,
400
                'count_connections' => $connectionsLastMonth,
401
            ];
402
        }
403
404
        return $courses;
405
    }
406
407
    /**
408
     * Search the courses database for a course that matches the search term.
409
     * The search is done on the code, title and tutor field of the course table.
410
     *
411
     * @param string $categoryCode
412
     * @param string $keyword      The string that the user submitted
413
     * @param array  $limit
414
     * @param bool   $justVisible  search only on visible courses in the catalogue
415
     * @param array  $conditions
416
     *
417
     * @return array an array containing a list of all the courses matching the the search term
418
     */
419
    public static function searchCourses($categoryCode, $keyword, $limit, $justVisible = false, $conditions = [])
420
    {
421
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
422
        $limitFilter = self::getLimitFilterFromArray($limit);
423
        $avoidCoursesCondition = self::getAvoidCourseCondition();
424
        $visibilityCondition = $justVisible ? CourseManager::getCourseVisibilitySQLCondition('course', true) : '';
425
426
        $keyword = Database::escape_string($keyword);
427
        $categoryCode = Database::escape_string($categoryCode);
428
429
        $sqlInjectJoins = '';
430
        $where = 'AND 1 = 1 ';
431
        $sqlInjectWhere = '';
432
        $injectExtraFields = '1';
433
        if (!empty($conditions)) {
434
            $sqlInjectJoins = $conditions['inject_joins'];
435
            $where = $conditions['where'];
436
            $sqlInjectWhere = $conditions['inject_where'];
437
            $injectExtraFields = !empty($conditions['inject_extra_fields']) ? $conditions['inject_extra_fields'] : 1;
438
            $injectExtraFields = rtrim($injectExtraFields, ', ');
439
        }
440
441
        $categoryFilter = '';
442
        if ($categoryCode === 'ALL' || empty($categoryCode)) {
443
            // Nothing to do
444
        } elseif ($categoryCode === 'NONE') {
445
            $categoryFilter = ' AND category_code = "" ';
446
        } else {
447
            $categoryFilter = ' AND category_code = "'.$categoryCode.'" ';
448
        }
449
450
        //$sql = "SELECT DISTINCT course.*, $injectExtraFields
451
        $sql = "SELECT DISTINCT(course.id)
452
                FROM $courseTable course
453
                $sqlInjectJoins
454
                WHERE (
455
                        course.code LIKE '%".$keyword."%' OR
456
                        course.title LIKE '%".$keyword."%' OR
457
                        course.tutor_name LIKE '%".$keyword."%'
458
                    )
459
                    $where
460
                    $categoryFilter
461
                    $sqlInjectWhere
462
                    $avoidCoursesCondition
463
                    $visibilityCondition
464
                ORDER BY title, visual_code ASC
465
                $limitFilter
466
                ";
467
468
        if (api_is_multiple_url_enabled()) {
469
            $urlId = api_get_current_access_url_id();
470
            if (-1 != $urlId) {
471
                $tbl_url_rel_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
472
                $urlCondition = ' access_url_id = '.$urlId.' AND';
473
                $allowBaseCategories = api_get_configuration_value('allow_base_course_category');
474
                if ($allowBaseCategories) {
475
                    $urlCondition = ' (access_url_id = '.$urlId.' OR access_url_id = 1) AND ';
476
                }
477
                //SELECT DISTINCT course.*, $injectExtraFields
478
                $sql = "SELECT DISTINCT(course.id)
479
                        FROM $courseTable as course
480
                        INNER JOIN $tbl_url_rel_course as url_rel_course
481
                        ON (url_rel_course.c_id = course.id)
482
                        $sqlInjectJoins
483
                        WHERE
484
                            access_url_id = $urlId AND
485
                            (
486
                                code LIKE '%".$keyword."%' OR
487
                                title LIKE '%".$keyword."%' OR
488
                                tutor_name LIKE '%".$keyword."%'
489
                            )
490
                            $where
491
                            $categoryFilter
492
                            $sqlInjectWhere
493
                            $avoidCoursesCondition
494
                            $visibilityCondition
495
                        ORDER BY title, visual_code ASC
496
                        $limitFilter
497
                       ";
498
            }
499
        }
500
501
        $result = Database::query($sql);
502
        $courses = [];
503
        while ($row = Database::fetch_array($result)) {
504
            $courseId = $row['id'];
505
            $courseInfo = api_get_course_info_by_id($courseId);
506
            if (empty($courseInfo)) {
507
                continue;
508
            }
509
            $courseCode = $courseInfo['code'];
510
511
            $countUsers = CourseManager::get_user_list_from_course_code(
512
                $courseCode,
513
                0,
514
                null,
515
                null,
516
                null,
517
                true
518
            );
519
            $connectionsLastMonth = Tracking::get_course_connections_count(
520
                $courseId,
521
                0,
522
                api_get_utc_datetime(time() - (30 * 86400))
523
            );
524
525
            $courseInfo['point_info'] = CourseManager::get_course_ranking($courseId, 0);
526
            $courseInfo['tutor'] = $courseInfo['tutor_name'];
527
            $courseInfo['registration_code'] = !empty($courseInfo['registration_code']);
528
            $courseInfo['count_users'] = $countUsers;
529
            $courseInfo['count_connections'] = $connectionsLastMonth;
530
531
            $courses[] = $courseInfo;
532
        }
533
534
        return $courses;
535
    }
536
537
    /**
538
     * Gets extra fields listed in configuration option course_catalog_settings/extra_field_sort_options sorting order.
539
     *
540
     * @return array "extra_field_$id" => order (1 = ascending, -1 = descending)
541
     */
542
    public static function courseExtraFieldSortingOrder()
543
    {
544
        $order = [];
545
        $variableOrder = api_get_configuration_sub_value('course_catalog_settings/extra_field_sort_options', []);
546
        foreach (self::getCourseExtraFieldsAvailableForSorting() as $extraField) {
547
            $order['extra_field_'.$extraField->getId()] = $variableOrder[$extraField->getVariable()];
548
        }
549
550
        return $order;
551
    }
552
553
    /**
554
     * Gets the extra fields listed in configuration option course_catalog_settings/extra_field_sort_options.
555
     *
556
     * @return ExtraField[]
557
     */
558
    public static function getCourseExtraFieldsAvailableForSorting()
559
    {
560
        $variables = array_keys(
561
            api_get_configuration_sub_value('course_catalog_settings/extra_field_sort_options', [])
562
        );
563
        if (is_array($variables) && !empty($variables)) {
564
            return ExtraField::getExtraFieldsFromVariablesOrdered($variables, ExtraField::COURSE_FIELD_TYPE);
565
        }
566
567
        return [];
568
    }
569
570
    /**
571
     * Builds the list of possible course standard sort criteria.
572
     *
573
     * @return array option name => order (1 = ascending, -1 = descending)
574
     */
575
    public static function courseStandardSortOrder()
576
    {
577
        return api_get_configuration_sub_value(
578
            'course_catalog_settings/standard_sort_options',
579
            [
580
                'title' => 1,
581
                'creation_date' => -1,
582
                'count_users' => -1, // subscription count
583
                'point_info/point_average' => -1, // average score
584
                'point_info/total_score' => -1, // score sum
585
                'point_info/users' => -1, // vote count
586
            ]
587
        );
588
    }
589
590
    /**
591
     * Builds the list of possible course sort criteria to be used in an HTML select element.
592
     *
593
     * @return array select option name => display text
594
     */
595
    public static function courseSortOptions()
596
    {
597
        /** @var $extraFields ExtraField[] */
598
        $standardLabels = [
599
            'title' => get_lang('Title'),
600
            'creation_date' => get_lang('CreationDate'),
601
            'count_users' => get_lang('SubscriptionCount'),
602
            'point_info/point_average' => get_lang('PointAverage'),
603
            'point_info/total_score' => get_lang('TotalScore'),
604
            'point_info/users' => get_lang('VoteCount'),
605
        ];
606
        $options = [];
607
        foreach (array_keys(self::courseStandardSortOrder()) as $name) {
608
            $options[$name] = $standardLabels[$name] ?: $name;
609
        }
610
        foreach (self::getCourseExtraFieldsAvailableForSorting() as $extraField) {
611
            $options['extra_field_'.$extraField->getId()] = $extraField->getDisplayText();
612
        }
613
614
        return $options;
615
    }
616
617
    public static function courseSortOrder()
618
    {
619
        return self::courseStandardSortOrder() + self::courseExtraFieldSortingOrder();
620
    }
621
622
    /**
623
     * Wrapper for self::searchCourses which locally sorts the results according to $sortKey.
624
     *
625
     * @param string   $categoryCode can be 'ALL', 'NONE' or any existing course category code
626
     * @param string   $keyword      search pattern to be found in course code, title or tutor_name
627
     * @param array    $limit        associative array generated by \CoursesAndSessionsCatalog::getLimitArray()
628
     * @param bool     $justVisible  search only on visible courses in the catalogue
629
     * @param array    $conditions   associative array generated using \ExtraField::parseConditions
630
     * @param string[] $sortKeys     a subset of the keys of the array returned by courseSortOptions()
631
     *
632
     * @return array list of all the courses matching the the search term
633
     */
634
    public static function searchAndSortCourses(
635
        $categoryCode,
636
        $keyword,
637
        $limit,
638
        $justVisible = false,
639
        $conditions = [],
640
        $sortKeys = []
641
    ) {
642
        // Get ALL matching courses (no limit)
643
        $courses = self::searchCourses($categoryCode, $keyword, null, $justVisible, $conditions);
644
        // Do we have extra fields to sort on ?
645
        $extraFieldsToSortOn = [];
646
        foreach (self::getCourseExtraFieldsAvailableForSorting() as $extraField) {
647
            if (in_array('extra_field_'.$extraField->getId(), $sortKeys)) {
648
                $extraFieldsToSortOn[] = $extraField;
649
            }
650
        }
651
        if (!empty($extraFieldsToSortOn)) {
652
            // load extra field values and store them in $courses
653
            $courseIds = [];
654
            foreach ($courses as $course) {
655
                $courseIds[] = $course['real_id'];
656
            }
657
            $values = ExtraField::getValueForEachExtraFieldForEachItem($extraFieldsToSortOn, $courseIds);
658
            foreach ($courses as &$course) {
659
                $courseId = $course['real_id'];
660
                if (array_key_exists($courseId, $values)) {
661
                    foreach ($values[$courseId] as $extraFieldId => $value) {
662
                        $course['extra_field_'.$extraFieldId] = $value;
663
                    }
664
                }
665
            }
666
            unset($course);
667
        }
668
669
        // do we have $course['groupKey']['subKey'] to sort on, such as 'point_info/users' ?
670
        foreach ($sortKeys as $key) {
671
            if (false !== strpos($key, '/')) {
672
                foreach ($courses as &$course) {
673
                    $subValue = api_array_sub_value($course, $key);
674
                    if (!is_null($subValue)) {
675
                        $course[$key] = $subValue;
676
                    }
677
                }
678
                unset($course);
679
            }
680
        }
681
        $sortOrder = self::courseSortOrder();
682
        usort($courses, function ($a, $b) use ($sortKeys, $sortOrder) {
683
            foreach ($sortKeys as $key) {
684
                $valueA = array_key_exists($key, $a) ? $a[$key] : null;
685
                $valueB = array_key_exists($key, $b) ? $b[$key] : null;
686
                if ($valueA !== $valueB) {
687
                    $aIsLessThanB = (is_string($valueA) && is_string($valueB))
688
                        ? strtolower($valueA) < strtolower($valueB)
689
                        : $valueA < $valueB;
690
                    $reverseOrder = (array_key_exists($key, $sortOrder) && -1 === $sortOrder[$key]);
691
                    $aIsBeforeB = ($aIsLessThanB xor $reverseOrder);
692
693
                    return $aIsBeforeB ? -1 : 1;
694
                }
695
            }
696
697
            return 0;
698
        });
699
700
        return array_slice($courses, $limit['start'], $limit['length']);
701
    }
702
703
    /**
704
     * List the sessions.
705
     *
706
     * @param string $date
707
     * @param array  $limit
708
     * @param bool   $returnQueryBuilder
709
     * @param bool   $getCount
710
     *
711
     * @return array|\Doctrine\ORM\Query The session list
712
     */
713
    public static function browseSessions($date = null, $limit = [], $returnQueryBuilder = false, $getCount = false)
714
    {
715
        $urlId = api_get_current_access_url_id();
716
        $em = Database::getManager();
717
        $qb = $em->createQueryBuilder();
718
        $qb2 = $em->createQueryBuilder();
719
720
        $qb = $qb
721
            ->select('s')
722
            ->from('ChamiloCoreBundle:Session', 's')
723
            ->where(
724
                $qb->expr()->in(
725
                    's',
726
                    $qb2
727
                        ->select('s2')
728
                        ->from('ChamiloCoreBundle:AccessUrlRelSession', 'url')
729
                        ->join('ChamiloCoreBundle:Session', 's2')
730
                        ->where(
731
                            $qb->expr()->eq('url.sessionId ', 's2.id')
732
                        )->andWhere(
733
                            $qb->expr()->eq('url.accessUrlId ', $urlId))
734
                        ->getDQL()
735
                )
736
            )
737
            ->andWhere($qb->expr()->gt('s.nbrCourses', 0))
738
        ;
739
740
        if (!empty($date)) {
741
            $qb->andWhere(
742
                $qb->expr()->orX(
743
                    $qb->expr()->isNull('s.accessEndDate'),
744
                    $qb->expr()->andX(
745
                        $qb->expr()->isNotNull('s.accessStartDate'),
746
                        $qb->expr()->isNotNull('s.accessEndDate'),
747
                        $qb->expr()->lte('s.accessStartDate', $date),
748
                        $qb->expr()->gte('s.accessEndDate', $date)
749
                    ),
750
                    $qb->expr()->andX(
751
                        $qb->expr()->isNull('s.accessStartDate'),
752
                        $qb->expr()->isNotNull('s.accessEndDate'),
753
                        $qb->expr()->gte('s.accessEndDate', $date)
754
                    )
755
                )
756
            );
757
        }
758
759
        if ($getCount) {
760
            $qb->select('count(s)');
761
        }
762
763
        $qb = self::hideFromSessionCatalogCondition($qb);
764
765
        if (!empty($limit)) {
766
            $qb
767
                ->setFirstResult($limit['start'])
768
                ->setMaxResults($limit['length'])
769
            ;
770
        }
771
772
        $query = $qb->getQuery();
773
774
        if ($returnQueryBuilder) {
775
            return $query;
776
        }
777
778
        if ($getCount) {
779
            return $query->getSingleScalarResult();
780
        }
781
782
        return $query->getResult();
783
    }
784
785
    /**
786
     * @param \Doctrine\ORM\QueryBuilder $qb
787
     *
788
     * @return mixed
789
     */
790
    public static function hideFromSessionCatalogCondition($qb)
791
    {
792
        $em = Database::getManager();
793
        $qb3 = $em->createQueryBuilder();
794
795
        $extraField = new ExtraFieldModel('session');
796
        $extraFieldInfo = $extraField->get_handler_field_info_by_field_variable('hide_from_catalog');
797
        if (!empty($extraFieldInfo)) {
798
            $qb->andWhere(
799
                $qb->expr()->notIn(
800
                    's',
801
                    $qb3
802
                        ->select('s3')
803
                        ->from('ChamiloCoreBundle:ExtraFieldValues', 'fv')
804
                        ->innerJoin('ChamiloCoreBundle:Session', 's3', Join::WITH, 'fv.itemId = s3.id')
805
                        ->where(
806
                            $qb->expr()->eq('fv.field', $extraFieldInfo['id'])
807
                        )->andWhere(
808
                            $qb->expr()->eq('fv.value ', 1)
809
                        )
810
                        ->getDQL()
811
                )
812
            );
813
        }
814
815
        return $qb;
816
    }
817
818
    /**
819
     * Search sessions by the tags in their courses.
820
     *
821
     * @param string $termTag Term for search in tags
822
     * @param array  $limit   Limit info
823
     *
824
     * @return array The sessions
825
     */
826
    public static function browseSessionsByTags($termTag, array $limit, $getCount = false)
827
    {
828
        $em = Database::getManager();
829
        $qb = $em->createQueryBuilder();
830
831
        $urlId = api_get_current_access_url_id();
832
833
        $qb->select('s')
834
            ->distinct()
835
            ->from('ChamiloCoreBundle:Session', 's')
836
            ->innerJoin(
837
                'ChamiloCoreBundle:SessionRelCourse',
838
                'src',
839
                Join::WITH,
840
                's.id = src.session'
841
            )
842
            ->innerJoin(
843
                'ChamiloCoreBundle:AccessUrlRelSession',
844
                'url',
845
                Join::WITH,
846
                'url.sessionId = s.id'
847
            )
848
            ->innerJoin(
849
                'ChamiloCoreBundle:ExtraFieldRelTag',
850
                'frt',
851
                Join::WITH,
852
                'src.course = frt.itemId'
853
            )
854
            ->innerJoin(
855
                'ChamiloCoreBundle:Tag',
856
                't',
857
                Join::WITH,
858
                'frt.tagId = t.id'
859
            )
860
            ->innerJoin(
861
                'ChamiloCoreBundle:ExtraField',
862
                'f',
863
                Join::WITH,
864
                'frt.fieldId = f.id'
865
            )
866
            ->where(
867
                $qb->expr()->like('t.tag', ':tag')
868
            )
869
            ->andWhere(
870
                $qb->expr()->eq('f.extraFieldType', ExtraField::COURSE_FIELD_TYPE)
871
            )
872
            ->andWhere($qb->expr()->gt('s.nbrCourses', 0))
873
            ->andWhere($qb->expr()->eq('url.accessUrlId', $urlId))
874
            ->setParameter('tag', "$termTag%")
875
        ;
876
877
        if (!empty($limit)) {
878
            $qb
879
                ->setFirstResult($limit['start'])
880
                ->setMaxResults($limit['length'])
881
            ;
882
        }
883
884
        $qb = self::hideFromSessionCatalogCondition($qb);
885
886
        if ($getCount) {
887
            $qb->select('count(s)');
888
889
            return $qb->getQuery()->getSingleScalarResult();
890
        }
891
892
        return $qb->getQuery()->getResult();
893
    }
894
895
    /**
896
     * Search sessions by the title.
897
     *
898
     * @param string $keyword
899
     * @param array  $limit   Limit info
900
     *
901
     * @return array The sessions
902
     */
903
    public static function getSessionsByName($keyword, array $limit, $getCount = false)
904
    {
905
        $em = Database::getManager();
906
        $qb = $em->createQueryBuilder();
907
        $urlId = api_get_current_access_url_id();
908
909
        $qb->select('s')
910
            ->distinct()
911
            ->from('ChamiloCoreBundle:Session', 's')
912
            ->innerJoin(
913
                'ChamiloCoreBundle:SessionRelCourse',
914
                'src',
915
                Join::WITH,
916
                's.id = src.session'
917
            )
918
            ->innerJoin(
919
                'ChamiloCoreBundle:AccessUrlRelSession',
920
                'url',
921
                Join::WITH,
922
                'url.sessionId = s.id'
923
            )
924
            ->andWhere($qb->expr()->eq('url.accessUrlId', $urlId))
925
            ->andWhere('s.name LIKE :keyword')
926
            ->andWhere($qb->expr()->gt('s.nbrCourses', 0))
927
            ->setParameter('keyword', "%$keyword%")
928
        ;
929
930
        if (!empty($limit)) {
931
            $qb
932
                ->setFirstResult($limit['start'])
933
                ->setMaxResults($limit['length']);
934
        }
935
936
        $qb = self::hideFromSessionCatalogCondition($qb);
937
938
        if ($getCount) {
939
            $qb->select('count(s)');
940
941
            return $qb->getQuery()->getSingleScalarResult();
942
        }
943
944
        return $qb->getQuery()->getResult();
945
    }
946
947
    /**
948
     * Build a recursive tree of course categories.
949
     *
950
     * @param array $categories
951
     * @param int   $parentId
952
     * @param int   $level
953
     *
954
     * @return array
955
     */
956
    public static function buildCourseCategoryTree($categories, $parentId = 0, $level = 0)
957
    {
958
        $list = [];
959
        $count = 0;
960
        $level++;
961
        foreach ($categories as $category) {
962
            if (empty($category['parent_id'])) {
963
                continue;
964
            }
965
            if ($category['parent_id'] == $parentId) {
966
                $list[$category['code']] = $category;
967
                $count += $category['number_courses'];
968
                $list[$category['code']]['level'] = $level;
969
                list($subList, $childrenCount) = self::buildCourseCategoryTree(
970
                    $categories,
971
                    $category['code'],
972
                    $level
973
                );
974
                $list[$category['code']]['number_courses'] += $childrenCount;
975
                foreach ($subList as $item) {
976
                    $list[$item['code']] = $item;
977
                }
978
                $count += $childrenCount;
979
            }
980
        }
981
982
        return [$list, $count];
983
    }
984
985
    /**
986
     * List Code Search Category.
987
     *
988
     * @param string $code
989
     *
990
     * @return array
991
     */
992
    public static function childrenCategories($code)
993
    {
994
        $allCategories = CourseCategory::getAllCategories();
995
        $list = [];
996
        $row = [];
997
998
        if ($code !== 'ALL' && $code !== 'NONE') {
999
            foreach ($allCategories as $category) {
1000
                if ($category['code'] === $code) {
1001
                    $list = self::buildCourseCategoryTree($allCategories, $category['code'], 0);
1002
                }
1003
            }
1004
            foreach ($list[0] as $item) {
1005
                $row[] = $item['code'];
1006
            }
1007
        }
1008
1009
        return $row;
1010
    }
1011
1012
    /**
1013
     * Get the image of a course for the catalog.
1014
     */
1015
    public static function returnThumbnail(array $course): string
1016
    {
1017
        $course_path = api_get_path(SYS_COURSE_PATH).$course['directory'];
1018
1019
        if (file_exists($course_path.'/course-pic.png')) {
1020
            // redimensioned image 85x85
1021
            return api_get_path(WEB_COURSE_PATH).$course['directory'].'/course-pic.png';
1022
        }
1023
1024
        // without picture
1025
        return Display::return_icon(
1026
            'session_default.png',
1027
            null,
1028
            null,
1029
            null,
1030
            null,
1031
            true
1032
        );
1033
    }
1034
1035
    public static function return_teacher(array $courseInfo): string
1036
    {
1037
        $teachers = CourseManager::getTeachersFromCourse($courseInfo['real_id']);
1038
        $length = count($teachers);
1039
1040
        if (!$length) {
1041
            return '';
1042
        }
1043
1044
        $html = '<div class="block-author">';
1045
        if ($length > 6) {
1046
            $html .= '<a
1047
            id="plist"
1048
            data-trigger="focus"
1049
            tabindex="0" role="button"
1050
            class="btn btn-default panel_popover"
1051
            data-toggle="popover"
1052
            title="'.addslashes(get_lang('CourseTeachers')).'"
1053
            data-html="true"
1054
        >
1055
            <i class="fa fa-graduation-cap" aria-hidden="true"></i>
1056
        </a>';
1057
            $html .= '<div id="popover-content-plist" class="hide">';
1058
            foreach ($teachers as $value) {
1059
                $name = $value['firstname'].' '.$value['lastname'];
1060
                $html .= '<div class="popover-teacher">';
1061
                $html .= '<a href="'.$value['url'].'" class="ajax" data-title="'.$name.'" title="'.$name.'">
1062
                        <img src="'.$value['avatar'].'" title="'.$name.'" alt="'.get_lang('UserPicture').'"/></a>';
1063
                $html .= '<div class="teachers-details"><h5>
1064
                        <a href="'.$value['url'].'" class="ajax" data-title="'.$name.'" title="'.$name.'">'
1065
                    .$name.'</a></h5></div>';
1066
                $html .= '</div>';
1067
            }
1068
            $html .= '</div>';
1069
        } else {
1070
            foreach ($teachers as $value) {
1071
                $name = $value['firstname'].' '.$value['lastname'];
1072
                if ($length > 2) {
1073
                    $html .= '<a href="'.$value['url'].'" class="ajax" data-title="'.$name.'" title="'.$name.'">
1074
                        <img src="'.$value['avatar'].'" title="'.$name.'" alt="'.get_lang('UserPicture').'"/></a>';
1075
                } else {
1076
                    $html .= '<a href="'.$value['url'].'" class="ajax" data-title="'.$name.'" title="'.$name.'">
1077
                        <img src="'.$value['avatar'].'" title="'.$name.'" alt="'.get_lang('UserPicture').'"/></a>';
1078
                    $html .= '<div class="teachers-details"><h5>
1079
                        <a href="'.$value['url'].'" class="ajax" data-title="'.$name.'">'
1080
                        .$name.'</a></h5><p>'.get_lang('Teacher').'</p></div>';
1081
                }
1082
            }
1083
        }
1084
        $html .= '</div>';
1085
1086
        return $html;
1087
    }
1088
1089
    /**
1090
     * Display the already registerd text in a course in the course catalog.
1091
     *
1092
     * @param $status
1093
     *
1094
     * @return string HTML string
1095
     */
1096
    public static function return_already_registered_label($status)
1097
    {
1098
        $icon = '<em class="fa fa-check"></em>';
1099
        $title = get_lang('YouAreATeacherOfThisCourse');
1100
        if ($status === 'student') {
1101
            $icon = '<em class="fa fa-check"></em>';
1102
            $title = get_lang('AlreadySubscribed');
1103
        }
1104
1105
        $html = Display::tag(
1106
            'span',
1107
            $icon.' '.$title,
1108
            [
1109
                'id' => 'register',
1110
                'class' => 'label-subscribed text-success',
1111
                'title' => $title,
1112
                'aria-label' => $title,
1113
            ]
1114
        );
1115
1116
        return $html.PHP_EOL;
1117
    }
1118
1119
    /**
1120
     * Display the register button of a course in the course catalog.
1121
     *
1122
     * @param $course
1123
     * @param $stok
1124
     * @param $categoryCode
1125
     * @param $search_term
1126
     *
1127
     * @return string
1128
     */
1129
    public static function return_register_button($course, $stok, $categoryCode, $search_term)
1130
    {
1131
        $title = get_lang('Subscribe');
1132
        $action = 'subscribe_course';
1133
        if (!empty($course['registration_code'])) {
1134
            $action = 'subscribe_course_validation';
1135
        }
1136
1137
        return Display::url(
1138
            Display::returnFontAwesomeIcon('check').PHP_EOL.$title,
1139
            api_get_path(WEB_CODE_PATH).'auth/courses.php'
1140
                .'?action='.$action.'&sec_token='.$stok
1141
                .'&course_code='.$course['code'].'&search_term='.$search_term.'&category_code='.$categoryCode,
1142
            ['class' => 'btn btn-success btn-sm', 'title' => $title, 'aria-label' => $title]
1143
        );
1144
    }
1145
1146
    /**
1147
     * Display the unregister button of a course in the course catalog.
1148
     *
1149
     * @param array  $course
1150
     * @param string $stok
1151
     * @param string $search_term
1152
     * @param string $categoryCode
1153
     * @param int    $sessionId
1154
     *
1155
     * @return string
1156
     */
1157
    public static function return_unregister_button($course, $stok, $search_term, $categoryCode, $sessionId = 0)
1158
    {
1159
        $title = get_lang('Unsubscription');
1160
        $search_term = Security::remove_XSS($search_term);
1161
        $categoryCode = Security::remove_XSS($categoryCode);
1162
        $sessionId = (int) $sessionId;
1163
1164
        $url = api_get_path(WEB_CODE_PATH).'auth/courses.php'
1165
            .'?action=unsubscribe&sec_token='.$stok.'&sid='.$sessionId.'&course_code='.$course['code'].
1166
            '&search_term='.$search_term.'&category_code='.$categoryCode;
1167
1168
        return Display::url(
1169
            Display::returnFontAwesomeIcon('sign-in').PHP_EOL.$title,
1170
            $url,
1171
            ['class' => 'btn btn-danger btn-sm', 'title' => $title, 'aria-label' => $title]
1172
        );
1173
    }
1174
1175
    /**
1176
     * Get a HTML button for subscribe to session.
1177
     *
1178
     * @param int    $sessionId         The session ID
1179
     * @param string $sessionName       The session name
1180
     * @param bool   $checkRequirements Optional.
1181
     *                                  Whether the session has requirement. Default is false
1182
     * @param bool   $includeText       Optional. Whether show the text in button
1183
     * @param bool   $btnBing
1184
     *
1185
     * @return string The button HTML
1186
     */
1187
    public static function getRegisteredInSessionButton(
1188
        $sessionId,
1189
        $sessionName,
1190
        $checkRequirements = false,
1191
        $includeText = false,
1192
        $btnBing = false
1193
    ) {
1194
        $sessionId = (int) $sessionId;
1195
        $class = 'btn-sm';
1196
        if ($btnBing) {
1197
            $class = 'btn-lg btn-block';
1198
        }
1199
1200
        if ($checkRequirements) {
1201
            return self::getRequirements($sessionId, SequenceResource::SESSION_TYPE, $includeText, $class);
1202
        }
1203
1204
        $catalogSessionAutoSubscriptionAllowed = false;
1205
        if (api_get_setting('catalog_allow_session_auto_subscription') === 'true') {
1206
            $catalogSessionAutoSubscriptionAllowed = true;
1207
        }
1208
1209
        $url = api_get_path(WEB_CODE_PATH);
1210
1211
        if ($catalogSessionAutoSubscriptionAllowed) {
1212
            $url .= 'auth/courses.php?';
1213
            $url .= http_build_query([
1214
                'action' => 'subscribe_to_session',
1215
                'session_id' => $sessionId,
1216
            ]);
1217
1218
            $result = Display::toolbarButton(
1219
                get_lang('Subscribe'),
1220
                $url,
1221
                'pencil',
1222
                'primary',
1223
                [
1224
                    'class' => $class.' ajax',
1225
                    'data-title' => get_lang('AreYouSureToSubscribe'),
1226
                    'data-size' => 'md',
1227
                    'title' => get_lang('Subscribe'),
1228
                ],
1229
                $includeText
1230
            );
1231
        } else {
1232
            $url .= 'inc/email_editor.php?';
1233
            $url .= http_build_query([
1234
                'action' => 'subscribe_me_to_session',
1235
                'session' => Security::remove_XSS($sessionName),
1236
            ]);
1237
1238
            $result = Display::toolbarButton(
1239
                get_lang('SubscribeToSessionRequest'),
1240
                $url,
1241
                'pencil',
1242
                'primary',
1243
                ['class' => $class],
1244
                $includeText
1245
            );
1246
        }
1247
1248
        $hook = HookResubscribe::create();
1249
        if (!empty($hook)) {
1250
            $hook->setEventData([
1251
                'session_id' => $sessionId,
1252
            ]);
1253
            try {
1254
                $hook->notifyResubscribe(HOOK_EVENT_TYPE_PRE);
1255
            } catch (Exception $exception) {
1256
                $result = $exception->getMessage();
1257
            }
1258
        }
1259
1260
        return $result;
1261
    }
1262
1263
    public static function getRequirements($id, $type, $includeText, $class, $sessionId = 0)
1264
    {
1265
        $id = (int) $id;
1266
        $type = (int) $type;
1267
        $url = api_get_path(WEB_AJAX_PATH).'sequence.ajax.php?';
1268
        $url .= http_build_query(
1269
            [
1270
                'a' => 'get_requirements',
1271
                'id' => $id,
1272
                'type' => $type,
1273
                'sid' => $sessionId,
1274
            ]
1275
        );
1276
1277
        return Display::toolbarButton(
1278
            get_lang('CheckRequirements'),
1279
            $url,
1280
            'shield',
1281
            'info',
1282
            [
1283
                'class' => $class.' ajax',
1284
                'data-title' => get_lang('CheckRequirements'),
1285
                'data-size' => 'md',
1286
                'title' => get_lang('CheckRequirements'),
1287
            ],
1288
            $includeText
1289
        );
1290
    }
1291
1292
    /**
1293
     * Generate a label if the user has been  registered in session.
1294
     *
1295
     * @return string The label
1296
     */
1297
    public static function getAlreadyRegisteredInSessionLabel()
1298
    {
1299
        $icon = '<em class="fa fa-graduation-cap"></em>';
1300
1301
        return Display::div(
1302
            $icon,
1303
            [
1304
                'class' => 'btn btn-default btn-sm registered',
1305
                'title' => get_lang("AlreadyRegisteredToSession"),
1306
            ]
1307
        );
1308
    }
1309
1310
    public static function getSessionPagination($action, $countSessions, $limit)
1311
    {
1312
        $pageTotal = ceil($countSessions / $limit['length']);
1313
        $pagination = '';
1314
        // Do NOT show pagination if only one page or less
1315
        if ($pageTotal > 1) {
1316
            $pagination = self::getCatalogPagination(
1317
                $limit['current'],
1318
                $limit['length'],
1319
                $pageTotal,
1320
                null,
1321
                $action
1322
            );
1323
        }
1324
1325
        return $pagination;
1326
    }
1327
1328
    /**
1329
     * Return Session catalog rendered view.
1330
     */
1331
    public static function sessionList(bool $returnHtml = false): ?string
1332
    {
1333
        $date = $_POST['date'] ?? '';
1334
        $limit = self::getLimitArray();
1335
1336
        $countSessions = self::browseSessions($date, [], false, true);
1337
        $sessions = self::browseSessions($date, $limit);
1338
1339
        $pagination = self::getSessionPagination('display_sessions', $countSessions, $limit);
1340
        $sessionsBlocks = self::getFormattedSessionsBlock($sessions);
1341
1342
        // Get session search catalogue URL
1343
        $courseUrl = self::getCatalogUrl(
1344
            1,
1345
            $limit['length'],
1346
            null,
1347
            'subscribe'
1348
        );
1349
1350
        $tpl = new Template();
1351
        $tpl->assign('actions', self::getTabList(2));
1352
        $tpl->assign('show_courses', self::showCourses());
1353
        $tpl->assign('show_sessions', self::showSessions());
1354
        $tpl->assign('show_tutor', api_get_setting('show_session_coach') === 'true');
1355
        $tpl->assign('course_url', $courseUrl);
1356
        $tpl->assign('catalog_pagination', $pagination);
1357
        $tpl->assign('search_token', Security::get_token());
1358
        $tpl->assign('search_date', $date);
1359
        $tpl->assign('web_session_courses_ajax_url', api_get_path(WEB_AJAX_PATH).'course.ajax.php');
1360
        $tpl->assign('sessions', $sessionsBlocks);
1361
        $tpl->assign('already_subscribed_label', self::getAlreadyRegisteredInSessionLabel());
1362
        $tpl->assign('catalog_settings', self::getCatalogSearchSettings());
1363
1364
        $templateContent = $tpl->fetch(
1365
            $tpl->get_template('catalog/session_catalog.tpl')
1366
        );
1367
1368
        if ($returnHtml) {
1369
            return $templateContent;
1370
        }
1371
1372
        $tpl->assign('content', $templateContent);
1373
        $tpl->display_one_col_template();
1374
1375
        return null;
1376
    }
1377
1378
    /**
1379
     * Show the Session Catalogue with filtered session by course tags.
1380
     */
1381
    public static function sessionsListByName()
1382
    {
1383
        $limit = self::getLimitArray();
1384
        $keyword = $_REQUEST['keyword'] ?? null;
1385
        $courseUrl = self::getCatalogUrl(
1386
            1,
1387
            $limit['length'],
1388
            null,
1389
            'subscribe'
1390
        );
1391
1392
        $count = self::getSessionsByName($keyword, [], true);
1393
        $sessions = self::getSessionsByName($keyword, $limit);
1394
        $sessionsBlocks = self::getFormattedSessionsBlock($sessions);
1395
        $pagination = self::getSessionPagination('search_session_title', $count, $limit);
1396
1397
        $tpl = new Template();
1398
        $tpl->assign('catalog_pagination', $pagination);
1399
        $tpl->assign('actions', self::getTabList(2));
1400
        $tpl->assign('show_courses', self::showCourses());
1401
        $tpl->assign('show_sessions', self::showSessions());
1402
        $tpl->assign('show_tutor', api_get_setting('show_session_coach') === 'true');
1403
        $tpl->assign('course_url', $courseUrl);
1404
        $tpl->assign('already_subscribed_label', self::getAlreadyRegisteredInSessionLabel());
1405
        $tpl->assign('search_token', Security::get_token());
1406
        $tpl->assign('keyword', Security::remove_XSS($keyword));
1407
        $tpl->assign('sessions', $sessionsBlocks);
1408
        $tpl->assign('catalog_settings', self::getCatalogSearchSettings());
1409
1410
        $templateContent = $tpl->fetch(
1411
            $tpl->get_template('catalog/session_catalog.tpl')
1412
        );
1413
1414
        $tpl->assign('content', $templateContent);
1415
        $tpl->display_one_col_template();
1416
    }
1417
1418
    public static function getCatalogSearchSettings()
1419
    {
1420
        $settings = api_get_configuration_value('catalog_settings');
1421
        if (empty($settings)) {
1422
            // Default everything is visible
1423
            $settings = [
1424
                'sessions' => [
1425
                    'by_title' => true,
1426
                    'by_date' => true,
1427
                    'by_tag' => true,
1428
                    'show_session_info' => true,
1429
                    'show_session_date' => true,
1430
                ],
1431
                'courses' => [
1432
                    'by_title' => true,
1433
                ],
1434
            ];
1435
        }
1436
1437
        return $settings;
1438
    }
1439
1440
    /**
1441
     * @param int $active
1442
     *
1443
     * @return string
1444
     */
1445
    public static function getTabList($active = 1)
1446
    {
1447
        $pageLength = isset($_GET['pageLength']) ? (int) $_GET['pageLength'] : self::PAGE_LENGTH;
1448
1449
        $url = self::getCatalogUrl(1, $pageLength, null, 'display_sessions');
1450
        $headers = [];
1451
        if (self::showCourses()) {
1452
            $headers[] = [
1453
                'url' => api_get_path(WEB_CODE_PATH).'auth/courses.php',
1454
                'content' => get_lang('CourseManagement'),
1455
            ];
1456
        }
1457
1458
        if (self::showSessions()) {
1459
            $headers[] = [
1460
                'url' => $url,
1461
                'content' => get_lang('SessionList'),
1462
            ];
1463
        }
1464
1465
        // If only one option hide menu.
1466
        if (1 === count($headers)) {
1467
            return '';
1468
        }
1469
1470
        return Display::tabsOnlyLink($headers, $active);
1471
    }
1472
1473
    /**
1474
     * Show the Session Catalogue with filtered session by course tags.
1475
     */
1476
    public static function sessionsListByCoursesTag()
1477
    {
1478
        $limit = self::getLimitArray();
1479
        $searchTag = $_REQUEST['search_tag'] ?? '';
1480
        $searchDate = $_REQUEST['date'] ?? date('Y-m-d');
1481
        $courseUrl = self::getCatalogUrl(
1482
            1,
1483
            $limit['length'],
1484
            null,
1485
            'subscribe'
1486
        );
1487
1488
        $sessions = self::browseSessionsByTags($searchTag, $limit);
1489
        $sessionsBlocks = self::getFormattedSessionsBlock($sessions);
1490
1491
        $count = self::browseSessionsByTags($searchTag, [], true);
1492
        $pagination = self::getSessionPagination('search_tag', $count, $limit);
1493
1494
        $tpl = new Template();
1495
        $tpl->assign('catalog_pagination', $pagination);
1496
        $tpl->assign('show_courses', self::showCourses());
1497
        $tpl->assign('show_sessions', self::showSessions());
1498
        $tpl->assign('show_tutor', api_get_setting('show_session_coach') === 'true');
1499
        $tpl->assign('course_url', $courseUrl);
1500
        $tpl->assign('already_subscribed_label', self::getAlreadyRegisteredInSessionLabel());
1501
        $tpl->assign('search_token', Security::get_token());
1502
        $tpl->assign('search_date', Security::remove_XSS($searchDate));
1503
        $tpl->assign('search_tag', Security::remove_XSS($searchTag));
1504
        $tpl->assign('sessions', $sessionsBlocks);
1505
1506
        $templateContent = $tpl->fetch(
1507
            $tpl->get_template('catalog/session_catalog.tpl')
1508
        );
1509
1510
        $tpl->assign('content', $templateContent);
1511
        $tpl->display_one_col_template();
1512
    }
1513
1514
    /**
1515
     * @return array
1516
     */
1517
    public static function getLimitArray()
1518
    {
1519
        $pageCurrent = isset($_REQUEST['pageCurrent']) ? (int) $_GET['pageCurrent'] : 1;
1520
        $pageLength = isset($_REQUEST['pageLength']) ? (int) $_GET['pageLength'] : self::PAGE_LENGTH;
1521
1522
        return [
1523
            'start' => ($pageCurrent - 1) * $pageLength,
1524
            'current' => $pageCurrent,
1525
            'length' => $pageLength,
1526
        ];
1527
    }
1528
1529
    /**
1530
     * Get the formatted data for sessions block to be displayed on Session Catalog page.
1531
     *
1532
     * @param array $sessions The session list
1533
     *
1534
     * @return array
1535
     */
1536
    public static function getFormattedSessionsBlock(array $sessions)
1537
    {
1538
        $extraFieldValue = new ExtraFieldValue('session');
1539
        $userId = api_get_user_id();
1540
        $sessionsBlocks = [];
1541
        $entityManager = Database::getManager();
1542
        $sessionRelCourseRepo = $entityManager->getRepository('ChamiloCoreBundle:SessionRelCourse');
1543
        $extraFieldRepo = $entityManager->getRepository('ChamiloCoreBundle:ExtraField');
1544
        $extraFieldRelTagRepo = $entityManager->getRepository('ChamiloCoreBundle:ExtraFieldRelTag');
1545
1546
        $tagsField = $extraFieldRepo->findOneBy([
1547
            'extraFieldType' => Chamilo\CoreBundle\Entity\ExtraField::COURSE_FIELD_TYPE,
1548
            'variable' => 'tags',
1549
        ]);
1550
1551
        /** @var \Chamilo\CoreBundle\Entity\Session $session */
1552
        foreach ($sessions as $session) {
1553
            $sessionDates = SessionManager::parseSessionDates([
1554
                'display_start_date' => $session->getDisplayStartDate(),
1555
                'display_end_date' => $session->getDisplayEndDate(),
1556
                'access_start_date' => $session->getAccessStartDate(),
1557
                'access_end_date' => $session->getAccessEndDate(),
1558
                'coach_access_start_date' => $session->getCoachAccessStartDate(),
1559
                'coach_access_end_date' => $session->getCoachAccessEndDate(),
1560
            ]);
1561
1562
            $imageField = $extraFieldValue->get_values_by_handler_and_field_variable(
1563
                $session->getId(),
1564
                'image'
1565
            );
1566
            $sessionCourseTags = [];
1567
            if (!is_null($tagsField)) {
1568
                $sessionRelCourses = $sessionRelCourseRepo->findBy([
1569
                    'session' => $session,
1570
                ]);
1571
                /** @var SessionRelCourse $sessionRelCourse */
1572
                foreach ($sessionRelCourses as $sessionRelCourse) {
1573
                    $courseTags = $extraFieldRelTagRepo->getTags(
1574
                        $tagsField,
1575
                        $sessionRelCourse->getCourse()->getId()
1576
                    );
1577
                    /** @var Tag $tag */
1578
                    foreach ($courseTags as $tag) {
1579
                        $sessionCourseTags[] = $tag->getTag();
1580
                    }
1581
                }
1582
            }
1583
1584
            if (!empty($sessionCourseTags)) {
1585
                $sessionCourseTags = array_unique($sessionCourseTags);
1586
            }
1587
1588
            /** @var SequenceResourceRepository $repo */
1589
            $repo = $entityManager->getRepository('ChamiloCoreBundle:SequenceResource');
1590
            $sequences = $repo->getRequirementsAndDependenciesWithinSequences(
1591
                $session->getId(),
1592
                SequenceResource::SESSION_TYPE
1593
            );
1594
1595
            $hasRequirements = false;
1596
            foreach ($sequences as $sequence) {
1597
                if (count($sequence['requirements']) === 0) {
1598
                    continue;
1599
                }
1600
                $hasRequirements = true;
1601
                break;
1602
            }
1603
            $cat = $session->getCategory();
1604
            if (empty($cat)) {
1605
                $cat = null;
1606
                $catName = '';
1607
            } else {
1608
                $catName = $cat->getName();
1609
            }
1610
1611
            $generalCoach = $session->getGeneralCoach();
1612
            $coachId = $generalCoach ? $generalCoach->getId() : 0;
1613
            $coachName = $generalCoach ? UserManager::formatUserFullName($session->getGeneralCoach()) : '';
1614
1615
            $actions = null;
1616
            if (api_is_platform_admin()) {
1617
                $actions = api_get_path(WEB_CODE_PATH).'session/resume_session.php?id_session='.$session->getId();
1618
            }
1619
1620
            $plugin = \BuyCoursesPlugin::create();
1621
            $isThisSessionOnSale = $plugin->getBuyCoursePluginPrice($session);
1622
1623
            $sessionsBlock = [
1624
                'id' => $session->getId(),
1625
                'name' => $session->getName(),
1626
                'image' => isset($imageField['value']) ? $imageField['value'] : null,
1627
                'nbr_courses' => $session->getNbrCourses(),
1628
                'nbr_users' => $session->getNbrUsers(),
1629
                'coach_id' => $coachId,
1630
                'coach_url' => $generalCoach
1631
                    ? api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$coachId
1632
                    : '',
1633
                'coach_name' => $coachName,
1634
                'coach_avatar' => UserManager::getUserPicture($coachId, USER_IMAGE_SIZE_SMALL),
1635
                'is_subscribed' => SessionManager::isUserSubscribedAsStudent($session->getId(), $userId),
1636
                '' => Display::return_icon(
1637
                    'window_list.png',
1638
                    $session->getName(),
1639
                    [],
1640
                    ICON_SIZE_MEDIUM
1641
                ),
1642
                'date' => $sessionDates['display'],
1643
                'price' => !empty($isThisSessionOnSale['html']) ? $isThisSessionOnSale['html'] : '',
1644
                'subscribe_button' => isset($isThisSessionOnSale['buy_button']) ? $isThisSessionOnSale['buy_button'] : self::getRegisteredInSessionButton(
1645
                    $session->getId(),
1646
                    $session->getName(),
1647
                    $hasRequirements
1648
                ),
1649
                'show_description' => $session->getShowDescription(),
1650
                'description' => $session->getDescription(),
1651
                'category' => $catName,
1652
                'tags' => $sessionCourseTags,
1653
                'edit_actions' => $actions,
1654
                'duration' => SessionManager::getDayLeftInSession(
1655
                    ['id' => $session->getId(), 'duration' => $session->getDuration()],
1656
                    $userId
1657
                ),
1658
            ];
1659
1660
            $sessionsBlocks[] = array_merge($sessionsBlock, $sequences);
1661
        }
1662
1663
        return $sessionsBlocks;
1664
    }
1665
1666
    /**
1667
     * Get Pagination HTML div.
1668
     *
1669
     * @param int    $pageCurrent
1670
     * @param int    $pageLength
1671
     * @param int    $pageTotal
1672
     * @param string $categoryCode
1673
     * @param string $action
1674
     * @param array  $fields
1675
     * @param array  $sortKeys
1676
     *
1677
     * @return string
1678
     */
1679
    public static function getCatalogPagination(
1680
        $pageCurrent,
1681
        $pageLength,
1682
        $pageTotal,
1683
        $categoryCode = '',
1684
        $action = '',
1685
        $fields = [],
1686
        $sortKeys = []
1687
    ) {
1688
        // Start empty html
1689
        $pageDiv = '';
1690
        $html = '';
1691
        $pageBottom = max(1, $pageCurrent - 3);
1692
        $pageTop = min($pageTotal, $pageCurrent + 3);
1693
1694
        if ($pageBottom > 1) {
1695
            $pageDiv .= self::getPageNumberItem(1, $pageLength);
1696
            if ($pageBottom > 2) {
1697
                $pageDiv .= self::getPageNumberItem(
1698
                    $pageBottom - 1,
1699
                    $pageLength,
1700
                    null,
1701
                    '...',
1702
                    $categoryCode,
1703
                    $action,
1704
                    $fields,
1705
                    $sortKeys
1706
                );
1707
            }
1708
        }
1709
1710
        // For each page add its page button to html
1711
        for ($i = $pageBottom; $i <= $pageTop; $i++) {
1712
            if ($i === $pageCurrent) {
1713
                $pageItemAttributes = ['class' => 'active'];
1714
            } else {
1715
                $pageItemAttributes = [];
1716
            }
1717
            $pageDiv .= self::getPageNumberItem(
1718
                $i,
1719
                $pageLength,
1720
                $pageItemAttributes,
1721
                '',
1722
                $categoryCode,
1723
                $action,
1724
                $fields,
1725
                $sortKeys
1726
            );
1727
        }
1728
1729
        // Check if current page is the last page
1730
        if ($pageTop < $pageTotal) {
1731
            if ($pageTop < ($pageTotal - 1)) {
1732
                $pageDiv .= self::getPageNumberItem(
1733
                    $pageTop + 1,
1734
                    $pageLength,
1735
                    null,
1736
                    '...',
1737
                    $categoryCode,
1738
                    $action,
1739
                    $fields,
1740
                    $sortKeys
1741
                );
1742
            }
1743
            $pageDiv .= self::getPageNumberItem(
1744
                $pageTotal,
1745
                $pageLength,
1746
                [],
1747
                '',
1748
                $categoryCode,
1749
                $action,
1750
                $fields,
1751
                $sortKeys
1752
            );
1753
        }
1754
1755
        // Complete pagination html
1756
        $pageDiv = Display::tag('ul', $pageDiv, ['class' => 'pagination']);
1757
        $html .= '<nav>'.$pageDiv.'</nav>';
1758
1759
        return $html;
1760
    }
1761
1762
    /**
1763
     * Get li HTML of page number.
1764
     *
1765
     * @param $pageNumber
1766
     * @param $pageLength
1767
     * @param array  $liAttributes
1768
     * @param string $content
1769
     * @param string $categoryCode
1770
     * @param string $action
1771
     * @param array  $fields
1772
     * @param array  $sortKeys
1773
     *
1774
     * @return string
1775
     */
1776
    public static function getPageNumberItem(
1777
        $pageNumber,
1778
        $pageLength,
1779
        $liAttributes = [],
1780
        $content = '',
1781
        $categoryCode = '',
1782
        $action = '',
1783
        $fields = [],
1784
        $sortKeys = []
1785
    ) {
1786
        // Get page URL
1787
        $url = self::getCatalogUrl($pageNumber, $pageLength, $categoryCode, $action, $fields, $sortKeys);
1788
1789
        // If is current page ('active' class) clear URL
1790
        if (isset($liAttributes) && is_array($liAttributes) && isset($liAttributes['class'])) {
1791
            if (strpos('active', $liAttributes['class']) !== false) {
1792
                $url = '';
1793
            }
1794
        }
1795
1796
        $content = !empty($content) ? $content : $pageNumber;
1797
1798
        return Display::tag(
1799
            'li',
1800
            Display::url(
1801
                $content,
1802
                $url
1803
            ),
1804
            $liAttributes
1805
        );
1806
    }
1807
1808
    /**
1809
     * Return URL to course catalog.
1810
     *
1811
     * @param int    $pageCurrent
1812
     * @param int    $pageLength
1813
     * @param string $categoryCode
1814
     * @param string $action
1815
     * @param array  $extraFields
1816
     * @param array  $sortKeys
1817
     *
1818
     * @return string
1819
     */
1820
    public static function getCatalogUrl(
1821
        $pageCurrent,
1822
        $pageLength,
1823
        $categoryCode = null,
1824
        $action = null,
1825
        $extraFields = [],
1826
        $sortKeys = []
1827
    ) {
1828
        $requestAction = isset($_REQUEST['action']) ? Security::remove_XSS($_REQUEST['action']) : '';
1829
        $action = isset($action) ? Security::remove_XSS($action) : $requestAction;
1830
        $searchTerm = isset($_REQUEST['search_term']) ? Security::remove_XSS($_REQUEST['search_term']) : '';
1831
        $keyword = isset($_REQUEST['keyword']) ? Security::remove_XSS($_REQUEST['keyword']) : '';
1832
        $searchTag = $_REQUEST['search_tag'] ?? '';
1833
1834
        if ($action === 'subscribe_user_with_password') {
1835
            $action = 'subscribe';
1836
        }
1837
1838
        $categoryCode = !empty($categoryCode) ? Security::remove_XSS($categoryCode) : 'ALL';
1839
1840
        // Start URL with params
1841
        $pageUrl = api_get_path(WEB_CODE_PATH).'auth/courses.php'.
1842
            '?action='.$action.
1843
            '&search_term='.$searchTerm.
1844
            '&keyword='.$keyword.
1845
            '&search_tag='.$searchTag.
1846
            '&category_code='.$categoryCode.
1847
            '&pageCurrent='.$pageCurrent.
1848
            '&pageLength='.$pageLength;
1849
1850
        if (!empty($extraFields)) {
1851
            $params = [];
1852
            foreach ($extraFields as $variable => $value) {
1853
                $params[Security::remove_XSS($variable)] = Security::remove_XSS($value);
1854
            }
1855
            if (!empty($params)) {
1856
                $pageUrl .= '&'.http_build_query($params);
1857
            }
1858
        }
1859
1860
        if (!empty($sortKeys)) {
1861
            foreach ($sortKeys as $sortKey) {
1862
                $pageUrl .= '&sortKeys%5B%5D='.Security::remove_XSS($sortKey);
1863
            }
1864
        }
1865
1866
        switch ($action) {
1867
            case 'subscribe':
1868
                // for search
1869
                $pageUrl .=
1870
                    '&sec_token='.Security::getTokenFromSession();
1871
                break;
1872
            case 'display_courses':
1873
            default:
1874
                break;
1875
        }
1876
1877
        return $pageUrl;
1878
    }
1879
1880
    public static function generateRedirectUrlAfterSubscription(string $coursePublicUrl): string
1881
    {
1882
        $settings = api_get_configuration_value('course_catalog_settings');
1883
1884
        $redirectAfterSubscription = 'course_home';
1885
1886
        if (!empty($settings) && isset($settings['redirect_after_subscription'])) {
1887
            $redirectAfterSubscription = $settings['redirect_after_subscription'];
1888
        }
1889
1890
        if ('course_home' !== $redirectAfterSubscription) {
1891
            return api_get_path(WEB_CODE_PATH).'auth/courses.php';
1892
        }
1893
1894
        if (api_get_configuration_value('catalog_course_subscription_in_user_s_session')) {
1895
            $user = api_get_user_entity(api_get_user_id());
1896
1897
            if ($user && $accesibleSessions = $user->getCurrentlyAccessibleSessions()) {
1898
                return $coursePublicUrl.'?id_session='.$accesibleSessions[0]->getId();
1899
            }
1900
        }
1901
1902
        return $coursePublicUrl;
1903
    }
1904
1905
    /**
1906
     * @throws Exception
1907
     */
1908
    public static function displayCoursesList(
1909
        string $action = '',
1910
        string $searchTerm = '',
1911
        string $categoryCode = '',
1912
        bool $returnHtml = false
1913
    ): ?string {
1914
        $settings = api_get_configuration_value('course_catalog_settings');
1915
1916
        $courseCatalogSettings = [
1917
            'info_url' => 'course_description_popup',
1918
            'title_url' => 'course_home',
1919
            'image_url' => 'course_about',
1920
        ];
1921
        // By default, all extra fields are shown (visible and filterable)
1922
        $extraFieldsInSearchForm = [];
1923
        $extraFieldsInCourseBlock = [];
1924
1925
        if (!empty($settings)) {
1926
            if (isset($settings['link_settings'])) {
1927
                $courseCatalogSettings = $settings['link_settings'];
1928
            }
1929
1930
            if (isset($settings['extra_fields_in_search_form'])) {
1931
                $extraFieldsInSearchForm = $settings['extra_fields_in_search_form'];
1932
            }
1933
1934
            if (isset($settings['extra_fields_in_course_block'])) {
1935
                $extraFieldsInCourseBlock = $settings['extra_fields_in_course_block'];
1936
            }
1937
        }
1938
1939
        $settings = CoursesAndSessionsCatalog::getCatalogSearchSettings();
1940
1941
        $form = new FormValidator('search', 'get', '', null, null, FormValidator::LAYOUT_GRID);
1942
        $form->addHidden('action', 'search_course');
1943
1944
        if (isset($settings['courses']) && true === $settings['courses']['by_title']) {
1945
            $form->addText('search_term', get_lang('Title'));
1946
        }
1947
1948
        $select = $form->addSelect(
1949
            'category_code',
1950
            get_lang('CourseCategories'),
1951
            [],
1952
            ['placeholder' => get_lang('SelectAnOption')]
1953
        );
1954
1955
        $defaults = [];
1956
        $listCategories = CoursesAndSessionsCatalog::getCourseCategoriesTree();
1957
1958
        foreach ($listCategories as $category) {
1959
            $countCourse = (int) $category['number_courses'];
1960
            if (empty($countCourse)) {
1961
                continue;
1962
            }
1963
1964
            $categoryCodeItem = Security::remove_XSS($category['code']);
1965
            $categoryName = Security::remove_XSS($category['name']);
1966
            $level = $category['level'];
1967
            $separate = '';
1968
            if ($level > 0) {
1969
                $separate = str_repeat('--', $level);
1970
            }
1971
            $select->addOption($separate.' '.$categoryName.' ('.$countCourse.')', $categoryCodeItem);
1972
        }
1973
1974
        $allowExtraFields = api_get_configuration_value('allow_course_extra_field_in_catalog');
1975
1976
        $jqueryReadyContent = '';
1977
        if ($allowExtraFields) {
1978
            $extraField = new ExtraFieldModel('course');
1979
            $returnParams = $extraField->addElements($form, null, [], true, false, $extraFieldsInSearchForm);
1980
            $jqueryReadyContent = $returnParams['jquery_ready_content'];
1981
        }
1982
1983
        $sortKeySelect = $form->addSelect(
1984
            'sortKeys',
1985
            get_lang('SortKeys'),
1986
            CoursesAndSessionsCatalog::courseSortOptions(),
1987
            ['multiple' => true]
1988
        );
1989
1990
        $sortKeys = isset($_REQUEST['sortKeys']) ? Security::remove_XSS($_REQUEST['sortKeys']) : '';
1991
        $defaults['sortKeys'] = $sortKeys;
1992
        $defaults['search_term'] = $searchTerm;
1993
        $defaults['category_code'] = $categoryCode;
1994
1995
        $conditions = [];
1996
        $fields = [];
1997
1998
        if ('display_random_courses' === $action) {
1999
            // Random value is used instead limit filter
2000
            $courses = CoursesAndSessionsCatalog::getCoursesInCategory(null, 12);
2001
            $countCoursesInCategory = count($courses);
2002
        } else {
2003
            $values = $_REQUEST;
2004
            if ($allowExtraFields) {
2005
                $extraResult = $extraField->processExtraFieldSearch($values, $form, 'course', 'AND');
2006
                $conditions = $extraResult['condition'];
2007
                $fields = $extraResult['fields'];
2008
                $defaults = $extraResult['defaults'];
2009
2010
                $defaults['sortKeys'] = $sortKeys;
2011
                $defaults['search_term'] = $searchTerm;
2012
                $defaults['category_code'] = $categoryCode;
2013
            }
2014
2015
            $courses = CoursesAndSessionsCatalog::searchAndSortCourses(
2016
                $categoryCode,
2017
                $searchTerm,
2018
                self::getLimitArray(),
2019
                true,
2020
                $conditions,
2021
                $sortKeySelect->getValue()
2022
            );
2023
            $countCoursesInCategory = CourseCategory::countCoursesInCategory(
2024
                $categoryCode,
2025
                $searchTerm,
2026
                true,
2027
                true,
2028
                $conditions
2029
            );
2030
        }
2031
2032
        $pageCurrent = isset($_GET['pageCurrent']) ? (int) $_GET['pageCurrent'] : 1;
2033
        $pageLength = isset($_GET['pageLength']) ? (int) $_GET['pageLength'] : CoursesAndSessionsCatalog::PAGE_LENGTH;
2034
        $pageTotal = (int) ceil($countCoursesInCategory / $pageLength);
2035
2036
        $url = CoursesAndSessionsCatalog::getCatalogUrl(1, $pageLength, 'ALL', 'search_course', $fields);
2037
        $urlNoExtraFields = CoursesAndSessionsCatalog::getCatalogUrl(1, $pageLength, 'ALL', 'search_course');
2038
        $urlNoCategory = CoursesAndSessionsCatalog::getCatalogUrl(1, $pageLength, '', 'search_course', $fields);
2039
        $urlNoCategory = str_replace('&category_code=ALL', '', $urlNoCategory);
2040
2041
        $form->setAttribute('action', $url);
2042
        $form->addButtonSearch(get_lang('Search'));
2043
        $form->setDefaults($defaults);
2044
2045
        $catalogPagination = '';
2046
2047
        if ($pageTotal > 1) {
2048
            $catalogPagination = CoursesAndSessionsCatalog::getCatalogPagination(
2049
                $pageCurrent,
2050
                $pageLength,
2051
                $pageTotal,
2052
                $categoryCode,
2053
                $action,
2054
                $fields,
2055
                $sortKeySelect->getValue()
2056
            );
2057
        }
2058
2059
        $stok = Security::get_token();
2060
2061
        $showTeacher = 'true' === api_get_setting('display_teacher_in_courselist');
2062
        $ajax_url = api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=add_course_vote';
2063
        $user_id = api_get_user_id();
2064
        $categoryListFromDatabase = CourseCategory::getAllCategories();
2065
2066
        $categoryList = [];
2067
        if (!empty($categoryListFromDatabase)) {
2068
            foreach ($categoryListFromDatabase as $categoryItem) {
2069
                $categoryList[$categoryItem['code']] = $categoryItem['name'];
2070
            }
2071
        }
2072
2073
        $courseUrl = api_get_path(WEB_COURSE_PATH);
2074
        $hideRating = api_get_configuration_value('hide_course_rating');
2075
2076
        if (!empty($courses)) {
2077
            foreach ($courses as &$course) {
2078
                $courseId = $course['real_id'];
2079
                if (COURSE_VISIBILITY_HIDDEN == $course['visibility']) {
2080
                    continue;
2081
                }
2082
2083
                $aboutPage = api_get_path(WEB_PATH).'course/'.$course['real_id'].'/about';
2084
                $settingsUrl = [
2085
                    'course_description_popup' => api_get_path(WEB_CODE_PATH).'inc/ajax/course_home.ajax.php?a=show_course_information&code='.$course['code'],
2086
                    'course_about' => $aboutPage,
2087
                    'course_home' => $courseUrl.$course['directory'].'/index.php?id_session=0',
2088
                ];
2089
2090
                $infoUrl = $settingsUrl[$courseCatalogSettings['info_url']];
2091
                $course['title_url'] = $settingsUrl[$courseCatalogSettings['title_url']];
2092
                $course['image_url'] = $settingsUrl[$courseCatalogSettings['image_url']];
2093
2094
                $userRegisteredInCourse = CourseManager::is_user_subscribed_in_course($user_id, $course['code']);
2095
                $userRegisteredInCourseAsTeacher = CourseManager::is_course_teacher($user_id, $course['code']);
2096
2097
                $course_private = COURSE_VISIBILITY_REGISTERED == $course['visibility'];
2098
                $courseClosed = COURSE_VISIBILITY_CLOSED == $course['visibility'];
2099
                $course_subscribe_allowed = 1 == $course['subscribe'];
2100
                $course_unsubscribe_allowed = 1 == $course['unsubscribe'];
2101
2102
                // display the course bloc
2103
                $course['category_title'] = '';
2104
2105
                if (!empty($course['category_code'])) {
2106
                    $course['category_title'] = $categoryList[$course['category_code']] ?? '';
2107
                    $course['category_code_link'] = $urlNoCategory.'&category_code='.$course['category_code'];
2108
                }
2109
2110
                // Display thumbnail
2111
                $course['thumbnail'] = CoursesAndSessionsCatalog::returnThumbnail($course);
2112
                $course['description_button'] = CourseManager::returnDescriptionButton($course, $infoUrl);
2113
                $subscribeButton = CoursesAndSessionsCatalog::return_register_button(
2114
                    $course,
2115
                    $stok,
2116
                    $categoryCode,
2117
                    $searchTerm
2118
                );
2119
2120
                // Start buy course validation
2121
                // display the course price and buy button if the buycourses plugin is enabled and this course is configured
2122
                $plugin = BuyCoursesPlugin::create();
2123
                $isThisCourseInSale = $plugin->buyCoursesForGridCatalogValidator(
2124
                    $courseId,
2125
                    BuyCoursesPlugin::PRODUCT_TYPE_COURSE
2126
                );
2127
2128
                $separator = '';
2129
2130
                if ($isThisCourseInSale) {
2131
                    // set the Price label
2132
                    $separator = $isThisCourseInSale['html'];
2133
                    // set the Buy button instead register.
2134
                    if ($isThisCourseInSale['verificator']) {
2135
                        $subscribeButton = $plugin->returnBuyCourseButton(
2136
                            $courseId,
2137
                            BuyCoursesPlugin::PRODUCT_TYPE_COURSE
2138
                        );
2139
                    }
2140
                }
2141
2142
                $course['rating'] = '';
2143
2144
                if ($hideRating === false) {
2145
                    $rating = Display::return_rating_system(
2146
                        'star_'.$course['real_id'],
2147
                        $ajax_url.'&course_id='.$course['real_id'],
2148
                        $course['point_info']
2149
                    );
2150
                    $course['rating'] = '<div class="ranking">'.$rating.'</div>';
2151
                }
2152
2153
                if ($showTeacher) {
2154
                    $course['teacher_info'] = CoursesAndSessionsCatalog::return_teacher($course);
2155
                }
2156
2157
                // display button line
2158
                $course['buy_course'] = $separator;
2159
                $course['extra_data'] = '';
2160
2161
                if ($allowExtraFields) {
2162
                    $course['extra_data'] = $extraField->getDataAndFormattedValues(
2163
                        $courseId,
2164
                        true,
2165
                        $extraFieldsInCourseBlock
2166
                    );
2167
                }
2168
2169
                // if user registered as student
2170
                if ($userRegisteredInCourse) {
2171
                    $course['already_registered_formatted'] = Display::url(
2172
                        Display::returnFontAwesomeIcon('external-link').PHP_EOL.
2173
                        get_lang('GoToCourse'),
2174
                        $courseUrl.$course['directory'].'/index.php?id_session=0',
2175
                        ['class' => 'btn btn-primary btn-sm']
2176
                    );
2177
2178
                    if (!$courseClosed && $course_unsubscribe_allowed
2179
                        && false === $userRegisteredInCourseAsTeacher
2180
                    ) {
2181
                        $course['unregister_formatted'] = CoursesAndSessionsCatalog::return_unregister_button(
2182
                            $course,
2183
                            $stok,
2184
                            $searchTerm,
2185
                            $categoryCode
2186
                        );
2187
                    }
2188
                } elseif ($userRegisteredInCourseAsTeacher) {
2189
                    // if user registered as teacher
2190
                    // Updated teacher cannot unregister himself.
2191
                    /*if ($course_unsubscribe_allowed) {
2192
                        $course['unregister_formatted'] = CoursesAndSessionsCatalog::return_unregister_button(
2193
                            $course,
2194
                            $stok,
2195
                            $searchTerm,
2196
                            $categoryCode
2197
                        );
2198
                    }*/
2199
                } else {
2200
                    // if user not registered in the course
2201
                    if (!$courseClosed && !$course_private && $course_subscribe_allowed) {
2202
                        $course['subscribe_formatted'] = $subscribeButton;
2203
                    }
2204
                }
2205
            }
2206
        } else {
2207
            if (!isset($_REQUEST['subscribe_user_with_password']) &&
2208
                !isset($_REQUEST['subscribe_course'])
2209
            ) {
2210
                Display::addFlash(Display::return_message(get_lang('NoResults'), 'warning'));
2211
            }
2212
        }
2213
2214
        if (api_is_course_admin()) {
2215
            foreach ($courses as &$course) {
2216
                $course['admin_url'] = api_get_path(WEB_CODE_PATH).'/admin/course_list.php?keyword='.$course['code'];
2217
            }
2218
        }
2219
2220
        $toolTitle = get_lang('CourseCatalog');
2221
2222
        $template = new Template($toolTitle, true, true, false, false, false);
2223
        $template->assign('tabs', CoursesAndSessionsCatalog::getTabList());
2224
        $template->assign('frm_filter', $form->returnForm());
2225
        $template->assign('courses', $courses);
2226
        $template->assign(
2227
            'total_number_of_courses',
2228
            CoursesAndSessionsCatalog::countAvailableCoursesToShowInCatalog(
2229
                api_get_current_access_url_id()
2230
            )
2231
        );
2232
        $template->assign('total_number_of_matching_courses', $countCoursesInCategory);
2233
        $template->assign('catalog_url_no_extra_fields', $urlNoExtraFields);
2234
        $template->assign('pagination', $catalogPagination);
2235
        $template->assign('jquery_ready_content', $jqueryReadyContent);
2236
2237
        $templateContent = $template->fetch(
2238
            $template->get_template('catalog/course_catalog.tpl')
2239
        );
2240
2241
        if ($returnHtml) {
2242
            return $templateContent;
2243
        }
2244
2245
        $template->assign('content', $templateContent);
2246
        $template->display_one_col_template();
2247
2248
        return null;
2249
    }
2250
2251
    public static function userCanView(): bool
2252
    {
2253
        // For students
2254
        $userCanViewPage = true;
2255
2256
        if ('false' === api_get_setting('allow_students_to_browse_courses')) {
2257
            $userCanViewPage = false;
2258
        }
2259
2260
        //For teachers/admins
2261
        if (api_is_platform_admin() || api_is_course_admin() || api_is_allowed_to_create_course()) {
2262
            $userCanViewPage = true;
2263
        }
2264
2265
        return $userCanViewPage;
2266
    }
2267
}
2268