Passed
Push — 1.11.x ( 9f497a...6ece51 )
by Julito
12:14
created

CoursesAndSessionsCatalog::getPageNumberItem()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 29
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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

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