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