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

CoursesAndSessionsCatalog::is()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
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