Passed
Push — master ( 3b3aab...efefcc )
by Julito
25:18
created

Link::deleteCategory()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 7
nc 2
nop 1
dl 0
loc 13
rs 10
c 1
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Framework\Container;
6
use Chamilo\CourseBundle\Entity\CLink;
7
use Chamilo\CourseBundle\Entity\CLinkCategory;
8
9
/**
10
 * Function library for the links tool.
11
 *
12
 * This is a complete remake of the original link tool.
13
 * New features:
14
 * - Organize links into categories;
15
 * - favorites/bookmarks interface;
16
 * - move links up/down within a category;
17
 * - move categories up/down;
18
 * - expand/collapse all categories;
19
 * - add link to 'root' category => category-less link is always visible.
20
 *
21
 * @author Patrick Cool (December 2003 - January 2004)
22
 * @author René Haentjens, CSV file import (October 2004)
23
 */
24
class Link extends Model
25
{
26
    public $table;
27
    public $is_course_model = true;
28
    public $columns = [
29
        'id',
30
        'c_id',
31
        'url',
32
        'title',
33
        'description',
34
        'category_id',
35
        'display_order',
36
        'on_homepage',
37
        'target',
38
        'session_id',
39
    ];
40
    public $required = ['url', 'title'];
41
    private $course;
42
43
    /**
44
     * Link constructor.
45
     */
46
    public function __construct()
47
    {
48
        $this->table = Database::get_course_table(TABLE_LINK);
49
    }
50
51
    /**
52
     * @param array $course
53
     */
54
    public function setCourse($course)
55
    {
56
        $this->course = $course;
57
    }
58
59
    /**
60
     * @return array
61
     */
62
    public function getCourse()
63
    {
64
        return !empty($this->course) ? $this->course : api_get_course_info();
65
    }
66
67
    /**
68
     * Organize the saving of a link, using the parent's save method and
69
     * updating the item_property table.
70
     *
71
     * @param array $params
72
     * @param bool  $showQuery Whether to show the query in logs when
73
     *                         calling parent's save method
74
     *
75
     * @return bool True if link could be saved, false otherwise
76
     */
77
    public function save($params, $showQuery = null)
78
    {
79
        $course_info = $this->getCourse();
80
        $course_id = $course_info['real_id'];
81
        $session_id = api_get_session_id();
82
83
        $title = stripslashes($params['title']);
84
        $urllink = $params['url'];
85
        $description = $params['description'];
86
        $categoryId = (int) $params['category_id'];
87
88
        $onhomepage = 0;
89
        if (isset($params['on_homepage'])) {
90
            $onhomepage = Security::remove_XSS($params['on_homepage']);
91
        }
92
93
        $target = '_self'; // Default target.
94
        if (!empty($params['target'])) {
95
            $target = Security::remove_XSS($params['target']);
96
        }
97
98
        $urllink = trim($urllink);
99
        $title = trim($title);
100
        $description = trim($description);
101
102
        // We ensure URL to be absolute.
103
        if (false === strpos($urllink, '://')) {
104
            $urllink = 'http://'.$urllink;
105
        }
106
107
        // If the title is empty, we use the URL as title.
108
        if ('' == $title) {
109
            $title = $urllink;
110
        }
111
112
        // If the URL is invalid, an error occurs.
113
        if (!api_valid_url($urllink, true)) {
114
            // A check against an absolute URL
115
            Display::addFlash(Display::return_message(get_lang('Please give the link URL, it should be valid.'), 'error'));
116
117
            return false;
118
        } else {
119
            $category = null;
120
            $repoCategory = Container::getLinkCategoryRepository();
121
            if (!empty($categoryId)) {
122
                /** @var CLinkCategory $category */
123
                $category = $repoCategory->find($categoryId);
124
            }
125
126
            // Looking for the largest order number for this category.
127
            $link = new CLink();
128
            $link
129
                ->setUrl($urllink)
130
                ->setTitle($title)
131
                ->setDescription($description)
132
                ->setOnHomepage($onhomepage)
133
                ->setTarget($target)
134
                ->setCategory($category)
135
            ;
136
137
            $repo = Container::getLinkRepository();
138
            $courseEntity = api_get_course_entity($course_id);
139
            if (empty($category)) {
140
                $link
141
                    ->setParent($courseEntity)
142
                    ->addCourseLink($courseEntity, api_get_session_entity($session_id))
143
                ;
144
            } else {
145
                $link
146
                    ->setParent($category)
147
                    ->addCourseLink($courseEntity, api_get_session_entity($session_id))
148
                ;
149
            }
150
151
            $repo->getEntityManager()->persist($link);
152
            $repo->getEntityManager()->flush();
153
            $link_id = $link->getIid();
154
155
            if (('true' === api_get_setting('search_enabled')) &&
156
                $link_id && extension_loaded('xapian')
157
            ) {
158
                require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
159
160
                $course_int_id = $_course['real_id'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $_course seems to be never defined.
Loading history...
161
                $courseCode = $_course['code'];
162
                $specific_fields = get_specific_field_list();
163
                $ic_slide = new IndexableChunk();
164
165
                // Add all terms to db.
166
                $all_specific_terms = '';
167
                foreach ($specific_fields as $specific_field) {
168
                    if (isset($_REQUEST[$specific_field['code']])) {
169
                        $sterms = trim($_REQUEST[$specific_field['code']]);
170
                        if (!empty($sterms)) {
171
                            $all_specific_terms .= ' '.$sterms;
172
                            $sterms = explode(',', $sterms);
173
                            foreach ($sterms as $sterm) {
174
                                $ic_slide->addTerm(
175
                                    trim($sterm),
176
                                    $specific_field['code']
177
                                );
178
                                add_specific_field_value(
179
                                    $specific_field['id'],
180
                                    $courseCode,
181
                                    TOOL_LINK,
182
                                    $link_id,
183
                                    $sterm
184
                                );
185
                            }
186
                        }
187
                    }
188
                }
189
190
                // Build the chunk to index.
191
                $ic_slide->addValue('title', $title);
192
                $ic_slide->addCourseId($courseCode);
193
                $ic_slide->addToolId(TOOL_LINK);
194
                $xapian_data = [
195
                    SE_COURSE_ID => $courseCode,
196
                    SE_TOOL_ID => TOOL_LINK,
197
                    SE_DATA => [
198
                        'link_id' => (int) $link_id,
199
                    ],
200
                    SE_USER => (int) api_get_user_id(),
201
                ];
202
                $ic_slide->xapian_data = serialize($xapian_data);
203
                $description = $all_specific_terms.' '.$description;
204
                $ic_slide->addValue('content', $description);
205
206
                // Add category name if set.
207
                if (isset($categoryId) && $categoryId > 0) {
208
                    $table_link_category = Database::get_course_table(
209
                        TABLE_LINK_CATEGORY
210
                    );
211
                    $sql_cat = 'SELECT * FROM %s WHERE id=%d AND c_id = %d LIMIT 1';
212
                    $sql_cat = sprintf(
213
                        $sql_cat,
214
                        $table_link_category,
215
                        (int) $categoryId,
216
                        $course_int_id
217
                    );
218
                    $result = Database:: query($sql_cat);
219
                    if (1 == Database:: num_rows($result)) {
220
                        $row = Database:: fetch_array($result);
221
                        $ic_slide->addValue(
222
                            'category',
223
                            $row['category_title']
224
                        );
225
                    }
226
                }
227
228
                $di = new ChamiloIndexer();
229
                isset($params['language']) ? $lang = Database:: escape_string(
230
                    $params['language']
231
                ) : $lang = 'english';
232
                $di->connectDb(null, null, $lang);
233
                $di->addChunk($ic_slide);
234
235
                // Index and return search engine document id.
236
                $did = $di->index();
237
                if ($did) {
238
                    // Save it to db.
239
                    $tbl_se_ref = Database::get_main_table(
240
                        TABLE_MAIN_SEARCH_ENGINE_REF
241
                    );
242
                    $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, search_did)
243
                            VALUES (NULL , \'%s\', \'%s\', %s, %s)';
244
                    $sql = sprintf(
245
                        $sql,
246
                        $tbl_se_ref,
247
                        $course_int_id,
248
                        $courseCode,
249
                        TOOL_LINK,
250
                        $link_id,
251
                        $did
252
                    );
253
                    Database:: query($sql);
254
                }
255
            }
256
            Display::addFlash(Display::return_message(get_lang('The link has been added.')));
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 (is_null($courseId)) {
282
            $courseId = api_get_course_int_id();
283
        }
284
        $courseId = (int) $courseId;
285
        if (is_null($sessionId)) {
286
            $sessionId = api_get_session_id();
287
        }
288
        $sessionId = (int) $sessionId;
289
        if ('' != $linkUrl) {
290
            $sql = "UPDATE $tblLink SET
291
                    url = '$linkUrl'
292
                    WHERE iid = $linkId ";
293
            $resLink = Database::query($sql);
294
295
            return $resLink;
296
        }
297
298
        return false;
299
    }
300
301
    public static function addCategory()
302
    {
303
        $_course = api_get_course_info();
304
        $course_id = $_course['real_id'];
305
        $category_title = trim($_POST['category_title']);
306
        $description = trim($_POST['description']);
307
308
        if (empty($category_title)) {
309
            echo Display::return_message(get_lang('Please give the category name'), 'error');
310
311
            return false;
312
        }
313
314
        // Looking for the largest order number for this category.
315
        /*$result = Database:: query(
316
            "SELECT MAX(display_order) FROM  $tbl_categories
317
            WHERE c_id = $course_id "
318
        );
319
        [$orderMax] = Database:: fetch_row($result);
320
        $order = $orderMax + 1;
321
        $order = (int) $order;*/
322
        $session_id = api_get_session_id();
323
324
        $repo = Container::getLinkCategoryRepository();
325
        $courseEntity = api_get_course_entity($course_id);
326
        $sessionEntity = api_get_session_entity($session_id);
327
328
        $category = new CLinkCategory();
329
        $category
330
            ->setCategoryTitle($category_title)
331
            ->setDescription($description)
332
         //   ->setDisplayOrder($order)
333
            ->setParent($courseEntity)
334
            ->addCourseLink($courseEntity, $sessionEntity)
335
        ;
336
337
        $repo->getEntityManager()->persist($category);
338
        $repo->getEntityManager()->flush();
339
        $linkId = $category->getIid();
340
341
        if ($linkId) {
342
            // add link_category visibility
343
            // course ID is taken from context in api_set_default_visibility
344
            //api_set_default_visibility($linkId, TOOL_LINK_CATEGORY);
345
            /*api_item_property_update(
346
                $_course,
347
                TOOL_LINK_CATEGORY,
348
                $linkId,
349
                'LinkCategoryAdded',
350
                api_get_user_id()
351
            );
352
            api_set_default_visibility($linkId, TOOL_LINK_CATEGORY);*/
353
        }
354
355
        Display::addFlash(Display::return_message(get_lang('Category added')));
356
357
        return $linkId;
358
    }
359
360
    public static function deleteCategory($id)
361
    {
362
        $repo = Container::getLinkCategoryRepository();
363
        /** @var CLinkCategory $category */
364
        $category = $repo->find($id);
365
        if ($category) {
0 ignored issues
show
introduced by
$category is of type Chamilo\CourseBundle\Entity\CLinkCategory, thus it always evaluated to true.
Loading history...
366
            $repo->delete($category);
367
            Display::addFlash(Display::return_message(get_lang('The category has been deleted.')));
368
369
            return true;
370
        }
371
372
        return false;
373
    }
374
375
    /**
376
     * Used to delete a link.
377
     *
378
     * @param int $id
379
     *
380
     * @return bool
381
     */
382
    public static function deleteLink($id)
383
    {
384
        $repo = Container::getLinkRepository();
385
        $link = $repo->find($id);
386
        if ($link) {
0 ignored issues
show
introduced by
$link is of type Chamilo\CoreBundle\Entity\ResourceInterface, thus it always evaluated to true.
Loading history...
387
            $repo->getEntityManager()->remove($link);
388
            $repo->getEntityManager()->flush();
389
            self::delete_link_from_search_engine(api_get_course_id(), $id);
390
            Skill::deleteSkillsFromItem($id, ITEM_TYPE_LINK);
391
            Display::addFlash(Display::return_message(get_lang('The link has been deleted')));
392
393
            return true;
394
        }
395
396
        return false;
397
398
        $courseInfo = api_get_course_info();
0 ignored issues
show
Unused Code introduced by
$courseInfo = api_get_course_info() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
399
        $tbl_link = Database::get_course_table(TABLE_LINK);
400
401
        $course_id = $courseInfo['real_id'];
402
        $id = intval($id);
403
404
        if (empty($id)) {
405
            return false;
406
        }
407
408
        // -> Items are no longer physically deleted,
409
        // but the visibility is set to 2 (in item_property).
410
        // This will make a restore function possible for the platform administrator.
411
        $sql = "UPDATE $tbl_link SET on_homepage='0'
412
                WHERE c_id = $course_id AND iid='".$id."'";
413
        Database:: query($sql);
414
415
        /*api_item_property_update(
416
            $courseInfo,
417
            TOOL_LINK,
418
            $id,
419
            'delete',
420
            api_get_user_id()
421
        );*/
422
423
        return true;
424
    }
425
426
    /**
427
     * Removes a link from search engine database.
428
     *
429
     * @param string $course_id Course code
430
     * @param int    $link_id   Document id to delete
431
     */
432
    public static function delete_link_from_search_engine($course_id, $link_id)
433
    {
434
        // Remove from search engine if enabled.
435
        if ('true' === api_get_setting('search_enabled')) {
436
            $tbl_se_ref = Database::get_main_table(
437
                TABLE_MAIN_SEARCH_ENGINE_REF
438
            );
439
            $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
440
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_LINK, $link_id);
441
            $res = Database:: query($sql);
442
            if (Database:: num_rows($res) > 0) {
443
                $row = Database::fetch_array($res);
444
                $di = new ChamiloIndexer();
445
                $di->remove_document($row['search_did']);
446
            }
447
            $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
448
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_LINK, $link_id);
449
            Database:: query($sql);
450
451
            // Remove terms from db.
452
            require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
453
            delete_all_values_for_item($course_id, TOOL_DOCUMENT, $link_id);
454
        }
455
    }
456
457
    /**
458
     * Get link info.
459
     *
460
     * @param int $id
461
     *
462
     * @return array link info
463
     */
464
    public static function getLinkInfo($id)
465
    {
466
        $tbl_link = Database::get_course_table(TABLE_LINK);
467
        $course_id = api_get_course_int_id();
468
        $id = (int) $id;
469
470
        if (empty($id) || empty($course_id)) {
471
            return [];
472
        }
473
474
        $sql = "SELECT * FROM $tbl_link
475
                WHERE iid= $id ";
476
        $result = Database::query($sql);
477
        $data = [];
478
        if (Database::num_rows($result)) {
479
            $data = Database::fetch_array($result);
480
        }
481
482
        return $data;
483
    }
484
485
    /**
486
     * @param int   $id
487
     * @param array $values
488
     */
489
    public static function editLink($id, $values = [])
490
    {
491
        $tbl_link = Database::get_course_table(TABLE_LINK);
492
        $_course = api_get_course_info();
493
        $course_id = $_course['real_id'];
494
        $id = (int) $id;
495
496
        $values['url'] = trim($values['url']);
497
        $values['title'] = trim($values['title']);
498
        $values['description'] = trim($values['description']);
499
        $values['target'] = empty($values['target']) ? '_self' : $values['target'];
500
        $values['on_homepage'] = isset($values['on_homepage']) ? $values['on_homepage'] : '';
501
502
        $categoryId = (int) $values['category_id'];
503
504
        // We ensure URL to be absolute.
505
        if (false === strpos($values['url'], '://')) {
506
            $values['url'] = 'http://'.$_POST['url'];
507
        }
508
509
        // If the title is empty, we use the URL as title.
510
        if ('' == $values['title']) {
511
            $values['title'] = $values['url'];
512
        }
513
514
        // If the URL is invalid, an error occurs.
515
        if (!api_valid_url($values['url'], true)) {
516
            Display::addFlash(
517
                Display::return_message(get_lang('Please give the link URL, it should be valid.'), 'error')
518
            );
519
520
            return false;
521
        }
522
523
        if (empty($id) || empty($course_id)) {
524
            return false;
525
        }
526
527
        $repo = Container::getLinkRepository();
528
        /** @var CLink $link */
529
        $link = $repo->find($id);
530
531
        if (null === $link) {
532
            return false;
533
        }
534
535
        /*if ($link->getCategory() != $values['category_id']) {
536
            $sql = "SELECT MAX(display_order)
537
                    FROM $tbl_link
538
                    WHERE
539
                        category_id='".intval($values['category_id'])."'";
540
            $result = Database:: query($sql);
541
            [$max_display_order] = Database:: fetch_row($result);
542
            $max_display_order++;
543
        } else {
544
            $max_display_order = $row['display_order'];
545
        }*/
546
547
        $link
548
            ->setUrl($values['url'])
549
            ->setTitle($values['title'])
550
            ->setDescription($values['description'])
551
            ->setOnHomepage($values['on_homepage'])
552
            ->setTarget($values['target'])
553
        ;
554
555
        if (!empty($values['category_id'])) {
556
            $repoCategory = Container::getLinkCategoryRepository();
557
            /** @var CLinkCategory $category */
558
            $category = $repoCategory->find($categoryId);
559
            $link->setCategory($category);
560
        }
561
562
        $repo->getEntityManager()->persist($link);
563
        $repo->getEntityManager()->flush();
564
565
        // Update search enchine and its values table if enabled.
566
        if ('true' === api_get_setting('search_enabled')) {
567
            $course_int_id = api_get_course_int_id();
568
            $course_id = api_get_course_id();
569
            $link_title = Database:: escape_string($values['title']);
570
            $link_description = Database:: escape_string($values['description']);
571
572
            // Actually, it consists on delete terms from db,
573
            // insert new ones, create a new search engine document, and remove the old one.
574
            // Get search_did.
575
            $tbl_se_ref = Database::get_main_table(
576
                TABLE_MAIN_SEARCH_ENGINE_REF
577
            );
578
            $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
579
            $sql = sprintf(
580
                $sql,
581
                $tbl_se_ref,
582
                $course_id,
583
                TOOL_LINK,
584
                $id
585
            );
586
            $res = Database:: query($sql);
587
588
            if (Database:: num_rows($res) > 0) {
589
                require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
590
591
                $se_ref = Database:: fetch_array($res);
592
                $specific_fields = get_specific_field_list();
593
                $ic_slide = new IndexableChunk();
594
595
                $all_specific_terms = '';
596
                foreach ($specific_fields as $specific_field) {
597
                    delete_all_specific_field_value(
598
                        $course_id,
599
                        $specific_field['id'],
600
                        TOOL_LINK,
601
                        $id
602
                    );
603
                    if (isset($_REQUEST[$specific_field['code']])) {
604
                        $sterms = trim(
605
                            $_REQUEST[$specific_field['code']]
606
                        );
607
                        if (!empty($sterms)) {
608
                            $all_specific_terms .= ' '.$sterms;
609
                            $sterms = explode(',', $sterms);
610
                            foreach ($sterms as $sterm) {
611
                                $ic_slide->addTerm(
612
                                    trim($sterm),
613
                                    $specific_field['code']
614
                                );
615
                                add_specific_field_value(
616
                                    $specific_field['id'],
617
                                    $course_id,
618
                                    TOOL_LINK,
619
                                    $id,
620
                                    $sterm
621
                                );
622
                            }
623
                        }
624
                    }
625
                }
626
627
                // Build the chunk to index.
628
                $ic_slide->addValue("title", $link_title);
629
                $ic_slide->addCourseId($course_id);
630
                $ic_slide->addToolId(TOOL_LINK);
631
                $xapian_data = [
632
                    SE_COURSE_ID => $course_id,
633
                    SE_TOOL_ID => TOOL_LINK,
634
                    SE_DATA => [
635
                        'link_id' => (int) $id,
636
                    ],
637
                    SE_USER => (int) api_get_user_id(),
638
                ];
639
                $ic_slide->xapian_data = serialize($xapian_data);
640
                $link_description = $all_specific_terms.' '.$link_description;
641
                $ic_slide->addValue('content', $link_description);
642
643
                // Add category name if set.
644
                if (isset($categoryId) && $categoryId > 0) {
645
                    $table_link_category = Database::get_course_table(
646
                        TABLE_LINK_CATEGORY
647
                    );
648
                    $sql_cat = 'SELECT * FROM %s WHERE id=%d and c_id = %d LIMIT 1';
649
                    $sql_cat = sprintf(
650
                        $sql_cat,
651
                        $table_link_category,
652
                        $categoryId,
653
                        $course_int_id
654
                    );
655
                    $result = Database:: query($sql_cat);
656
                    if (1 == Database:: num_rows($result)) {
657
                        $row = Database:: fetch_array($result);
658
                        $ic_slide->addValue(
659
                            'category',
660
                            $row['category_title']
661
                        );
662
                    }
663
                }
664
665
                $di = new ChamiloIndexer();
666
                isset($_POST['language']) ? $lang = Database:: escape_string($_POST['language']) : $lang = 'english';
667
                $di->connectDb(null, null, $lang);
668
                $di->remove_document($se_ref['search_did']);
669
                $di->addChunk($ic_slide);
670
671
                // Index and return search engine document id.
672
                $did = $di->index();
673
                if ($did) {
674
                    // Save it to db.
675
                    $sql = 'DELETE FROM %s
676
                            WHERE course_code=\'%s\'
677
                            AND tool_id=\'%s\'
678
                            AND ref_id_high_level=\'%s\'';
679
                    $sql = sprintf(
680
                        $sql,
681
                        $tbl_se_ref,
682
                        $course_id,
683
                        TOOL_LINK,
684
                        $id
685
                    );
686
                    Database:: query($sql);
687
                    $sql = 'INSERT INTO %s (c_id, id, course_code, tool_id, ref_id_high_level, search_did)
688
                            VALUES (NULL , \'%s\', \'%s\', %s, %s)';
689
                    $sql = sprintf(
690
                        $sql,
691
                        $tbl_se_ref,
692
                        $course_int_id,
693
                        $course_id,
694
                        TOOL_LINK,
695
                        $id,
696
                        $did
697
                    );
698
                    Database:: query($sql);
699
                }
700
            }
701
        }
702
703
        Display::addFlash(Display::return_message(get_lang('The link has been modified.')));
704
    }
705
706
    /**
707
     * @param int   $id
708
     * @param array $values
709
     *
710
     * @return bool
711
     */
712
    public static function editCategory($id, $values)
713
    {
714
        $repo = Container::getLinkCategoryRepository();
715
        /** @var CLinkCategory $category */
716
        $category = $repo->find($id);
717
        $category
718
            ->setCategoryTitle($values['category_title'])
719
            ->setDescription($values['description'])
720
        ;
721
722
        $repo->getEntityManager()->persist($category);
723
        $repo->getEntityManager()->flush();
724
725
        Display::addFlash(Display::return_message(get_lang('The category has been modified.')));
726
727
        return true;
728
    }
729
730
    /**
731
     * Changes the visibility of a link.
732
     */
733
    public static function setVisible($id, $scope)
734
    {
735
        if (TOOL_LINK == $scope) {
736
            /*api_item_property_update(
737
                $_course,
738
                TOOL_LINK,
739
                $id,
740
                $_GET['action'],
741
                $_user['user_id']
742
            );*/
743
            $repo = Container::getLinkRepository();
744
            /** @var CLink $link */
745
            $link = $repo->find($id);
746
            if ($link) {
0 ignored issues
show
introduced by
$link is of type Chamilo\CourseBundle\Entity\CLink, thus it always evaluated to true.
Loading history...
747
                $repo->setVisibilityPublished($link);
748
            }
749
        } elseif (TOOL_LINK_CATEGORY == $scope) {
750
            $repo = Container::getLinkCategoryRepository();
751
            /** @var CLink $link */
752
            $link = $repo->find($id);
753
            if ($link) {
0 ignored issues
show
introduced by
$link is of type Chamilo\CourseBundle\Entity\CLink, thus it always evaluated to true.
Loading history...
754
                $repo->setVisibilityPublished($link);
755
            }
756
            /*api_item_property_update(
757
                $_course,
758
                TOOL_LINK_CATEGORY,
759
                $id,
760
                $_GET['action'],
761
                $_user['user_id']
762
            );*/
763
        }
764
        Display::addFlash(Display::return_message(get_lang('The visibility has been changed.')));
765
    }
766
767
    public static function setInvisible($id, $scope)
768
    {
769
        if (TOOL_LINK == $scope) {
770
            $repo = Container::getLinkRepository();
771
            /** @var CLink $link */
772
            $link = $repo->find($id);
773
            if ($link) {
0 ignored issues
show
introduced by
$link is of type Chamilo\CourseBundle\Entity\CLink, thus it always evaluated to true.
Loading history...
774
                $repo->setVisibilityDraft($link);
775
            }
776
        } elseif (TOOL_LINK_CATEGORY == $scope) {
777
            $repo = Container::getLinkCategoryRepository();
778
            /** @var CLinkCategory $link */
779
            $link = $repo->find($id);
780
            if ($link) {
0 ignored issues
show
introduced by
$link is of type Chamilo\CourseBundle\Entity\CLinkCategory, thus it always evaluated to true.
Loading history...
781
                $repo->setVisibilityDraft($link);
782
            }
783
        }
784
        Display::addFlash(Display::return_message(get_lang('The visibility has been changed.')));
785
    }
786
787
    /**
788
     * Generate SQL to select all the links categories in the current course and
789
     * session.
790
     *
791
     * @param int  $courseId
792
     * @param int  $sessionId
793
     * @param bool $withBaseContent
794
     *
795
     * @return CLinkCategory[]
796
     */
797
    public static function getLinkCategories($courseId, $sessionId, $withBaseContent = true)
798
    {
799
        $repo = Container::getLinkCategoryRepository();
800
801
        $courseEntity = api_get_course_entity($courseId);
802
        $sessionEntity = api_get_session_entity($sessionId);
803
804
        $qb = $repo->getResourcesByCourse($courseEntity, $sessionEntity);
805
806
        return $qb->getQuery()->getResult();
807
808
        $tblLinkCategory = Database::get_course_table(TABLE_LINK_CATEGORY);
0 ignored issues
show
Unused Code introduced by
$tblLinkCategory = Datab...le(TABLE_LINK_CATEGORY) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
809
        $tblItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
810
        $courseId = (int) $courseId;
811
        $courseInfo = api_get_course_info_by_id($courseId);
812
813
        // Condition for the session.
814
        $sessionCondition = api_get_session_condition(
815
            $sessionId,
816
            true,
817
            $withBaseContent,
818
            'linkcat.session_id'
819
        );
820
821
        // Getting links
822
        $sql = "SELECT *, linkcat.id
823
                FROM $tblLinkCategory linkcat
824
                WHERE
825
                    linkcat.c_id = $courseId
826
                    $sessionCondition
827
                ORDER BY linkcat.display_order DESC";
828
829
        $result = Database::query($sql);
830
        $categories = Database::store_result($result);
831
832
        $sql = "SELECT *, linkcat.id
833
                FROM $tblLinkCategory linkcat
834
                INNER JOIN $tblItemProperty ip
835
                ON (linkcat.id = ip.ref AND linkcat.c_id = ip.c_id)
836
                WHERE
837
                    ip.tool = '".TOOL_LINK_CATEGORY."' AND
838
                    (ip.visibility = '0' OR ip.visibility = '1')
839
                    $sessionCondition AND
840
                    linkcat.c_id = ".$courseId."
841
                ORDER BY linkcat.display_order DESC";
842
843
        $result = Database::query($sql);
844
845
        $categoryInItemProperty = [];
846
        if (Database::num_rows($result)) {
847
            while ($row = Database::fetch_array($result, 'ASSOC')) {
848
                $categoryInItemProperty[$row['id']] = $row;
849
            }
850
        }
851
852
        foreach ($categories as &$category) {
853
            if (!isset($categoryInItemProperty[$category['id']])) {
854
                api_item_property_update(
0 ignored issues
show
Bug introduced by
The function api_item_property_update was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

854
                /** @scrutinizer ignore-call */ 
855
                api_item_property_update(
Loading history...
855
                    $courseInfo,
856
                    TOOL_LINK_CATEGORY,
857
                    $category['id'],
858
                    'LinkCategoryAdded',
859
                    api_get_user_id()
860
                );
861
            }
862
        }
863
864
        $sql = "SELECT DISTINCT linkcat.*, visibility
865
                FROM $tblLinkCategory linkcat
866
                INNER JOIN $tblItemProperty ip
867
                ON (linkcat.id = ip.ref AND linkcat.c_id = ip.c_id)
868
                WHERE
869
                    ip.tool = '".TOOL_LINK_CATEGORY."' AND
870
                    (ip.visibility = '0' OR ip.visibility = '1')
871
                    $sessionCondition AND
872
                    linkcat.c_id = ".$courseId."
873
                ORDER BY linkcat.display_order DESC
874
                ";
875
        $result = Database::query($sql);
876
877
        return Database::store_result($result, 'ASSOC');
878
    }
879
880
    /**
881
     * @param int $categoryId
882
     * @param $courseId
883
     * @param $sessionId
884
     * @param bool $withBaseContent
885
     *
886
     * @return CLink[]|null
887
     */
888
    public static function getLinksPerCategory(
889
        $categoryId,
890
        $courseId,
891
        $sessionId,
892
        $withBaseContent = true
893
    ) {
894
        $courseEntity = api_get_course_entity($courseId);
895
        $sessionEntity = api_get_session_entity($sessionId);
896
897
        if (empty($categoryId)) {
898
            $repo = Container::getLinkRepository();
899
            $qb = $repo->getResourcesByCourse($courseEntity, $sessionEntity, null, $courseEntity->getResourceNode());
900
901
            return $qb->getQuery()->getResult();
902
        }
903
904
        $repo = Container::getLinkCategoryRepository();
905
        /** @var CLinkCategory $category */
906
        $category = $repo->find($categoryId);
907
        if ($category) {
0 ignored issues
show
introduced by
$category is of type Chamilo\CourseBundle\Entity\CLinkCategory, thus it always evaluated to true.
Loading history...
908
            $repo = Container::getLinkRepository();
909
            $qb = $repo->getResourcesByCourse($courseEntity, $sessionEntity, null, $category->getResourceNode());
910
911
            return $qb->getQuery()->getResult();
912
        }
913
914
        return null;
915
916
        $tbl_link = Database::get_course_table(TABLE_LINK);
0 ignored issues
show
Unused Code introduced by
$tbl_link = Database::get_course_table(TABLE_LINK) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
917
        $TABLE_ITEM_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
918
        $courseId = (int) $courseId;
919
        $sessionId = (int) $sessionId;
920
        $categoryId = (int) $categoryId;
921
922
        // Condition for the session.
923
        $condition_session = api_get_session_condition(
924
            $sessionId,
925
            true,
926
            false,
927
            'ip.session_id'
928
        );
929
930
        if (!empty($sessionId)) {
931
            $conditionBaseSession = api_get_session_condition(
932
                0,
933
                true,
934
                $withBaseContent,
935
                'ip.session_id'
936
            );
937
            $condition = " AND
938
                (
939
                    (ip.visibility = '1' $conditionBaseSession) OR
940
941
                    (
942
                        (ip.visibility = '0' OR ip.visibility = '1')
943
                        $condition_session
944
                    )
945
                )
946
            ";
947
        } else {
948
            $condition = api_get_session_condition(
949
                0,
950
                true,
951
                false,
952
                'ip.session_id'
953
            );
954
            $condition .= " AND (ip.visibility = '0' OR ip.visibility = '1') $condition ";
955
        }
956
957
        $sql = "SELECT
958
                    link.id,
959
                    ip.session_id,
960
                    link.session_id link_session_id,
961
                    url,
962
                    category_id,
963
                    visibility,
964
                    description,
965
                    title,
966
                    target,
967
                    on_homepage
968
                FROM $tbl_link link
969
                INNER JOIN $TABLE_ITEM_PROPERTY ip
970
                ON (link.id = ip.ref AND link.c_id = ip.c_id)
971
                WHERE
972
                    ip.tool = '".TOOL_LINK."' AND
973
                    link.category_id = '".$categoryId."' AND
974
                    link.c_id = $courseId AND
975
                    ip.c_id = $courseId
976
                    $condition
977
                ORDER BY link.display_order ASC, ip.session_id DESC";
978
979
        $result = Database:: query($sql);
980
981
        return Database::store_result($result);
982
    }
983
984
    /**
985
     * Displays all the links of a given category.
986
     *
987
     * @param int  $categoryId
988
     * @param int  $courseId
989
     * @param int  $sessionId
990
     * @param bool $showActionLinks
991
     *
992
     * @return string
993
     */
994
    public static function showLinksPerCategory($categoryId, $courseId, $sessionId, $showActionLinks = true)
995
    {
996
        global $token;
997
        $links = self::getLinksPerCategory($categoryId, $courseId, $sessionId);
998
        $content = '';
999
        $numberOfLinks = count($links);
1000
        if (!empty($links)) {
1001
            $courseEntity = api_get_course_entity($courseId);
1002
            $sessionEntity = api_get_session_entity($sessionId);
1003
            $_user = api_get_user_info();
1004
1005
            $content .= '<div class="link list-group">';
1006
            $i = 1;
1007
            $linksAdded = [];
1008
            foreach ($links as $link) {
1009
                $linkId = $link->getIid();
1010
                $resourceLink = $link->getFirstResourceLink();
1011
1012
                if (in_array($linkId, $linksAdded)) {
1013
                    continue;
1014
                }
1015
1016
                $visibility = (int) $link->isVisible($courseEntity, $sessionEntity);
1017
1018
                $linksAdded[] = $linkId;
1019
                $categoryId = 0;
1020
                if ($link->getCategory()) {
1021
                    $categoryId = $link->getCategory()->getIid();
1022
                }
1023
1024
                // Validation when belongs to a session.
1025
                $session_img = '';
1026
                $session = $resourceLink->getSession();
1027
                if ($session) {
1028
                    $session_img = api_get_session_image(
1029
                        $session->getId(),
1030
                        $_user['status']
1031
                    );
1032
                }
1033
1034
                $toolbar = '';
1035
                $link_validator = '';
1036
                if (api_is_allowed_to_edit(null, true)) {
1037
                    $toolbar .= Display::toolbarButton(
1038
                        '',
1039
                        'javascript:void(0);',
1040
                        'check-circle',
1041
                        'secondary btn-sm',
1042
                        [
1043
                            'onclick' => "check_url('".$linkId."', '".addslashes($link->getUrl())."');",
1044
                            'title' => get_lang('Check link'),
1045
                        ]
1046
                    );
1047
1048
                    $link_validator .= Display::span(
1049
                        '',
1050
                        [
1051
                        'id' => 'url_id_'.$linkId,
1052
                        'class' => 'check-link',
1053
                        ]
1054
                    );
1055
1056
                    if ($session === $sessionEntity) {
1057
                        $url = api_get_self().'?'.api_get_cidreq().'&action=editlink&id='.$linkId;
1058
                        $title = get_lang('Edit');
1059
                        $toolbar .= Display::toolbarButton(
1060
                            '',
1061
                            $url,
1062
                            'pencil-alt',
1063
                            'secondary btn-sm',
1064
                            [
1065
                                'title' => $title,
1066
                            ]
1067
                        );
1068
                    }
1069
1070
                    $urlVisibility = api_get_self().'?'.api_get_cidreq().
1071
                            '&sec_token='.$token.
1072
                            '&id='.$linkId.
1073
                            '&scope=link&category_id='.$categoryId;
1074
1075
                    switch ($visibility) {
1076
                        case 1:
1077
                            $urlVisibility .= '&action=invisible';
1078
                            $title = get_lang('Make invisible');
1079
                            $toolbar .= Display::toolbarButton(
1080
                                '',
1081
                                $urlVisibility,
1082
                                'eye',
1083
                                'secondary btn-sm',
1084
                                [
1085
                                    'title' => $title,
1086
                                ]
1087
                            );
1088
                            break;
1089
                        case 0:
1090
                            $urlVisibility .= '&action=visible';
1091
                            $title = get_lang('Make Visible');
1092
                            $toolbar .= Display::toolbarButton(
1093
                                '',
1094
                                $urlVisibility,
1095
                                'eye-slash',
1096
                                'secondary btn-sm',
1097
                                [
1098
                                    'title' => $title,
1099
                                ]
1100
                            );
1101
                            break;
1102
                    }
1103
1104
                    if ($session === $sessionEntity) {
1105
                        $moveLinkParams = [
1106
                            'id' => $linkId,
1107
                            'scope' => 'category',
1108
                            'category_id' => $categoryId,
1109
                            'action' => 'move_link_up',
1110
                        ];
1111
1112
                        $toolbar .= Display::toolbarButton(
1113
                            get_lang('Move up'),
1114
                            api_get_self().'?'.api_get_cidreq().'&'.http_build_query($moveLinkParams),
1115
                            'level-up-alt',
1116
                            'secondary',
1117
                            ['class' => 'btn-sm '.(1 === $i ? 'disabled' : '')],
1118
                            false
1119
                        );
1120
1121
                        $moveLinkParams['action'] = 'move_link_down';
1122
                        $toolbar .= Display::toolbarButton(
1123
                            get_lang('Move down'),
1124
                            api_get_self().'?'.api_get_cidreq().'&'.http_build_query($moveLinkParams),
1125
                            'level-down-alt',
1126
                            'secondary',
1127
                            ['class' => 'btn-sm '.($i === $numberOfLinks ? 'disabled' : '')],
1128
                            false
1129
                        );
1130
1131
                        $url = api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=deletelink&id='.$linkId.'&category_id='.$categoryId;
1132
                        $event = "javascript: if(!confirm('".get_lang('Do you want to delete this link?')."'))return false;";
1133
                        $title = get_lang('Delete');
1134
1135
                        $toolbar .= Display::toolbarButton(
1136
                            '',
1137
                            $url,
1138
                            'trash',
1139
                            'secondary btn-sm',
1140
                            [
1141
                                'onclick' => $event,
1142
                                'title' => $title,
1143
                            ]
1144
                        );
1145
                    }
1146
                }
1147
1148
                $showLink = false;
1149
                $titleClass = '';
1150
                if ($visibility) {
1151
                    $showLink = true;
1152
                } else {
1153
                    if (api_is_allowed_to_edit(null, true)) {
1154
                        $showLink = true;
1155
                        $titleClass = 'text-muted';
1156
                    }
1157
                }
1158
1159
                if ($showLink) {
1160
                    $iconLink = Display::return_icon(
1161
                        'url.png',
1162
                        get_lang('Link'),
1163
                        null,
1164
                        ICON_SIZE_SMALL
1165
                    );
1166
                    $url = api_get_path(WEB_CODE_PATH).'link/link_goto.php?'.api_get_cidreq().'&link_id='.$linkId.'&link_url='.urlencode($link->getUrl());
1167
                    $content .= '<div class="list-group-item">';
1168
                    if ($showActionLinks) {
1169
                        $content .= '<div class="pull-right"><div class="btn-group">'.$toolbar.'</div></div>';
1170
                    }
1171
                    $content .= '<h4 class="list-group-item-heading">';
1172
                    $content .= $iconLink;
1173
                    $content .= Display::tag(
1174
                        'a',
1175
                        Security::remove_XSS($link->getTitle()),
1176
                        [
1177
                            'href' => $url,
1178
                            'target' => $link->getTarget(),
1179
                            'class' => $titleClass,
1180
                        ]
1181
                    );
1182
                    $content .= $link_validator;
1183
                    $content .= $session_img;
1184
                    $content .= '</h4>';
1185
                    $content .= '<p class="list-group-item-text">'.$link->getDescription().'</p>';
1186
                    $content .= '</div>';
1187
                }
1188
                $i++;
1189
            }
1190
            $content .= '</div>';
1191
        }
1192
1193
        return $content;
1194
    }
1195
1196
    /**
1197
     * Displays the edit, delete and move icons.
1198
     *
1199
     * @param int   Category ID
1200
     * @param int $currentCategory
1201
     * @param int $countCategories
1202
     *
1203
     * @return string
1204
     *
1205
     * @author Patrick Cool <[email protected]>, Ghent University
1206
     */
1207
    public static function showCategoryAdminTools(CLinkCategory $category, $currentCategory, $countCategories)
1208
    {
1209
        $categoryId = $category->getIid();
1210
        $token = null;
1211
        $tools = '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=editcategory&id='.$categoryId.'&category_id='.$categoryId.'" title='.get_lang('Edit').'">'.
1212
            Display:: return_icon(
1213
                'edit.png',
1214
                get_lang('Edit'),
1215
                [],
1216
                ICON_SIZE_SMALL
1217
            ).'</a>';
1218
1219
        // DISPLAY MOVE UP COMMAND only if it is not the top link.
1220
        if (0 != $currentCategory) {
1221
            $tools .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=up&up='.$categoryId.'&category_id='.$categoryId.'" title="'.get_lang('Up').'">'.
1222
                Display:: return_icon(
1223
                    'up.png',
1224
                    get_lang('Up'),
1225
                    [],
1226
                    ICON_SIZE_SMALL
1227
                ).'</a>';
1228
        } else {
1229
            $tools .= Display:: return_icon(
1230
                'up_na.png',
1231
                get_lang('Up'),
1232
                [],
1233
                ICON_SIZE_SMALL
1234
            ).'</a>';
1235
        }
1236
1237
        // DISPLAY MOVE DOWN COMMAND only if it is not the bottom link.
1238
        if ($currentCategory < $countCategories - 1) {
1239
            $tools .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=down&down='.$categoryId.'&category_id='.$categoryId.'">'.
1240
                Display:: return_icon(
1241
                    'down.png',
1242
                    get_lang('down'),
1243
                    [],
1244
                    ICON_SIZE_SMALL
1245
                ).'</a>';
1246
        } else {
1247
            $tools .= Display:: return_icon(
1248
                'down_na.png',
1249
                get_lang('down'),
1250
                [],
1251
                ICON_SIZE_SMALL
1252
            ).'</a>';
1253
        }
1254
1255
        $tools .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=deletecategory&id='.$categoryId."&category_id=$categoryId\"
1256
            onclick=\"javascript: if(!confirm('".get_lang('When deleting a category, all links of this category are also deleted.
1257
Do you really want to delete this category and its links ?')."')) return false;\">".
1258
            Display:: return_icon(
1259
                'delete.png',
1260
                get_lang('Delete'),
1261
                [],
1262
                ICON_SIZE_SMALL
1263
            ).'</a>';
1264
1265
        return $tools;
1266
    }
1267
1268
    /**
1269
     * move a link or a linkcategory up or down.
1270
     *
1271
     * @param   int Category ID
1272
     * @param   int Course ID
1273
     * @param   int Session ID
1274
     *
1275
     * @author Patrick Cool <[email protected]>, Ghent University
1276
     *
1277
     * @todo support sessions
1278
     */
1279
    public static function movecatlink($action, $catlinkid, $courseId = null, $sessionId = null)
1280
    {
1281
        $tbl_categories = Database::get_course_table(TABLE_LINK_CATEGORY);
1282
1283
        if (is_null($courseId)) {
1284
            $courseId = api_get_course_int_id();
1285
        }
1286
        $courseId = intval($courseId);
1287
        if (is_null($sessionId)) {
1288
            $sessionId = api_get_session_id();
1289
        }
1290
        $sessionId = intval($sessionId);
1291
        $thiscatlinkId = intval($catlinkid);
1292
1293
        if ('down' == $action) {
1294
            $sortDirection = 'DESC';
1295
        }
1296
1297
        if ('up' == $action) {
1298
            $sortDirection = 'ASC';
1299
        }
1300
1301
        $movetable = $tbl_categories;
1302
1303
        if (!empty($sortDirection)) {
1304
            if (!in_array(trim(strtoupper($sortDirection)), ['ASC', 'DESC'])) {
1305
                $sortDirection = 'ASC';
1306
            }
1307
1308
            $sql = "SELECT id, display_order FROM $tbl_categories
1309
                    WHERE c_id = $courseId
1310
                    ORDER BY display_order $sortDirection";
1311
            $linkresult = Database:: query($sql);
1312
            $thislinkOrder = 1;
1313
            while ($sortrow = Database:: fetch_array($linkresult)) {
1314
                // STEP 2 : FOUND THE NEXT LINK ID AND ORDER, COMMIT SWAP
1315
                // This part seems unlogic, but it isn't . We first look for the current link with the querystring ID
1316
                // and we know the next iteration of the while loop is the next one. These should be swapped.
1317
                if (isset($thislinkFound) && $thislinkFound) {
1318
                    $nextlinkId = $sortrow['id'];
1319
                    $nextlinkOrder = $sortrow['display_order'];
1320
1321
                    Database:: query(
1322
                        "UPDATE ".$movetable."
1323
                        SET display_order = '$nextlinkOrder'
1324
                        WHERE c_id = $courseId  AND id =  '$thiscatlinkId'"
1325
                    );
1326
                    Database:: query(
1327
                        "UPDATE ".$movetable."
1328
                        SET display_order = '$thislinkOrder'
1329
                        WHERE c_id = $courseId  AND id =  '$nextlinkId'"
1330
                    );
1331
1332
                    break;
1333
                }
1334
                if ($sortrow['id'] == $thiscatlinkId) {
1335
                    $thislinkOrder = $sortrow['display_order'];
1336
                    $thislinkFound = true;
1337
                }
1338
            }
1339
        }
1340
1341
        Display::addFlash(Display::return_message(get_lang('LinksMoved')));
1342
    }
1343
1344
    /**
1345
     * This function checks if the url is a vimeo link.
1346
     *
1347
     * @author Julio Montoya
1348
     *
1349
     * @version 1.0
1350
     */
1351
    public static function isVimeoLink($url)
1352
    {
1353
        $isLink = strrpos($url, 'vimeo.com');
1354
1355
        return $isLink;
1356
    }
1357
1358
    /**
1359
     * Get vimeo id from URL.
1360
     *
1361
     * @param string $url
1362
     *
1363
     * @return bool|mixed
1364
     */
1365
    public static function getVimeoLinkId($url)
1366
    {
1367
        $possibleUrls = [
1368
            'http://www.vimeo.com/',
1369
            'http://vimeo.com/',
1370
            'https://www.vimeo.com/',
1371
            'https://vimeo.com/',
1372
        ];
1373
        $url = str_replace($possibleUrls, '', $url);
1374
1375
        if (is_numeric($url)) {
1376
            return $url;
1377
        }
1378
1379
        return false;
1380
    }
1381
1382
    /**
1383
     * This function checks if the url is a youtube link.
1384
     *
1385
     * @author Jorge Frisancho
1386
     * @author Julio Montoya - Fixing code
1387
     *
1388
     * @version 1.0
1389
     */
1390
    public static function is_youtube_link($url)
1391
    {
1392
        $is_youtube_link = strrpos($url, 'youtube') || strrpos(
1393
            $url,
1394
            'youtu.be'
1395
        );
1396
1397
        return $is_youtube_link;
1398
    }
1399
1400
    /**
1401
     * This function checks if the url is a PDF File link.
1402
     *
1403
     * @author Jorge Frisancho
1404
     * @author Alex Aragón - Fixing code
1405
     *
1406
     * @version 1.0
1407
     */
1408
    public static function isPdfLink($url)
1409
    {
1410
        $isPdfLink = strrpos(strtolower($url), '.pdf');
1411
1412
        return $isPdfLink;
1413
    }
1414
1415
    /**
1416
     * Get youtube id from an URL.
1417
     *
1418
     * @param string $url
1419
     *
1420
     * @return string
1421
     */
1422
    public static function get_youtube_video_id($url)
1423
    {
1424
        // This is the length of YouTube's video IDs
1425
        $len = 11;
1426
1427
        // The ID string starts after "v=", which is usually right after
1428
        // "youtube.com/watch?" in the URL
1429
        $pos = strpos($url, "v=");
1430
        $id = '';
1431
1432
        //If false try other options
1433
        if (false === $pos) {
1434
            $url_parsed = parse_url($url);
1435
1436
            //Youtube shortener
1437
            //http://youtu.be/ID
1438
            $pos = strpos($url, "youtu.be");
1439
1440
            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...
1441
                $id = '';
1442
            } else {
1443
                return substr($url_parsed['path'], 1);
1444
            }
1445
1446
            //if empty try the youtube.com/embed/ID
1447
            if (empty($id)) {
1448
                $pos = strpos($url, "embed");
1449
                if (false === $pos) {
1450
                    return '';
1451
                } else {
1452
                    return substr($url_parsed['path'], 7);
1453
                }
1454
            }
1455
        } else {
1456
            // Offset the start location to match the beginning of the ID string
1457
            $pos += 2;
1458
            // Get the ID string and return it
1459
            $id = substr($url, $pos, $len);
1460
1461
            return $id;
1462
        }
1463
    }
1464
1465
    /**
1466
     * @param int    $courseId
1467
     * @param int    $sessionId
1468
     * @param int    $categoryId
1469
     * @param string $show
1470
     * @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...
1471
     * @param bool   $showActionLinks
1472
     * @param bool   $forceOpenCategories
1473
     *
1474
     * @return string
1475
     */
1476
    public static function listLinksAndCategories(
1477
        $courseId,
1478
        $sessionId,
1479
        $categoryId,
1480
        $show = 'none',
1481
        $token = null,
1482
        $showActionLinks = true,
1483
        $forceOpenCategories = false
1484
    ) {
1485
        $categoryId = (int) $categoryId;
1486
        $content = '';
1487
        $categories = self::getLinkCategories($courseId, $sessionId);
1488
        $countCategories = count($categories);
1489
        $linksPerCategory = self::showLinksPerCategory(0, $courseId, $sessionId, $showActionLinks);
1490
1491
        if ($showActionLinks) {
1492
            /*	Action Links */
1493
            $content = '<div class="actions">';
1494
            if (api_is_allowed_to_edit(null, true)) {
1495
                $content .= '<a href="'.api_get_self().'?'.api_get_cidreq(
1496
                    ).'&action=addlink&category_id='.$categoryId.'">'.
1497
                    Display::return_icon('new_link.png', get_lang('Add a link'), '', ICON_SIZE_MEDIUM).'</a>';
1498
                $content .= '<a href="'.api_get_self().'?'.api_get_cidreq(
1499
                    ).'&action=addcategory&category_id='.$categoryId.'">'.
1500
                    Display::return_icon('new_folder.png', get_lang('Add a category'), '', ICON_SIZE_MEDIUM).'</a>';
1501
            }
1502
1503
            if (!empty($countCategories)) {
1504
                $content .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=list&show=none">';
1505
                $content .= Display::return_icon(
1506
                        'forum_listview.png',
1507
                        get_lang('List View'),
1508
                        '',
1509
                        ICON_SIZE_MEDIUM
1510
                    ).' </a>';
1511
1512
                $content .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=list&show=all">';
1513
                $content .= Display::return_icon(
1514
                        'forum_nestedview.png',
1515
                        get_lang('Nested View'),
1516
                        '',
1517
                        ICON_SIZE_MEDIUM
1518
                    ).'</a>';
1519
            }
1520
1521
            $content .= Display::url(
1522
                Display::return_icon('pdf.png', get_lang('Export to PDF'), '', ICON_SIZE_MEDIUM),
1523
                api_get_self().'?'.api_get_cidreq().'&action=export'
1524
            );
1525
            $content .= '</div>';
1526
        }
1527
1528
        if (empty($countCategories)) {
1529
            $content .= $linksPerCategory;
1530
        } else {
1531
            if (!empty($linksPerCategory)) {
1532
                $content .= Display::panel($linksPerCategory, get_lang('General'));
1533
            }
1534
        }
1535
1536
        $counter = 0;
1537
        $courseEntity = api_get_course_entity($courseId);
1538
        $sessionEntity = api_get_session_entity($sessionId);
1539
        $allowToEdit = api_is_allowed_to_edit(null, true);
1540
1541
        foreach ($categories as $category) {
1542
            $categoryItemId = $category->getIid();
1543
            $isVisible = $category->isVisible($courseEntity, $sessionEntity);
1544
            // Student don't see invisible categories.
1545
            if (!$allowToEdit) {
1546
                if (!$isVisible) {
1547
                    continue;
1548
                }
1549
            }
1550
1551
            // Validation when belongs to a session
1552
            $showChildren = $categoryId === $categoryItemId || 'all' === $show;
1553
            if ($forceOpenCategories) {
1554
                $showChildren = true;
1555
            }
1556
1557
            $strVisibility = '';
1558
            $visibilityClass = null;
1559
            if ($isVisible) {
1560
                $strVisibility = '<a
1561
                    href="link.php?'.api_get_cidreq().'&sec_token='.$token.'&action=invisible&id='.$categoryItemId.'&scope='.TOOL_LINK_CATEGORY.'"
1562
                    title="'.get_lang('Hide').'">'.
1563
                    Display::return_icon('visible.png', get_lang('Hide'), [], ICON_SIZE_SMALL).'</a>';
1564
            } elseif (!$isVisible) {
1565
                $visibilityClass = 'text-muted';
1566
                $strVisibility = ' <a
1567
                    href="link.php?'.api_get_cidreq().'&sec_token='.$token.'&action=visible&id='.$categoryItemId.'&scope='.TOOL_LINK_CATEGORY.'"
1568
                    title="'.get_lang('Show').'">'.
1569
                    Display::return_icon('invisible.png', get_lang('Show'), [], ICON_SIZE_SMALL).'</a>';
1570
            }
1571
1572
            $header = '';
1573
            if ($showChildren) {
1574
                $header .= '<a
1575
                    class="'.$visibilityClass.'" href="'.api_get_self().'?'.api_get_cidreq().'&category_id=">';
1576
                $header .= Display::return_icon('forum_nestedview.png');
1577
            } else {
1578
                $header .= '<a
1579
                    class="'.$visibilityClass.'" href="'.api_get_self().'?'.api_get_cidreq().'&category_id='.$categoryItemId.'">';
1580
                $header .= Display::return_icon('forum_listview.png');
1581
            }
1582
            $header .= Security::remove_XSS($category->getCategoryTitle()).'</a>';
1583
1584
            if ($showActionLinks) {
1585
                if ($allowToEdit) {
1586
                    if ($category->getFirstResourceLink() &&
1587
                        $sessionEntity ===  $category->getFirstResourceLink()->getSession()
1588
                    ) {
1589
                        $header .= $strVisibility;
1590
                        $header .= self::showCategoryAdminTools($category, $counter, count($categories));
1591
                    } else {
1592
                        $header .= get_lang('Edition not available from the session, please edit from the basic course.');
1593
                    }
1594
                }
1595
            }
1596
1597
            $childrenContent = '';
1598
            if ($showChildren) {
1599
                $childrenContent = self::showLinksPerCategory(
1600
                    $categoryItemId,
1601
                    api_get_course_int_id(),
1602
                    api_get_session_id()
1603
                );
1604
            }
1605
1606
            $content .= Display::panel($category->getDescription().$childrenContent, $header);
1607
            $counter++;
1608
        }
1609
1610
        return $content;
1611
    }
1612
1613
    /**
1614
     * @param int    $linkId
1615
     * @param string $action
1616
     * @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...
1617
     *
1618
     * @return FormValidator
1619
     */
1620
    public static function getLinkForm($linkId, $action, $token = null)
1621
    {
1622
        $courseId = api_get_course_int_id();
1623
        $sessionId = api_get_session_id();
1624
        $linkInfo = self::getLinkInfo($linkId);
1625
        $categoryId = isset($linkInfo['category_id']) ? $linkInfo['category_id'] : '';
1626
        $lpId = isset($_GET['lp_id']) ? Security::remove_XSS($_GET['lp_id']) : null;
1627
1628
        $form = new FormValidator(
1629
            'link',
1630
            'post',
1631
            api_get_self().'?action='.$action.
1632
            '&category_id='.$categoryId.
1633
            '&'.api_get_cidreq().
1634
            '&id='.$linkId.
1635
            '&sec_token='.$token
1636
        );
1637
1638
        if ('addlink' === $action) {
1639
            $form->addHeader(get_lang('LinksAdd'));
1640
        } else {
1641
            $form->addHeader(get_lang('LinksMod'));
1642
        }
1643
1644
        $target_link = '_blank';
1645
        $title = '';
1646
        $category = '';
1647
        $onhomepage = '';
1648
        $description = '';
1649
1650
        if (!empty($linkInfo)) {
1651
            $urllink = $linkInfo['url'];
1652
            $title = $linkInfo['title'];
1653
            $description = $linkInfo['description'];
1654
            $category = $linkInfo['category_id'];
1655
            if (0 != $linkInfo['on_homepage']) {
1656
                $onhomepage = 1;
1657
            }
1658
            $target_link = $linkInfo['target'];
1659
        }
1660
1661
        $form->addHidden('id', $linkId);
1662
        $form->addText('url', 'URL');
1663
        $form->addRule('url', get_lang('Please give the link URL, it should be valid.'), 'url');
1664
        $form->addText('title', get_lang('LinksName'));
1665
        $form->addHtmlEditor('description', get_lang('Description'), false, false, ['ToolbarSet' => 'Profile', 'Width' => '100%', 'Height' => '130']);
1666
1667
        $resultcategories = self::getLinkCategories($courseId, $sessionId);
1668
        $options = ['0' => '--'];
1669
        if (!empty($resultcategories)) {
1670
            foreach ($resultcategories as $myrow) {
1671
                $options[$myrow->getIid()] = $myrow->getCategoryTitle();
1672
            }
1673
        }
1674
1675
        $form->addSelect('category_id', get_lang('Category'), $options);
1676
        $form->addCheckBox('on_homepage', null, get_lang('Show link on course homepage'));
1677
1678
        $targets = [
1679
            '_self' => get_lang('LinksOpenSelf'),
1680
            '_blank' => get_lang('LinksOpenBlank'),
1681
            '_parent' => get_lang('LinksOpenParent'),
1682
            '_top' => get_lang('LinksOpenTop'),
1683
        ];
1684
1685
        $form->addSelect(
1686
            'target',
1687
            [
1688
                get_lang('LinksTarget'),
1689
                get_lang('AddTargetOfLinksShow link on course homepage'),
1690
            ],
1691
            $targets
1692
        );
1693
1694
        $defaults = [
1695
            'url' => empty($urllink) ? 'http://' : Security::remove_XSS($urllink),
1696
            'title' => Security::remove_XSS($title),
1697
            'category_id' => $category,
1698
            'on_homepage' => $onhomepage,
1699
            'description' => $description,
1700
            'target' => $target_link,
1701
        ];
1702
1703
        if ('true' == api_get_setting('search_enabled')) {
1704
            require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
1705
            $specific_fields = get_specific_field_list();
1706
            $form->addCheckBox('index_document', get_lang('Index link title and description?s'), get_lang('Yes'));
1707
1708
            foreach ($specific_fields as $specific_field) {
1709
                $default_values = '';
1710
                if ('editlink' == $action) {
1711
                    $filter = [
1712
                        'field_id' => $specific_field['id'],
1713
                        'ref_id' => intval($_GET['id']),
1714
                        'tool_id' => '\''.TOOL_LINK.'\'',
1715
                    ];
1716
                    $values = get_specific_field_values_list($filter, ['value']);
1717
                    if (!empty($values)) {
1718
                        $arr_str_values = [];
1719
                        foreach ($values as $value) {
1720
                            $arr_str_values[] = $value['value'];
1721
                        }
1722
                        $default_values = implode(', ', $arr_str_values);
1723
                    }
1724
                }
1725
                $form->addText($specific_field['name'], $specific_field['code']);
1726
                $defaults[$specific_field['name']] = $default_values;
1727
            }
1728
        }
1729
1730
        $skillList = Skill::addSkillsToForm($form, ITEM_TYPE_LINK, $linkId);
1731
        $form->addHidden('lp_id', $lpId);
1732
        $form->addButtonSave(get_lang('Save links'), 'submitLink');
1733
        $defaults['skills'] = array_keys($skillList);
1734
        $form->setDefaults($defaults);
1735
1736
        return $form;
1737
    }
1738
1739
    /**
1740
     * @param int    $id
1741
     * @param string $action
1742
     *
1743
     * @return FormValidator
1744
     */
1745
    public static function getCategoryForm($id, $action)
1746
    {
1747
        $id = (int) $id;
1748
        $action = Security::remove_XSS($action);
1749
1750
        $form = new FormValidator(
1751
            'category',
1752
            'post',
1753
            api_get_self().'?action='.$action.'&'.api_get_cidreq()
1754
        );
1755
1756
        $defaults = [];
1757
        if ('addcategory' === $action) {
1758
            $form->addHeader(get_lang('Add a category'));
1759
            $my_cat_title = get_lang('Add a category');
1760
        } else {
1761
            $form->addHeader(get_lang('Edit Category'));
1762
            $my_cat_title = get_lang('Edit Category');
1763
            $defaults = self::getCategory($id);
1764
        }
1765
        $form->addHidden('id', $id);
1766
        $form->addText('category_title', get_lang('Category name'));
1767
        $form->addHtmlEditor(
1768
            'description',
1769
            get_lang('Description'),
1770
            false,
1771
            false,
1772
            ['ToolbarSet' => 'Profile', 'Width' => '100%', 'Height' => '130']
1773
        );
1774
        $form->addButtonSave($my_cat_title, 'submitCategory');
1775
        $form->setDefaults($defaults);
1776
1777
        return $form;
1778
    }
1779
1780
    /**
1781
     * @param int $id
1782
     *
1783
     * @return array
1784
     */
1785
    public static function getCategory($id)
1786
    {
1787
        $table = Database::get_course_table(TABLE_LINK_CATEGORY);
1788
        $id = (int) $id;
1789
        $courseId = api_get_course_int_id();
1790
1791
        if (empty($id) || empty($courseId)) {
1792
            return [];
1793
        }
1794
        $sql = "SELECT * FROM $table
1795
                WHERE iid = $id";
1796
        $result = Database::query($sql);
1797
1798
        return Database::fetch_array($result, 'ASSOC');
1799
    }
1800
1801
    /**
1802
     * Move a link up in its category.
1803
     *
1804
     * @param int $id
1805
     *
1806
     * @return bool
1807
     */
1808
    public static function moveLinkUp($id)
1809
    {
1810
        return self::moveLinkDisplayOrder($id, 'ASC');
1811
    }
1812
1813
    /**
1814
     * Move a link down in its category.
1815
     *
1816
     * @param int $id
1817
     *
1818
     * @return bool
1819
     */
1820
    public static function moveLinkDown($id)
1821
    {
1822
        return self::moveLinkDisplayOrder($id, 'DESC');
1823
    }
1824
1825
    /**
1826
     * @param string $url
1827
     *
1828
     * @return bool
1829
     */
1830
    public static function checkUrl($url)
1831
    {
1832
        // Check if curl is available.
1833
        if (!in_array('curl', get_loaded_extensions())) {
1834
            return false;
1835
        }
1836
1837
        // set URL and other appropriate options
1838
        $defaults = [
1839
            CURLOPT_URL => $url,
1840
            CURLOPT_FOLLOWLOCATION => true, // follow redirects accept youtube.com
1841
            CURLOPT_HEADER => 0,
1842
            CURLOPT_RETURNTRANSFER => true,
1843
            CURLOPT_TIMEOUT => 4,
1844
        ];
1845
1846
        $proxySettings = api_get_configuration_value('proxy_settings');
1847
1848
        if (!empty($proxySettings) &&
1849
            isset($proxySettings['curl_setopt_array'])
1850
        ) {
1851
            $defaults[CURLOPT_PROXY] = $proxySettings['curl_setopt_array']['CURLOPT_PROXY'];
1852
            $defaults[CURLOPT_PROXYPORT] = $proxySettings['curl_setopt_array']['CURLOPT_PROXYPORT'];
1853
        }
1854
1855
        // Create a new cURL resource
1856
        $ch = curl_init();
1857
        curl_setopt_array($ch, $defaults);
1858
1859
        // grab URL and pass it to the browser
1860
        ob_start();
1861
        $result = curl_exec($ch);
1862
        ob_get_clean();
1863
1864
        // close cURL resource, and free up system resources
1865
        curl_close($ch);
1866
1867
        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...
1868
    }
1869
1870
    /**
1871
     * Move a link inside its category (display_order field).
1872
     *
1873
     * @param int    $id        The link ID
1874
     * @param string $direction The direction to sort the links
1875
     *
1876
     * @return bool
1877
     */
1878
    private static function moveLinkDisplayOrder($id, $direction)
1879
    {
1880
        $em = Database::getManager();
1881
        $repo = Container::getLinkRepository();
1882
1883
        /** @var CLink $link */
1884
        $link = $repo->find($id);
1885
1886
        if (!$link) {
0 ignored issues
show
introduced by
$link is of type Chamilo\CourseBundle\Entity\CLink, thus it always evaluated to true.
Loading history...
1887
            return false;
1888
        }
1889
1890
        $compareLinks = $repo
1891
            ->findBy(
1892
                [
1893
                    'categoryId' => $link->getCategory() ? $link->getCategory()->getIid() : 0,
1894
                ],
1895
                ['displayOrder' => $direction]
1896
            );
1897
1898
        /** @var CLink $prevLink */
1899
        $prevLink = null;
1900
1901
        /** @var CLink $compareLink */
1902
        foreach ($compareLinks as $compareLink) {
1903
            if ($compareLink->getIid() !== $link->getIid()) {
1904
                $prevLink = $compareLink;
1905
1906
                continue;
1907
            }
1908
1909
            if (!$prevLink) {
1910
                return false;
1911
            }
1912
1913
            $newPrevLinkDisplayOrder = $link->getDisplayOrder();
1914
            $newLinkDisplayOrder = $prevLink->getDisplayOrder();
1915
1916
            $link->setDisplayOrder($newLinkDisplayOrder);
1917
            $prevLink->setDisplayOrder($newPrevLinkDisplayOrder);
1918
1919
            $em->persist($prevLink);
1920
            $em->persist($link);
1921
            break;
1922
        }
1923
1924
        $em->flush();
1925
1926
        return true;
1927
    }
1928
}
1929