Link::setInvisible()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 11
nc 5
nop 4
dl 0
loc 18
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\Course;
6
use Chamilo\CoreBundle\Entity\Session;
7
use Chamilo\CoreBundle\Enums\ActionIcon;
8
use Chamilo\CoreBundle\Enums\ObjectIcon;
9
use Chamilo\CoreBundle\Enums\StateIcon;
10
use Chamilo\CoreBundle\Framework\Container;
11
use Chamilo\CourseBundle\Entity\CLink;
12
use Chamilo\CourseBundle\Entity\CLinkCategory;
13
14
/**
15
 * Function library for the links tool.
16
 *
17
 * This is a complete remake of the original link tool.
18
 * New features:
19
 * - Organize links into categories;
20
 * - favorites/bookmarks interface;
21
 * - move links up/down within a category;
22
 * - move categories up/down;
23
 * - expand/collapse all categories;
24
 * - add link to 'root' category => category-less link is always visible.
25
 *
26
 * @author Patrick Cool (December 2003 - January 2004)
27
 * @author René Haentjens, CSV file import (October 2004)
28
 */
29
class Link extends Model
30
{
31
    public $table;
32
    public $is_course_model = true;
33
    public $columns = [
34
        'id',
35
        'c_id',
36
        'url',
37
        'title',
38
        'description',
39
        'category_id',
40
        'on_homepage',
41
        'target',
42
        'session_id',
43
    ];
44
    public array $required = ['url', 'title'];
45
    private $course;
46
47
    public function __construct()
48
    {
49
        $this->table = Database::get_course_table(TABLE_LINK);
50
    }
51
52
    /**
53
     * @param array $course
54
     */
55
    public function setCourse($course)
56
    {
57
        $this->course = $course;
58
    }
59
60
    /**
61
     * @return array
62
     */
63
    public function getCourse()
64
    {
65
        return !empty($this->course) ? $this->course : api_get_course_info();
66
    }
67
68
    /**
69
     * Organize the saving of a link, using the parent's save method and
70
     * updating the item_property table.
71
     *
72
     * @param array $params
73
     * @param bool  $showQuery Whether to show the query in logs when
74
     *                         calling parent's save method
75
     *
76
     * @return bool True if link could be saved, false otherwise
77
     */
78
    public function save($params, $showQuery = null, $showFlash = true)
79
    {
80
        $course_info = $this->getCourse();
81
        $course_id = $course_info['real_id'];
82
        $session_id = api_get_session_id();
83
84
        $title = stripslashes($params['title']);
85
        $urllink = $params['url'];
86
        $description = $params['description'];
87
        $categoryId = (int) $params['category_id'];
88
89
        $onhomepage = 0;
90
        if (isset($params['on_homepage'])) {
91
            $onhomepage = Security::remove_XSS($params['on_homepage']);
92
        }
93
94
        $target = '_self'; // Default target.
95
        if (!empty($params['target'])) {
96
            $target = Security::remove_XSS($params['target']);
97
        }
98
99
        $urllink = trim($urllink);
100
        $title = trim($title);
101
        $description = trim($description);
102
103
        // We ensure URL to be absolute.
104
        if (false === strpos($urllink, '://')) {
105
            $urllink = 'http://'.$urllink;
106
        }
107
108
        // If the title is empty, we use the URL as title.
109
        if ('' == $title) {
110
            $title = $urllink;
111
        }
112
113
        // If the URL is invalid, an error occurs.
114
        if (!api_valid_url($urllink, true)) {
115
            // A check against an absolute URL
116
            Display::addFlash(
117
                Display::return_message(get_lang('Please give the link URL, it should be valid.'), 'error')
118
            );
119
120
            return false;
121
        } else {
122
            $category = null;
123
            $repoCategory = Container::getLinkCategoryRepository();
124
            if (!empty($categoryId)) {
125
                /** @var CLinkCategory $category */
126
                $category = $repoCategory->find($categoryId);
127
            }
128
129
            // Looking for the largest order number for this category.
130
            $link = new CLink();
131
            $link
132
                ->setUrl($urllink)
133
                ->setTitle($title)
134
                ->setDescription($description)
135
                ->setTarget($target)
136
                ->setCategory($category)
137
            ;
138
139
            $repo = Container::getLinkRepository();
140
            $courseEntity = api_get_course_entity($course_id);
141
            if (empty($category)) {
142
                $link
143
                    ->setParent($courseEntity)
144
                    ->addCourseLink($courseEntity, api_get_session_entity($session_id))
145
                ;
146
            } else {
147
                $link
148
                    ->setParent($category)
149
                    ->addCourseLink($courseEntity, api_get_session_entity($session_id))
150
                ;
151
            }
152
153
            $repo->create($link);
154
            $link_id = $link->getIid();
155
156
            if (('true' === api_get_setting('search_enabled')) &&
157
                $link_id && extension_loaded('xapian')
158
            ) {
159
                $courseCode = $course_info['code'];
160
                $specific_fields = get_specific_field_list();
161
                $ic_slide = new IndexableChunk();
162
163
                // Add all terms to db.
164
                $all_specific_terms = '';
165
                foreach ($specific_fields as $specific_field) {
166
                    if (isset($_REQUEST[$specific_field['code']])) {
167
                        $sterms = trim($_REQUEST[$specific_field['code']]);
168
                        if (!empty($sterms)) {
169
                            $all_specific_terms .= ' '.$sterms;
170
                            $sterms = explode(',', $sterms);
171
                            foreach ($sterms as $sterm) {
172
                                $ic_slide->addTerm(
173
                                    trim($sterm),
174
                                    $specific_field['code']
175
                                );
176
                                add_specific_field_value(
177
                                    $specific_field['id'],
178
                                    $courseCode,
179
                                    TOOL_LINK,
180
                                    $link_id,
181
                                    $sterm
182
                                );
183
                            }
184
                        }
185
                    }
186
                }
187
188
                // Build the chunk to index.
189
                $ic_slide->addValue('title', $title);
190
                $ic_slide->addCourseId($courseCode);
191
                $ic_slide->addToolId(TOOL_LINK);
192
                $xapian_data = [
193
                    SE_COURSE_ID => $courseCode,
194
                    SE_TOOL_ID => TOOL_LINK,
195
                    SE_DATA => [
196
                        'link_id' => $link_id,
197
                    ],
198
                    SE_USER => (int) api_get_user_id(),
199
                ];
200
                $ic_slide->xapian_data = serialize($xapian_data);
201
                $description = $all_specific_terms.' '.$description;
202
                $ic_slide->addValue('content', $description);
203
204
                // Add category name if set.
205
                if (isset($categoryId) && $categoryId > 0) {
206
                    $table_link_category = Database::get_course_table(
207
                        TABLE_LINK_CATEGORY
208
                    );
209
                    $sql_cat = 'SELECT * FROM %s WHERE id=%d AND c_id = %d LIMIT 1';
210
                    $sql_cat = sprintf(
211
                        $sql_cat,
212
                        $table_link_category,
213
                        $categoryId,
214
                        $course_id
215
                    );
216
                    $result = Database:: query($sql_cat);
217
                    if (1 == Database:: num_rows($result)) {
218
                        $row = Database:: fetch_array($result);
219
                        $ic_slide->addValue(
220
                            'category',
221
                            $row['title']
222
                        );
223
                    }
224
                }
225
226
                $di = new ChamiloIndexer();
227
                isset($params['language']) ? $lang = Database:: escape_string(
228
                    $params['language']
229
                ) : $lang = 'english';
230
                $di->connectDb(null, null, $lang);
231
                $di->addChunk($ic_slide);
232
233
                // Index and return search engine document id.
234
                $did = $di->index();
235
                if ($did) {
236
                    // Save it to db.
237
                    $tbl_se_ref = Database::get_main_table(
238
                        TABLE_MAIN_SEARCH_ENGINE_REF
239
                    );
240
                    $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, search_did)
241
                            VALUES (NULL , \'%s\', \'%s\', %s, %s)';
242
                    $sql = sprintf(
243
                        $sql,
244
                        $tbl_se_ref,
245
                        $course_id,
246
                        $courseCode,
247
                        TOOL_LINK,
248
                        $link_id,
249
                        $did
250
                    );
251
                    Database:: query($sql);
252
                }
253
            }
254
            if ($showFlash) {
255
                Display::addFlash(Display::return_message(get_lang('The link has been added.')));
256
            }
257
258
            return $link_id;
259
        }
260
    }
261
262
    /**
263
     * Update a link in the database.
264
     *
265
     * @param int    $linkId    The ID of the link to update
266
     * @param string $linkUrl   The new URL to be saved
267
     * @param int    $courseId
268
     * @param int    $sessionId
269
     *
270
     * @return bool
271
     */
272
    public function updateLink(
273
        $linkId,
274
        $linkUrl,
275
        $courseId = null,
276
        $sessionId = null
277
    ) {
278
        $tblLink = Database::get_course_table(TABLE_LINK);
279
        $linkUrl = Database::escape_string($linkUrl);
280
        $linkId = (int) $linkId;
281
        if ('' != $linkUrl) {
282
            $sql = "UPDATE $tblLink SET
283
                    url = '$linkUrl'
284
                    WHERE iid = $linkId ";
285
            $resLink = Database::query($sql);
286
287
            return $resLink;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $resLink also could return the type Doctrine\DBAL\Result which is incompatible with the documented return type boolean.
Loading history...
288
        }
289
290
        return false;
291
    }
292
293
    public static function addCategory()
294
    {
295
        $_course = api_get_course_info();
296
        $course_id = $_course['real_id'];
297
        $category_title = trim($_POST['category_title']);
298
        $description = trim($_POST['description']);
299
300
        if (empty($category_title)) {
301
            echo Display::return_message(get_lang('Please give the category name'), 'error');
302
303
            return false;
304
        }
305
306
        // Looking for the largest order number for this category.
307
        /*$result = Database:: query(
308
            "SELECT MAX(display_order) FROM  $tbl_categories
309
            WHERE c_id = $course_id "
310
        );
311
        [$orderMax] = Database:: fetch_row($result);
312
        $order = $orderMax + 1;
313
        $order = (int) $order;*/
314
        $session_id = api_get_session_id();
315
316
        $repo = Container::getLinkCategoryRepository();
317
        $courseEntity = api_get_course_entity($course_id);
318
        $sessionEntity = api_get_session_entity($session_id);
319
320
        $category = (new CLinkCategory())
321
            ->setTitle($category_title)
322
            ->setDescription($description)
323
         //   ->setDisplayOrder($order)
324
            ->setParent($courseEntity)
325
            ->addCourseLink($courseEntity, $sessionEntity)
326
        ;
327
328
        $repo->create($category);
329
330
        Display::addFlash(Display::return_message(get_lang('Category added')));
331
332
        return $category;
333
    }
334
335
    public static function deleteCategory($id)
336
    {
337
        $repo = Container::getLinkCategoryRepository();
338
        /** @var CLinkCategory $category */
339
        $category = $repo->find($id);
340
        if ($category) {
0 ignored issues
show
introduced by
$category is of type Chamilo\CourseBundle\Entity\CLinkCategory, thus it always evaluated to true.
Loading history...
341
            $repo->delete($category);
342
            Display::addFlash(Display::return_message(get_lang('The category has been deleted.')));
343
344
            return true;
345
        }
346
347
        return false;
348
    }
349
350
    /**
351
     * Used to delete a link.
352
     *
353
     * @param int $id
354
     *
355
     * @return bool
356
     */
357
    public static function deleteLink($id)
358
    {
359
        $repo = Container::getLinkRepository();
360
        $link = $repo->find($id);
361
        if ($link) {
362
            $repo->delete($link);
363
            self::delete_link_from_search_engine(api_get_course_id(), $id);
364
            SkillModel::deleteSkillsFromItem($id, ITEM_TYPE_LINK);
365
            Display::addFlash(Display::return_message(get_lang('The link has been deleted')));
366
367
            return true;
368
        }
369
370
        return false;
371
    }
372
373
    /**
374
     * Removes a link from search engine database.
375
     *
376
     * @param string $course_id Course code
377
     * @param int    $link_id   Document id to delete
378
     */
379
    public static function delete_link_from_search_engine($course_id, $link_id)
380
    {
381
        // Remove from search engine if enabled.
382
        if ('true' === api_get_setting('search_enabled')) {
383
            $tbl_se_ref = Database::get_main_table(
384
                TABLE_MAIN_SEARCH_ENGINE_REF
385
            );
386
            $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
387
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_LINK, $link_id);
388
            $res = Database:: query($sql);
389
            if (Database:: num_rows($res) > 0) {
390
                $row = Database::fetch_array($res);
391
                $di = new ChamiloIndexer();
392
                $di->remove_document($row['search_did']);
393
            }
394
            $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
395
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_LINK, $link_id);
396
            Database:: query($sql);
397
398
            // Remove terms from db.
399
            delete_all_values_for_item($course_id, TOOL_DOCUMENT, $link_id);
400
        }
401
    }
402
403
    /**
404
     * Get link info.
405
     *
406
     * @param int $id
407
     *
408
     * @return array link info
409
     */
410
    public static function getLinkInfo($id)
411
    {
412
        $tbl_link = Database::get_course_table(TABLE_LINK);
413
        $course_id = api_get_course_int_id();
414
        $id = (int) $id;
415
416
        if (empty($id) || empty($course_id)) {
417
            return [];
418
        }
419
420
        $sql = "SELECT * FROM $tbl_link
421
                WHERE iid= $id ";
422
        $result = Database::query($sql);
423
        $data = [];
424
        if (Database::num_rows($result)) {
425
            $data = Database::fetch_array($result);
426
        }
427
428
        return $data;
429
    }
430
431
    /**
432
     * @param int   $id
433
     * @param array $values
434
     */
435
    public static function editLink($id, $values = [])
436
    {
437
        $_course = api_get_course_info();
438
        $course_id = $_course['real_id'];
439
        $id = (int) $id;
440
441
        $values['url'] = trim($values['url']);
442
        $values['title'] = trim($values['title']);
443
        $values['description'] = trim($values['description']);
444
        $values['target'] = empty($values['target']) ? '_self' : $values['target'];
445
        $values['on_homepage'] = isset($values['on_homepage']) ? $values['on_homepage'] : '';
446
447
        $categoryId = (int) $values['category_id'];
448
449
        // We ensure URL to be absolute.
450
        if (false === strpos($values['url'], '://')) {
451
            $values['url'] = 'http://'.$_POST['url'];
452
        }
453
454
        // If the title is empty, we use the URL as title.
455
        if ('' == $values['title']) {
456
            $values['title'] = $values['url'];
457
        }
458
459
        // If the URL is invalid, an error occurs.
460
        if (!api_valid_url($values['url'], true)) {
461
            Display::addFlash(
462
                Display::return_message(get_lang('Please give the link URL, it should be valid.'), 'error')
463
            );
464
465
            return false;
466
        }
467
468
        if (empty($id) || empty($course_id)) {
469
            return false;
470
        }
471
472
        $repo = Container::getLinkRepository();
473
        /** @var CLink $link */
474
        $link = $repo->find($id);
475
476
        if (null === $link) {
477
            return false;
478
        }
479
480
        /*if ($link->getCategory() != $values['category_id']) {
481
            $sql = "SELECT MAX(display_order)
482
                    FROM $tbl_link
483
                    WHERE
484
                        category_id='".intval($values['category_id'])."'";
485
            $result = Database:: query($sql);
486
            [$max_display_order] = Database:: fetch_row($result);
487
            $max_display_order++;
488
        } else {
489
            $max_display_order = $row['display_order'];
490
        }*/
491
492
        $link
493
            ->setUrl($values['url'])
494
            ->setTitle($values['title'])
495
            ->setDescription($values['description'])
496
            ->setTarget($values['target'])
497
        ;
498
499
        $courseEntity = api_get_course_entity($course_id);
500
501
        if ($categoryId) {
502
            $repoCategory = Container::getLinkCategoryRepository();
503
            /** @var CLinkCategory $category */
504
            $category = $repoCategory->find($categoryId);
505
            $link
506
                ->setCategory($category)
507
                ->setParent($category);
508
        } else {
509
            $link
510
                ->setCategory(null)
511
                ->setParent($courseEntity);
512
        }
513
514
        $repo->updateNodeForResource($link);
515
        $repo->update($link);
516
517
        // Update search enchine and its values table if enabled.
518
        if ('true' === api_get_setting('search_enabled')) {
519
            $course_int_id = api_get_course_int_id();
520
            $course_id = api_get_course_id();
521
            $link_title = Database:: escape_string($values['title']);
522
            $link_description = Database:: escape_string($values['description']);
523
524
            // Actually, it consists on delete terms from db,
525
            // insert new ones, create a new search engine document, and remove the old one.
526
            // Get search_did.
527
            $tbl_se_ref = Database::get_main_table(
528
                TABLE_MAIN_SEARCH_ENGINE_REF
529
            );
530
            $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
531
            $sql = sprintf(
532
                $sql,
533
                $tbl_se_ref,
534
                $course_id,
535
                TOOL_LINK,
536
                $id
537
            );
538
            $res = Database:: query($sql);
539
540
            if (Database:: num_rows($res) > 0) {
541
                $se_ref = Database:: fetch_array($res);
542
                $specific_fields = get_specific_field_list();
543
                $ic_slide = new IndexableChunk();
544
545
                $all_specific_terms = '';
546
                foreach ($specific_fields as $specific_field) {
547
                    delete_all_specific_field_value(
548
                        $course_id,
549
                        $specific_field['id'],
550
                        TOOL_LINK,
551
                        $id
552
                    );
553
                    if (isset($_REQUEST[$specific_field['code']])) {
554
                        $sterms = trim(
555
                            $_REQUEST[$specific_field['code']]
556
                        );
557
                        if (!empty($sterms)) {
558
                            $all_specific_terms .= ' '.$sterms;
559
                            $sterms = explode(',', $sterms);
560
                            foreach ($sterms as $sterm) {
561
                                $ic_slide->addTerm(
562
                                    trim($sterm),
563
                                    $specific_field['code']
564
                                );
565
                                add_specific_field_value(
566
                                    $specific_field['id'],
567
                                    $course_id,
568
                                    TOOL_LINK,
569
                                    $id,
570
                                    $sterm
571
                                );
572
                            }
573
                        }
574
                    }
575
                }
576
577
                // Build the chunk to index.
578
                $ic_slide->addValue("title", $link_title);
579
                $ic_slide->addCourseId($course_id);
580
                $ic_slide->addToolId(TOOL_LINK);
581
                $xapian_data = [
582
                    SE_COURSE_ID => $course_id,
583
                    SE_TOOL_ID => TOOL_LINK,
584
                    SE_DATA => [
585
                        'link_id' => $id,
586
                    ],
587
                    SE_USER => (int) api_get_user_id(),
588
                ];
589
                $ic_slide->xapian_data = serialize($xapian_data);
590
                $link_description = $all_specific_terms.' '.$link_description;
591
                $ic_slide->addValue('content', $link_description);
592
593
                // Add category name if set.
594
                if (isset($categoryId) && $categoryId > 0) {
595
                    $table_link_category = Database::get_course_table(
596
                        TABLE_LINK_CATEGORY
597
                    );
598
                    $sql_cat = 'SELECT * FROM %s WHERE id=%d and c_id = %d LIMIT 1';
599
                    $sql_cat = sprintf(
600
                        $sql_cat,
601
                        $table_link_category,
602
                        $categoryId,
603
                        $course_int_id
604
                    );
605
                    $result = Database:: query($sql_cat);
606
                    if (1 == Database:: num_rows($result)) {
607
                        $row = Database:: fetch_array($result);
608
                        $ic_slide->addValue(
609
                            'category',
610
                            $row['title']
611
                        );
612
                    }
613
                }
614
615
                $di = new ChamiloIndexer();
616
                isset($_POST['language']) ? $lang = Database:: escape_string($_POST['language']) : $lang = 'english';
617
                $di->connectDb(null, null, $lang);
618
                $di->remove_document($se_ref['search_did']);
619
                $di->addChunk($ic_slide);
620
621
                // Index and return search engine document id.
622
                $did = $di->index();
623
                if ($did) {
624
                    // Save it to db.
625
                    $sql = 'DELETE FROM %s
626
                            WHERE course_code=\'%s\'
627
                            AND tool_id=\'%s\'
628
                            AND ref_id_high_level=\'%s\'';
629
                    $sql = sprintf(
630
                        $sql,
631
                        $tbl_se_ref,
632
                        $course_id,
633
                        TOOL_LINK,
634
                        $id
635
                    );
636
                    Database:: query($sql);
637
                    $sql = 'INSERT INTO %s (c_id, id, course_code, tool_id, ref_id_high_level, search_did)
638
                            VALUES (NULL , \'%s\', \'%s\', %s, %s)';
639
                    $sql = sprintf(
640
                        $sql,
641
                        $tbl_se_ref,
642
                        $course_int_id,
643
                        $course_id,
644
                        TOOL_LINK,
645
                        $id,
646
                        $did
647
                    );
648
                    Database:: query($sql);
649
                }
650
            }
651
        }
652
653
        Display::addFlash(Display::return_message(get_lang('The link has been modified.')));
654
    }
655
656
    /**
657
     * @param int   $id
658
     * @param array $values
659
     *
660
     * @return bool
661
     */
662
    public static function editCategory($id, $values)
663
    {
664
        $repo = Container::getLinkCategoryRepository();
665
        /** @var CLinkCategory $category */
666
        $category = $repo->find($id);
667
        $category
668
            ->setTitle($values['category_title'])
669
            ->setDescription($values['description'])
670
        ;
671
672
        $repo->update($category);
673
674
        Display::addFlash(Display::return_message(get_lang('The category has been modified.')));
675
676
        return true;
677
    }
678
679
    /**
680
     * Changes the visibility of a link.
681
     */
682
    public static function setVisible($id, $scope, ?Course $course, ?Session $session)
683
    {
684
        if (TOOL_LINK == $scope) {
685
            /*api_item_property_update(
686
                $_course,
687
                TOOL_LINK,
688
                $id,
689
                $_GET['action'],
690
                $_user['user_id']
691
            );*/
692
            $repo = Container::getLinkRepository();
693
            /** @var CLink $link */
694
            $link = $repo->find($id);
695
            if ($link) {
0 ignored issues
show
introduced by
$link is of type Chamilo\CourseBundle\Entity\CLink, thus it always evaluated to true.
Loading history...
696
                $repo->setVisibilityPublished($link, $course, $session);
697
            }
698
        } elseif (TOOL_LINK_CATEGORY == $scope) {
699
            $repo = Container::getLinkCategoryRepository();
700
            /** @var CLink $link */
701
            $link = $repo->find($id);
702
            if ($link) {
0 ignored issues
show
introduced by
$link is of type Chamilo\CourseBundle\Entity\CLink, thus it always evaluated to true.
Loading history...
703
                $repo->setVisibilityPublished($link, $course, $session);
704
            }
705
            /*api_item_property_update(
706
                $_course,
707
                TOOL_LINK_CATEGORY,
708
                $id,
709
                $_GET['action'],
710
                $_user['user_id']
711
            );*/
712
        }
713
        Display::addFlash(Display::return_message(get_lang('The visibility has been changed.')));
714
    }
715
716
    public static function setInvisible($id, $scope, ?Course $course, ?Session $session)
717
    {
718
        if (TOOL_LINK == $scope) {
719
            $repo = Container::getLinkRepository();
720
            /** @var CLink $link */
721
            $link = $repo->find($id);
722
            if ($link) {
0 ignored issues
show
introduced by
$link is of type Chamilo\CourseBundle\Entity\CLink, thus it always evaluated to true.
Loading history...
723
                $repo->setVisibilityDraft($link, $course, $session);
724
            }
725
        } elseif (TOOL_LINK_CATEGORY == $scope) {
726
            $repo = Container::getLinkCategoryRepository();
727
            /** @var CLinkCategory $link */
728
            $link = $repo->find($id);
729
            if ($link) {
0 ignored issues
show
introduced by
$link is of type Chamilo\CourseBundle\Entity\CLinkCategory, thus it always evaluated to true.
Loading history...
730
                $repo->setVisibilityDraft($link, $course, $session);
731
            }
732
        }
733
        Display::addFlash(Display::return_message(get_lang('The visibility has been changed.')));
734
    }
735
736
    /**
737
     * Generate SQL to select all the links categories in the current course and
738
     * session.
739
     *
740
     * @param int  $courseId
741
     * @param int  $sessionId
742
     * @param bool $withBaseContent
743
     *
744
     * @return CLinkCategory[]
745
     */
746
    public static function getLinkCategories($courseId, $sessionId, $withBaseContent = true)
747
    {
748
        $repo = Container::getLinkCategoryRepository();
749
750
        $courseEntity = api_get_course_entity($courseId);
751
        $sessionEntity = api_get_session_entity($sessionId);
752
753
        $qb = $repo->getResourcesByCourse($courseEntity, $sessionEntity);
754
755
        return $qb->getQuery()->getResult();
756
        /*
757
        $tblLinkCategory = Database::get_course_table(TABLE_LINK_CATEGORY);
758
        $tblItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
759
        $courseId = (int) $courseId;
760
        $courseInfo = api_get_course_info_by_id($courseId);
761
762
        // Condition for the session.
763
        $sessionCondition = api_get_session_condition(
764
            $sessionId,
765
            true,
766
            $withBaseContent,
767
            'linkcat.session_id'
768
        );
769
770
        // Getting links
771
        $sql = "SELECT *, linkcat.id
772
                FROM $tblLinkCategory linkcat
773
                WHERE
774
                    linkcat.c_id = $courseId
775
                    $sessionCondition
776
                ORDER BY linkcat.display_order DESC";
777
778
        $result = Database::query($sql);
779
        $categories = Database::store_result($result);
780
781
        $sql = "SELECT *, linkcat.id
782
                FROM $tblLinkCategory linkcat
783
                INNER JOIN $tblItemProperty ip
784
                ON (linkcat.id = ip.ref AND linkcat.c_id = ip.c_id)
785
                WHERE
786
                    ip.tool = '".TOOL_LINK_CATEGORY."' AND
787
                    (ip.visibility = '0' OR ip.visibility = '1')
788
                    $sessionCondition AND
789
                    linkcat.c_id = ".$courseId."
790
                ORDER BY linkcat.display_order DESC";
791
792
        $result = Database::query($sql);
793
794
        $categoryInItemProperty = [];
795
        if (Database::num_rows($result)) {
796
            while ($row = Database::fetch_assoc($result)) {
797
                $categoryInItemProperty[$row['id']] = $row;
798
            }
799
        }
800
801
        foreach ($categories as &$category) {
802
            if (!isset($categoryInItemProperty[$category['id']])) {
803
                api_item_property_update(
804
                    $courseInfo,
805
                    TOOL_LINK_CATEGORY,
806
                    $category['id'],
807
                    'LinkCategoryAdded',
808
                    api_get_user_id()
809
                );
810
            }
811
        }
812
813
        $sql = "SELECT DISTINCT linkcat.*, visibility
814
                FROM $tblLinkCategory linkcat
815
                INNER JOIN $tblItemProperty ip
816
                ON (linkcat.id = ip.ref AND linkcat.c_id = ip.c_id)
817
                WHERE
818
                    ip.tool = '".TOOL_LINK_CATEGORY."' AND
819
                    (ip.visibility = '0' OR ip.visibility = '1')
820
                    $sessionCondition AND
821
                    linkcat.c_id = ".$courseId."
822
                ORDER BY linkcat.display_order DESC
823
                ";
824
        $result = Database::query($sql);
825
826
        return Database::store_result($result, 'ASSOC');*/
827
    }
828
829
    /**
830
     * @param int $categoryId
831
     * @param $courseId
832
     * @param $sessionId
833
     * @param bool $withBaseContent
834
     *
835
     * @return array<int, CLink>|null
836
     */
837
    public static function getLinksPerCategory(
838
        $categoryId,
839
        $courseId,
840
        $sessionId,
841
        $withBaseContent = true
842
    ): ?array {
843
        $courseEntity = api_get_course_entity($courseId);
844
        $sessionEntity = api_get_session_entity($sessionId);
845
846
        if (empty($categoryId)) {
847
            $repo = Container::getLinkRepository();
848
            $qb = $repo->getResourcesByCourse($courseEntity, $sessionEntity, null, $courseEntity->getResourceNode());
849
850
            return $qb->getQuery()->getResult();
851
        }
852
853
        $repo = Container::getLinkCategoryRepository();
854
        /** @var CLinkCategory $category */
855
        $category = $repo->find($categoryId);
856
        if ($category) {
0 ignored issues
show
introduced by
$category is of type Chamilo\CourseBundle\Entity\CLinkCategory, thus it always evaluated to true.
Loading history...
857
            $repo = Container::getLinkRepository();
858
            $qb = $repo->getResourcesByCourse($courseEntity, $sessionEntity, null, $category->getResourceNode());
859
860
            return $qb->getQuery()->getResult();
861
        }
862
863
        return null;
864
    }
865
866
    /**
867
     * Displays all the links of a given category.
868
     *
869
     * @param int  $categoryId
870
     * @param int  $courseId
871
     * @param int  $sessionId
872
     * @param bool $showActionLinks
873
     *
874
     * @return string
875
     */
876
    public static function showLinksPerCategory($categoryId, $courseId, $sessionId, $showActionLinks = true)
877
    {
878
        global $token;
879
        $links = self::getLinksPerCategory($categoryId, $courseId, $sessionId);
880
        $content = '';
881
        $numberOfLinks = count($links);
882
        if (!empty($links)) {
883
            $courseEntity = api_get_course_entity($courseId);
884
            $sessionEntity = api_get_session_entity($sessionId);
885
            $user = api_get_user_entity();
886
            $i = 1;
887
            $linksAdded = [];
888
            $iconLink = Display::getMdiIcon(ObjectIcon::LINK, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Link'));
889
            foreach ($links as $link) {
890
                $linkId = $link->getIid();
891
                $resourceLink = $link->getFirstResourceLink();
892
893
                if (in_array($linkId, $linksAdded)) {
894
                    continue;
895
                }
896
897
                $visibility = (int) $link->isVisible($courseEntity, $sessionEntity);
898
899
                $linksAdded[] = $linkId;
900
                $categoryId = 0;
901
                if ($link->getCategory()) {
902
                    $categoryId = $link->getCategory()->getIid();
903
                }
904
905
                // Validation when belongs to a session.
906
                $session_img = '';
907
                $session = $resourceLink->getSession();
908
                if ($session) {
909
                    $session_img = api_get_session_image($session->getId(), $user);
910
                }
911
912
                $toolbar = '';
913
                $link_validator = '';
914
                if (api_is_allowed_to_edit(null, true)) {
915
                    $toolbar .= Display::toolbarButton(
916
                        '',
917
                        'javascript:void(0);',
918
                        'check-circle',
919
                        'secondary btn-sm',
920
                        [
921
                            'onclick' => "check_url('".$linkId."', '".addslashes($link->getUrl())."');",
922
                            'title' => get_lang('Check link'),
923
                        ]
924
                    );
925
926
                    $link_validator .= Display::span(
927
                        '',
928
                        [
929
                        'id' => 'url_id_'.$linkId,
930
                        'class' => 'check-link',
931
                        ]
932
                    );
933
934
                    if ($session === $sessionEntity) {
935
                        $url = api_get_self().'?'.api_get_cidreq().'&action=editlink&id='.$linkId;
936
                        $title = get_lang('Edit');
937
                        $toolbar .= Display::toolbarButton(
938
                            '',
939
                            $url,
940
                            'pencil',
941
                            'secondary btn-sm',
942
                            [
943
                                'title' => $title,
944
                            ]
945
                        );
946
                    }
947
948
                    $urlVisibility = api_get_self().'?'.api_get_cidreq().
949
                            '&sec_token='.$token.
950
                            '&id='.$linkId.
951
                            '&scope=link&category_id='.$categoryId;
952
953
                    switch ($visibility) {
954
                        case 1:
955
                            $urlVisibility .= '&action=invisible';
956
                            $title = get_lang('Make invisible');
957
                            $toolbar .= Display::toolbarButton(
958
                                '',
959
                                $urlVisibility,
960
                                'eye',
961
                                'secondary btn-sm',
962
                                [
963
                                    'title' => $title,
964
                                ]
965
                            );
966
                            break;
967
                        case 0:
968
                            $urlVisibility .= '&action=visible';
969
                            $title = get_lang('Make visible');
970
                            $toolbar .= Display::toolbarButton(
971
                                '',
972
                                $urlVisibility,
973
                                'eye-off',
974
                                'secondary btn-sm',
975
                                [
976
                                    'title' => $title,
977
                                ]
978
                            );
979
                            break;
980
                    }
981
982
                    if ($session === $sessionEntity) {
983
                        $moveLinkParams = [
984
                            'id' => $linkId,
985
                            'scope' => 'category',
986
                            'category_id' => $categoryId,
987
                            'action' => 'move_link_up',
988
                        ];
989
990
                        $toolbar .= Display::toolbarButton(
991
                            get_lang('Move up'),
992
                            api_get_self().'?'.api_get_cidreq().'&'.http_build_query($moveLinkParams),
993
                            'level-up-alt',
994
                            'secondary',
995
                            ['class' => 'btn-sm '.(1 === $i ? 'disabled' : '')],
996
                            false
997
                        );
998
999
                        $moveLinkParams['action'] = 'move_link_down';
1000
                        $toolbar .= Display::toolbarButton(
1001
                            get_lang('Move down'),
1002
                            api_get_self().'?'.api_get_cidreq().'&'.http_build_query($moveLinkParams),
1003
                            'level-down-alt',
1004
                            'secondary',
1005
                            ['class' => 'btn-sm '.($i === $numberOfLinks ? 'disabled' : '')],
1006
                            false
1007
                        );
1008
1009
                        $url = api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=deletelink&id='.$linkId.'&category_id='.$categoryId;
1010
                        $event = "javascript: if(!confirm('".get_lang('Do you want to delete this link?')."'))return false;";
1011
                        $title = get_lang('Delete');
1012
1013
                        $toolbar .= Display::toolbarButton(
1014
                            '',
1015
                            $url,
1016
                            'delete',
1017
                            'secondary btn-sm',
1018
                            [
1019
                                'onclick' => $event,
1020
                                'title' => $title,
1021
                            ]
1022
                        );
1023
                    }
1024
                }
1025
1026
                $showLink = false;
1027
                $titleClass = '';
1028
                if ($visibility) {
1029
                    $showLink = true;
1030
                } else {
1031
                    if (api_is_allowed_to_edit(null, true)) {
1032
                        $showLink = true;
1033
                        $titleClass = 'text-muted';
1034
                    }
1035
                }
1036
1037
                if ($showLink) {
1038
                    $url = api_get_path(WEB_CODE_PATH).'link/link_goto.php?'.api_get_cidreq().'&link_id='.$linkId.'&link_url='.urlencode($link->getUrl());
1039
                    $actions = '';
1040
                    if ($showActionLinks) {
1041
                        $actions .= $toolbar;
1042
                    }
1043
1044
                    $title = $iconLink;
1045
                    $title .= Display::tag(
1046
                        'a',
1047
                        Security::remove_XSS($link->getTitle()),
1048
                        [
1049
                            'href' => $url,
1050
                            'target' => $link->getTarget(),
1051
                            'class' => $titleClass,
1052
                        ]
1053
                    );
1054
                    $title .= $link_validator;
1055
                    $title .= $session_img;
1056
                    $content .= Display::panel(null, $title, null, null, null, null, null, $actions);
1057
                }
1058
                $i++;
1059
            }
1060
        }
1061
1062
        return $content;
1063
    }
1064
1065
    /**
1066
     * Displays the edit, delete and move icons.
1067
     *
1068
     * @param int   Category ID
1069
     * @param int $currentCategory
1070
     * @param int $countCategories
1071
     *
1072
     * @return string
1073
     *
1074
     * @author Patrick Cool <[email protected]>, Ghent University
1075
     */
1076
    public static function showCategoryAdminTools(CLinkCategory $category, $currentCategory, $countCategories)
1077
    {
1078
        $categoryId = $category->getIid();
1079
        $token = null;
1080
        $tools = '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=editcategory&id='.$categoryId.'&category_id='.$categoryId.'" title='.get_lang('Edit').'">'.
1081
            Display::getMdiIcon(
1082
                ActionIcon::EDIT,
1083
                'ch-tool-icon',
1084
                null,
1085
                ICON_SIZE_SMALL,
1086
                get_lang('Edit')
1087
            ).'</a>';
1088
1089
        // DISPLAY MOVE UP COMMAND only if it is not the top link.
1090
        if (0 != $currentCategory) {
1091
            $tools .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=up&up='.$categoryId.'&category_id='.$categoryId.'" title="'.get_lang('Up').'">'.
1092
                Display::getMdiIcon(
1093
                    ActionIcon::UP,
1094
                    'ch-tool-icon',
1095
                    null,
1096
                    ICON_SIZE_SMALL,
1097
                    get_lang('Up')
1098
                ).'</a>';
1099
        } else {
1100
            $tools .= Display::getMdiIcon(
1101
                ActionIcon::UP,
1102
                'ch-tool-icon-disabled',
1103
                null,
1104
                ICON_SIZE_SMALL,
1105
                get_lang('Up')
1106
            ).'</a>';
1107
        }
1108
1109
        // DISPLAY MOVE DOWN COMMAND only if it is not the bottom link.
1110
        if ($currentCategory < $countCategories - 1) {
1111
            $tools .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=down&down='.$categoryId.'&category_id='.$categoryId.'">'.
1112
                Display::getMdiIcon(
1113
                    ActionIcon::DOWN,
1114
                    'ch-tool-icon',
1115
                    null,
1116
                    ICON_SIZE_SMALL,
1117
                    get_lang('down')
1118
                ).'</a>';
1119
        } else {
1120
            $tools .= Display::getMdiIcon(
1121
                ActionIcon::DOWN,
1122
                'ch-tool-icon-disabled',
1123
                null,
1124
                ICON_SIZE_SMALL,
1125
                get_lang('down')
1126
                ).'</a>';
1127
        }
1128
1129
        $tools .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=deletecategory&id='.$categoryId."&category_id=$categoryId\"
1130
            onclick=\"javascript: if(!confirm('".get_lang('When deleting a category, all links of this category are also deleted.
1131
Do you really want to delete this category and its links ?')."')) return false;\">".
1132
            Display::getMdiIcon(
1133
                ActionIcon::DELETE,
1134
                'ch-tool-icon',
1135
                null,
1136
                ICON_SIZE_SMALL,
1137
                get_lang('Delete')
1138
            ).'</a>';
1139
1140
        return $tools;
1141
    }
1142
1143
    /**
1144
     * move a link or a linkcategory up or down.
1145
     *
1146
     * @param   int Category ID
1147
     * @param   int Course ID
1148
     * @param   int Session ID
1149
     *
1150
     * @author Patrick Cool <[email protected]>, Ghent University
1151
     *
1152
     * @todo support sessions
1153
     */
1154
    public static function movecatlink($action, $catlinkid, $courseId = null, $sessionId = null)
1155
    {
1156
        $tbl_categories = Database::get_course_table(TABLE_LINK_CATEGORY);
1157
1158
        if (is_null($courseId)) {
1159
            $courseId = api_get_course_int_id();
1160
        }
1161
        $courseId = intval($courseId);
1162
        if (is_null($sessionId)) {
1163
            $sessionId = api_get_session_id();
1164
        }
1165
        $sessionId = intval($sessionId);
1166
        $thiscatlinkId = intval($catlinkid);
1167
1168
        if ('down' == $action) {
1169
            $sortDirection = 'DESC';
1170
        }
1171
1172
        if ('up' == $action) {
1173
            $sortDirection = 'ASC';
1174
        }
1175
1176
        $movetable = $tbl_categories;
1177
1178
        if (!empty($sortDirection)) {
1179
            if (!in_array(trim(strtoupper($sortDirection)), ['ASC', 'DESC'])) {
1180
                $sortDirection = 'ASC';
1181
            }
1182
1183
            $sql = "SELECT id, display_order FROM $tbl_categories
1184
                    WHERE c_id = $courseId
1185
                    ORDER BY display_order $sortDirection";
1186
            $linkresult = Database:: query($sql);
1187
            $thislinkOrder = 1;
1188
            while ($sortrow = Database:: fetch_array($linkresult)) {
1189
                // STEP 2 : FOUND THE NEXT LINK ID AND ORDER, COMMIT SWAP
1190
                // This part seems unlogic, but it isn't . We first look for the current link with the querystring ID
1191
                // and we know the next iteration of the while loop is the next one. These should be swapped.
1192
                if (isset($thislinkFound) && $thislinkFound) {
1193
                    $nextlinkId = $sortrow['id'];
1194
                    $nextlinkOrder = $sortrow['display_order'];
1195
1196
                    Database:: query(
1197
                        "UPDATE ".$movetable."
1198
                        SET display_order = '$nextlinkOrder'
1199
                        WHERE c_id = $courseId  AND id =  '$thiscatlinkId'"
1200
                    );
1201
                    Database:: query(
1202
                        "UPDATE ".$movetable."
1203
                        SET display_order = '$thislinkOrder'
1204
                        WHERE c_id = $courseId  AND id =  '$nextlinkId'"
1205
                    );
1206
1207
                    break;
1208
                }
1209
                if ($sortrow['id'] == $thiscatlinkId) {
1210
                    $thislinkOrder = $sortrow['display_order'];
1211
                    $thislinkFound = true;
1212
                }
1213
            }
1214
        }
1215
1216
        Display::addFlash(Display::return_message(get_lang('Links moved')));
1217
    }
1218
1219
    /**
1220
     * This function checks if the url is a vimeo link.
1221
     *
1222
     * @author Julio Montoya
1223
     *
1224
     * @version 1.0
1225
     */
1226
    public static function isVimeoLink($url)
1227
    {
1228
        $isLink = strrpos($url, 'vimeo.com');
1229
1230
        return $isLink;
1231
    }
1232
1233
    /**
1234
     * Get vimeo id from URL.
1235
     *
1236
     * @param string $url
1237
     *
1238
     * @return bool|mixed
1239
     */
1240
    public static function getVimeoLinkId($url)
1241
    {
1242
        $possibleUrls = [
1243
            'http://www.vimeo.com/',
1244
            'http://vimeo.com/',
1245
            'https://www.vimeo.com/',
1246
            'https://vimeo.com/',
1247
        ];
1248
        $url = str_replace($possibleUrls, '', $url);
1249
1250
        if (is_numeric($url)) {
1251
            return $url;
1252
        }
1253
1254
        return false;
1255
    }
1256
1257
    /**
1258
     * This function checks if the url is a youtube link.
1259
     *
1260
     * @author Jorge Frisancho
1261
     * @author Julio Montoya - Fixing code
1262
     *
1263
     * @version 1.0
1264
     */
1265
    public static function is_youtube_link($url)
1266
    {
1267
        $is_youtube_link = strrpos($url, 'youtube') || strrpos(
1268
            $url,
1269
            'youtu.be'
1270
        );
1271
1272
        return $is_youtube_link;
1273
    }
1274
1275
    /**
1276
     * This function checks if the url is a PDF File link.
1277
     *
1278
     * @author Jorge Frisancho
1279
     * @author Alex Aragón - Fixing code
1280
     *
1281
     * @version 1.0
1282
     */
1283
    public static function isPdfLink($url)
1284
    {
1285
        $isPdfLink = strrpos(strtolower($url), '.pdf');
1286
1287
        return $isPdfLink;
1288
    }
1289
1290
    /**
1291
     * Get youtube id from an URL.
1292
     *
1293
     * @param string $url
1294
     *
1295
     * @return string
1296
     */
1297
    public static function get_youtube_video_id($url)
1298
    {
1299
        // This is the length of YouTube's video IDs
1300
        $len = 11;
1301
1302
        // The ID string starts after "v=", which is usually right after
1303
        // "youtube.com/watch?" in the URL
1304
        $pos = strpos($url, "v=");
1305
        $id = '';
1306
1307
        //If false try other options
1308
        if (false === $pos) {
1309
            $url_parsed = parse_url($url);
1310
1311
            //Youtube shortener
1312
            //http://youtu.be/ID
1313
            $pos = strpos($url, "youtu.be");
1314
1315
            if (false == $pos) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $pos of type integer to the boolean false. If you are specifically checking for 0, consider using something more explicit like === 0 instead.
Loading history...
1316
                $id = '';
1317
            } else {
1318
                return substr($url_parsed['path'], 1);
1319
            }
1320
1321
            //if empty try the youtube.com/embed/ID
1322
            if (empty($id)) {
1323
                $pos = strpos($url, "embed");
1324
                if (false === $pos) {
1325
                    return '';
1326
                } else {
1327
                    return substr($url_parsed['path'], 7);
1328
                }
1329
            }
1330
        } else {
1331
            // Offset the start location to match the beginning of the ID string
1332
            $pos += 2;
1333
            // Get the ID string and return it
1334
            $id = substr($url, $pos, $len);
1335
1336
            return $id;
1337
        }
1338
    }
1339
1340
    /**
1341
     * @param int    $courseId
1342
     * @param int    $sessionId
1343
     * @param int    $categoryId
1344
     * @param string $show
1345
     * @param null   $token
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $token is correct as it would always require null to be passed?
Loading history...
1346
     * @param bool   $showActionLinks
1347
     * @param bool   $forceOpenCategories
1348
     *
1349
     * @return string
1350
     */
1351
    public static function listLinksAndCategories(
1352
        $courseId,
1353
        $sessionId,
1354
        $categoryId,
1355
        $show = 'none',
1356
        $token = null,
1357
        $showActionLinks = true,
1358
        $forceOpenCategories = false
1359
    ) {
1360
        $categoryId = (int) $categoryId;
1361
        $content = '';
1362
        $toolbar = '';
1363
        $categories = self::getLinkCategories($courseId, $sessionId);
1364
        $countCategories = count($categories);
1365
        $linksPerCategory = self::showLinksPerCategory(0, $courseId, $sessionId, $showActionLinks);
1366
1367
        if ($showActionLinks) {
1368
            /*	Action Links */
1369
            $actions = '';
1370
            if (api_is_allowed_to_edit(null, true)) {
1371
                $actions .= '<a
1372
                    href="'.api_get_self().'?'.api_get_cidreq().'&action=addlink&category_id='.$categoryId.'">'.
1373
                    Display::getMdiIcon(ActionIcon::ADD, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Add a link')).'</a>';
1374
                $actions .= '<a
1375
                    href="'.api_get_self().'?'.api_get_cidreq().'&action=addcategory&category_id='.$categoryId.'">'.
1376
                    Display::getMdiIcon(ActionIcon::CREATE_CATEGORY, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Add a category')).'</a>';
1377
            }
1378
1379
            if (!empty($countCategories)) {
1380
                $actions .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=list&show=none">';
1381
                $actions .= Display::getMdiIcon(StateIcon::LIST_VIEW, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('List View')).' </a>';
1382
1383
                $actions .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=list&show=all">';
1384
                $actions .= Display::getMdiIcon(StateIcon::NESTED_VIEW, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Nested View')).'</a>';
1385
            }
1386
            $actions .= Display::url(
1387
                Display::getMdiIcon(ActionIcon::EXPORT_PDF, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Export to PDF')),
1388
                api_get_self().'?'.api_get_cidreq().'&action=export'
1389
            );
1390
            $toolbar = Display::toolbarAction('toolbar', [$actions]);
1391
        }
1392
1393
        if (empty($countCategories)) {
1394
            $content .= $linksPerCategory;
1395
        } else {
1396
            if (!empty($linksPerCategory)) {
1397
                $content .= Display::panel($linksPerCategory, get_lang('General'));
1398
            }
1399
        }
1400
1401
        $counter = 0;
1402
        $courseEntity = api_get_course_entity($courseId);
1403
        $sessionEntity = api_get_session_entity($sessionId);
1404
        $allowToEdit = api_is_allowed_to_edit(null, true);
1405
1406
        foreach ($categories as $category) {
1407
            $categoryItemId = $category->getIid();
1408
            $isVisible = $category->isVisible($courseEntity, $sessionEntity);
1409
            // Student don't see invisible categories.
1410
            if (!$allowToEdit) {
1411
                if (!$isVisible) {
1412
                    continue;
1413
                }
1414
            }
1415
1416
            // Validation when belongs to a session
1417
            $showChildren = $categoryId === $categoryItemId || 'all' === $show;
1418
            if ($forceOpenCategories) {
1419
                $showChildren = true;
1420
            }
1421
1422
            $strVisibility = '';
1423
            $visibilityClass = null;
1424
            if ($isVisible) {
1425
                $strVisibility = '<a
1426
                    href="link.php?'.api_get_cidreq().'&sec_token='.$token.'&action=invisible&id='.$categoryItemId.'&scope='.TOOL_LINK_CATEGORY.'"
1427
                    title="'.get_lang('Hide').'">'.
1428
                    Display::getMdiIcon(StateIcon::ACTIVE, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Hide')).'</a>';
1429
            } elseif (!$isVisible) {
1430
                $visibilityClass = 'text-muted';
1431
                $strVisibility = ' <a
1432
                    href="link.php?'.api_get_cidreq().'&sec_token='.$token.'&action=visible&id='.$categoryItemId.'&scope='.TOOL_LINK_CATEGORY.'"
1433
                    title="'.get_lang('Show').'">'.
1434
                    Display::getMdiIcon(StateIcon::INACTIVE, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Show')).'</a>';
1435
            }
1436
1437
            $header = '';
1438
            if ($showChildren) {
1439
                $header .= '<a
1440
                    class="'.$visibilityClass.'" href="'.api_get_self().'?'.api_get_cidreq().'&category_id=">';
1441
                $header .= Display::getMdiIcon(StateIcon::NESTED_VIEW, 'ch-tool-icon', null, ICON_SIZE_SMALL);
1442
            } else {
1443
                $header .= '<a
1444
                    class="'.$visibilityClass.'"
1445
                    href="'.api_get_self().'?'.api_get_cidreq().'&category_id='.$categoryItemId.'">';
1446
                $header .= Display::getMdiIcon(StateIcon::LIST_VIEW, 'ch-tool-icon', null, ICON_SIZE_SMALL);
1447
            }
1448
            $header .= Security::remove_XSS($category->getTitle()).'</a>';
1449
1450
            if ($showActionLinks) {
1451
                if ($allowToEdit) {
1452
                    if ($category->getFirstResourceLink() &&
1453
                        $sessionEntity === $category->getFirstResourceLink()->getSession()
1454
                    ) {
1455
                        $header .= $strVisibility;
1456
                        $header .= self::showCategoryAdminTools($category, $counter, count($categories));
1457
                    } else {
1458
                        $header .= get_lang('Edition not available from the session, please edit from the basic course.');
1459
                    }
1460
                }
1461
            }
1462
1463
            $childrenContent = '';
1464
            if ($showChildren) {
1465
                $childrenContent = self::showLinksPerCategory(
1466
                    $categoryItemId,
1467
                    api_get_course_int_id(),
1468
                    api_get_session_id()
1469
                );
1470
            }
1471
1472
            $content .= Display::panel($category->getDescription().$childrenContent, $header);
1473
            $counter++;
1474
        }
1475
1476
        if (empty($content) && api_is_allowed_to_edit()) {
1477
            $content .= Display::noDataView(
1478
                get_lang('Links'),
1479
                Display::getMdiIcon(ObjectIcon::LINK, 'ch-tool-icon', null, ICON_SIZE_BIG),
1480
                get_lang('Add a link'),
1481
                api_get_self().'?'.api_get_cidreq().'&'.http_build_query(['action' => 'addlink'])
1482
            );
1483
        }
1484
1485
        return $toolbar.$content;
1486
    }
1487
1488
    /**
1489
     * @param int    $linkId
1490
     * @param string $action
1491
     * @param null   $token
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $token is correct as it would always require null to be passed?
Loading history...
1492
     *
1493
     * @return FormValidator
1494
     */
1495
    public static function getLinkForm($linkId, $action, $token = null)
1496
    {
1497
        $courseId = api_get_course_int_id();
1498
        $sessionId = api_get_session_id();
1499
        $linkInfo = self::getLinkInfo($linkId);
1500
        $categoryId = isset($linkInfo['category_id']) ? $linkInfo['category_id'] : '';
1501
        $lpId = isset($_GET['lp_id']) ? Security::remove_XSS($_GET['lp_id']) : null;
1502
1503
        $form = new FormValidator(
1504
            'link',
1505
            'post',
1506
            api_get_self().'?action='.$action.
1507
            '&category_id='.$categoryId.
1508
            '&'.api_get_cidreq().
1509
            '&id='.$linkId.
1510
            '&sec_token='.$token
1511
        );
1512
1513
        if ('addlink' === $action) {
1514
            $form->addHeader(get_lang('Add a link'));
1515
        } else {
1516
            $form->addHeader(get_lang('Edit link'));
1517
        }
1518
1519
        $target_link = '_blank';
1520
        $title = '';
1521
        $category = '';
1522
        $onhomepage = '';
1523
        $description = '';
1524
1525
        if (!empty($linkInfo)) {
1526
            $urllink = $linkInfo['url'];
1527
            $title = $linkInfo['title'];
1528
            $description = $linkInfo['description'];
1529
            $category = $linkInfo['category_id'];
1530
            if (isset($linkInfo['on_homepage']) && 0 != $linkInfo['on_homepage']) {
1531
                $onhomepage = 1;
1532
            }
1533
            $target_link = $linkInfo['target'];
1534
        }
1535
1536
        $form->addHidden('id', $linkId);
1537
        $form->addText('url', 'URL');
1538
        $form->addRule('url', get_lang('Please give the link URL, it should be valid.'), 'url');
1539
        $form->addText('title', get_lang('Link name'));
1540
        $form->addHtmlEditor(
1541
            'description',
1542
            get_lang('Description'),
1543
            false,
1544
            false,
1545
            ['ToolbarSet' => 'Profile', 'Width' => '100%', 'Height' => '130']
1546
        );
1547
1548
        $resultcategories = self::getLinkCategories($courseId, $sessionId);
1549
        $options = ['0' => '--'];
1550
        if (!empty($resultcategories)) {
1551
            foreach ($resultcategories as $myrow) {
1552
                $options[$myrow->getIid()] = $myrow->getTitle();
1553
            }
1554
        }
1555
1556
        $form->addSelect('category_id', get_lang('Category'), $options);
1557
        $form->addCheckBox('on_homepage', null, get_lang('Show link on course homepage'));
1558
1559
        $targets = [
1560
            '_self' => get_lang('Open self'),
1561
            '_blank' => get_lang('Open blank'),
1562
            '_parent' => get_lang('Open parent'),
1563
            '_top' => get_lang('Open top'),
1564
        ];
1565
1566
        $form->addSelect(
1567
            'target',
1568
            [
1569
                get_lang('Link\'s target'),
1570
                get_lang('Select the "target" which shows the link on the homepage of the course'),
1571
            ],
1572
            $targets
1573
        );
1574
1575
        $defaults = [
1576
            'url' => empty($urllink) ? 'http://' : Security::remove_XSS($urllink),
1577
            'title' => Security::remove_XSS($title),
1578
            'category_id' => $category,
1579
            'on_homepage' => $onhomepage,
1580
            'description' => $description,
1581
            'target' => $target_link,
1582
        ];
1583
1584
        if ('true' === api_get_setting('search_enabled')) {
1585
            $specific_fields = get_specific_field_list();
1586
            $form->addCheckBox('index_document', get_lang('Index link title and description?'), get_lang('Yes'));
1587
1588
            foreach ($specific_fields as $specific_field) {
1589
                $default_values = '';
1590
                if ('editlink' === $action) {
1591
                    $filter = [
1592
                        'field_id' => $specific_field['id'],
1593
                        'ref_id' => intval($_GET['id']),
1594
                        'tool_id' => '\''.TOOL_LINK.'\'',
1595
                    ];
1596
                    $values = get_specific_field_values_list($filter, ['value']);
1597
                    if (!empty($values)) {
1598
                        $arr_str_values = [];
1599
                        foreach ($values as $value) {
1600
                            $arr_str_values[] = $value['value'];
1601
                        }
1602
                        $default_values = implode(', ', $arr_str_values);
1603
                    }
1604
                }
1605
                $form->addText($specific_field['name'], $specific_field['code']);
1606
                $defaults[$specific_field['name']] = $default_values;
1607
            }
1608
        }
1609
1610
        $skillList = SkillModel::addSkillsToForm($form, ITEM_TYPE_LINK, $linkId);
1611
        $form->addHidden('lp_id', $lpId);
1612
        $form->addButtonSave(get_lang('Save links'), 'submitLink');
1613
        $defaults['skills'] = array_keys($skillList);
1614
        $form->setDefaults($defaults);
1615
1616
        return $form;
1617
    }
1618
1619
    /**
1620
     * @param int    $id
1621
     * @param string $action
1622
     *
1623
     * @return FormValidator
1624
     */
1625
    public static function getCategoryForm($id, $action)
1626
    {
1627
        $id = (int) $id;
1628
        $action = Security::remove_XSS($action);
1629
1630
        $form = new FormValidator(
1631
            'category',
1632
            'post',
1633
            api_get_self().'?action='.$action.'&'.api_get_cidreq()
1634
        );
1635
1636
        $defaults = [];
1637
        if ('addcategory' === $action) {
1638
            $form->addHeader(get_lang('Add a category'));
1639
            $my_cat_title = get_lang('Add a category');
1640
        } else {
1641
            $form->addHeader(get_lang('Edit Category'));
1642
            $my_cat_title = get_lang('Edit Category');
1643
            $defaults = self::getCategory($id);
1644
        }
1645
        $form->addHidden('id', $id);
1646
        $form->addText('category_title', get_lang('Category name'));
1647
        $form->addHtmlEditor(
1648
            'description',
1649
            get_lang('Description'),
1650
            false,
1651
            false,
1652
            ['ToolbarSet' => 'Profile', 'Width' => '100%', 'Height' => '130']
1653
        );
1654
        $form->addButtonSave($my_cat_title, 'submitCategory');
1655
        $form->setDefaults($defaults);
1656
1657
        return $form;
1658
    }
1659
1660
    /**
1661
     * @param int $id
1662
     *
1663
     * @return array
1664
     */
1665
    public static function getCategory($id)
1666
    {
1667
        $table = Database::get_course_table(TABLE_LINK_CATEGORY);
1668
        $id = (int) $id;
1669
        $courseId = api_get_course_int_id();
1670
1671
        if (empty($id) || empty($courseId)) {
1672
            return [];
1673
        }
1674
        $sql = "SELECT * FROM $table
1675
                WHERE iid = $id";
1676
        $result = Database::query($sql);
1677
1678
        return Database::fetch_assoc($result);
0 ignored issues
show
Bug Best Practice introduced by
The expression return Database::fetch_assoc($result) also could return the type boolean which is incompatible with the documented return type array.
Loading history...
1679
    }
1680
1681
    /**
1682
     * Move a link up in its category.
1683
     *
1684
     * @param int $id
1685
     *
1686
     * @return bool
1687
     */
1688
    public static function moveLinkUp($id)
1689
    {
1690
        return self::moveLinkDisplayOrder($id, 'ASC');
1691
    }
1692
1693
    /**
1694
     * Move a link down in its category.
1695
     *
1696
     * @param int $id
1697
     *
1698
     * @return bool
1699
     */
1700
    public static function moveLinkDown($id)
1701
    {
1702
        return self::moveLinkDisplayOrder($id, 'DESC');
1703
    }
1704
1705
    /**
1706
     * @param string $url
1707
     *
1708
     * @return bool
1709
     */
1710
    public static function checkUrl($url)
1711
    {
1712
        // Check if curl is available.
1713
        if (!in_array('curl', get_loaded_extensions())) {
1714
            return false;
1715
        }
1716
1717
        // set URL and other appropriate options
1718
        $defaults = [
1719
            CURLOPT_URL => $url,
1720
            CURLOPT_FOLLOWLOCATION => true, // follow redirects accept youtube.com
1721
            CURLOPT_HEADER => 0,
1722
            CURLOPT_RETURNTRANSFER => true,
1723
            CURLOPT_TIMEOUT => 4,
1724
        ];
1725
1726
        $proxySettings = api_get_setting('security.proxy_settings', true);
1727
1728
        if (!empty($proxySettings) &&
1729
            isset($proxySettings['curl_setopt_array'])
1730
        ) {
1731
            $defaults[CURLOPT_PROXY] = $proxySettings['curl_setopt_array']['CURLOPT_PROXY'];
1732
            $defaults[CURLOPT_PROXYPORT] = $proxySettings['curl_setopt_array']['CURLOPT_PROXYPORT'];
1733
        }
1734
1735
        // Create a new cURL resource
1736
        $ch = curl_init();
1737
        curl_setopt_array($ch, $defaults);
1738
1739
        // grab URL and pass it to the browser
1740
        ob_start();
1741
        $result = curl_exec($ch);
1742
        ob_get_clean();
1743
1744
        // close cURL resource, and free up system resources
1745
        curl_close($ch);
1746
1747
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result also could return the type string which is incompatible with the documented return type boolean.
Loading history...
1748
    }
1749
1750
    /**
1751
     * Move a link inside its category (display_order field).
1752
     *
1753
     * @param int    $id        The link ID
1754
     * @param string $direction The direction to sort the links
1755
     *
1756
     * @return bool
1757
     */
1758
    private static function moveLinkDisplayOrder($id, $direction)
1759
    {
1760
        $em = Database::getManager();
1761
        $repo = Container::getLinkRepository();
1762
1763
        /** @var CLink $link */
1764
        $link = $repo->find($id);
1765
1766
        if (!$link) {
0 ignored issues
show
introduced by
$link is of type Chamilo\CourseBundle\Entity\CLink, thus it always evaluated to true.
Loading history...
1767
            return false;
1768
        }
1769
1770
        $compareLinks = $repo
1771
            ->findBy(
1772
                [
1773
                    'categoryId' => $link->getCategory() ? $link->getCategory()->getIid() : 0,
1774
                ],
1775
                ['displayOrder' => $direction]
1776
            );
1777
1778
        /** @var CLink $prevLink */
1779
        $prevLink = null;
1780
1781
        /** @var CLink $compareLink */
1782
        foreach ($compareLinks as $compareLink) {
1783
            if ($compareLink->getIid() !== $link->getIid()) {
1784
                $prevLink = $compareLink;
1785
1786
                continue;
1787
            }
1788
1789
            if (!$prevLink) {
1790
                return false;
1791
            }
1792
1793
            $newPrevLinkDisplayOrder = $link->getDisplayOrder();
0 ignored issues
show
Bug introduced by
The method getDisplayOrder() does not exist on Chamilo\CourseBundle\Entity\CLink. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1793
            /** @scrutinizer ignore-call */ 
1794
            $newPrevLinkDisplayOrder = $link->getDisplayOrder();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1794
            $newLinkDisplayOrder = $prevLink->getDisplayOrder();
1795
1796
            $link->setDisplayOrder($newLinkDisplayOrder);
0 ignored issues
show
Bug introduced by
The method setDisplayOrder() does not exist on Chamilo\CourseBundle\Entity\CLink. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1796
            $link->/** @scrutinizer ignore-call */ 
1797
                   setDisplayOrder($newLinkDisplayOrder);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1797
            $prevLink->setDisplayOrder($newPrevLinkDisplayOrder);
1798
1799
            $em->persist($prevLink);
1800
            $em->persist($link);
1801
            break;
1802
        }
1803
1804
        $em->flush();
1805
1806
        return true;
1807
    }
1808
}
1809