Passed
Branch 1.11.x (12bab0)
by Julito
16:55 queued 05:17
created

Link::moveLinkUp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CourseBundle\Entity\CLink;
5
6
/**
7
 * Function library for the links tool.
8
 *
9
 * This is a complete remake of the original link tool.
10
 * New features:
11
 * - Organize links into categories;
12
 * - favorites/bookmarks interface;
13
 * - move links up/down within a category;
14
 * - move categories up/down;
15
 * - expand/collapse all categories;
16
 * - add link to 'root' category => category-less link is always visible.
17
 *
18
 * @author Patrick Cool, complete remake (December 2003 - January 2004)
19
 * @author René Haentjens, CSV file import (October 2004)
20
 *
21
 * @package chamilo.link
22
 */
23
class Link extends Model
24
{
25
    public $table;
26
    public $is_course_model = true;
27
    public $columns = [
28
        'id',
29
        'c_id',
30
        'url',
31
        'title',
32
        'description',
33
        'category_id',
34
        'display_order',
35
        'on_homepage',
36
        'target',
37
        'session_id',
38
    ];
39
    public $required = ['url', 'title'];
40
    private $course;
41
42
    /**
43
     * Link constructor.
44
     */
45
    public function __construct()
46
    {
47
        $this->table = Database::get_course_table(TABLE_LINK);
48
    }
49
50
    /**
51
     * @param array $course
52
     */
53
    public function setCourse($course)
54
    {
55
        $this->course = $course;
56
    }
57
58
    /**
59
     * @return array
60
     */
61
    public function getCourse()
62
    {
63
        return !empty($this->course) ? $this->course : api_get_course_info();
64
    }
65
66
    /**
67
     * Organize the saving of a link, using the parent's save method and
68
     * updating the item_property table.
69
     *
70
     * @param array $params
71
     * @param bool  $show_query Whether to show the query in logs when
72
     *                          calling parent's save method
73
     *
74
     * @return bool True if link could be saved, false otherwise
75
     */
76
    public function save($params, $show_query = null)
77
    {
78
        $course_info = $this->getCourse();
79
        $courseId = $course_info['real_id'];
80
81
        $params['session_id'] = api_get_session_id();
82
        $params['category_id'] = isset($params['category_id']) ? $params['category_id'] : 0;
83
84
        $sql = "SELECT MAX(display_order)
85
                FROM  ".$this->table."
86
                WHERE
87
                    c_id = $courseId AND
88
                    category_id = '".intval($params['category_id'])."'";
89
        $result = Database:: query($sql);
90
        list($orderMax) = Database:: fetch_row($result);
91
        $order = $orderMax + 1;
92
        $params['display_order'] = $order;
93
94
        $id = parent::save($params, $show_query);
95
96
        if (!empty($id)) {
97
            // iid
98
            $sql = "UPDATE ".$this->table." SET id = iid WHERE iid = $id";
99
            Database::query($sql);
100
101
            api_item_property_update(
102
                $course_info,
103
                TOOL_LINK,
104
                $id,
105
                'LinkAdded',
106
                api_get_user_id()
107
            );
108
109
            api_set_default_visibility($id, TOOL_LINK);
110
        }
111
112
        return $id;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $id also could return the type integer which is incompatible with the documented return type boolean.
Loading history...
113
    }
114
115
    /**
116
     * Update a link in the database.
117
     *
118
     * @param int    $linkId    The ID of the link to update
119
     * @param string $linkUrl   The new URL to be saved
120
     * @param int    $courseId
121
     * @param int    $sessionId
122
     *
123
     * @return bool
124
     */
125
    public function updateLink(
126
        $linkId,
127
        $linkUrl,
128
        $courseId = null,
129
        $sessionId = null
130
    ) {
131
        $tblLink = Database::get_course_table(TABLE_LINK);
132
        $linkUrl = Database::escape_string($linkUrl);
133
        $linkId = intval($linkId);
134
        if (is_null($courseId)) {
135
            $courseId = api_get_course_int_id();
136
        }
137
        $courseId = intval($courseId);
138
        if (is_null($sessionId)) {
139
            $sessionId = api_get_session_id();
140
        }
141
        $sessionId = intval($sessionId);
142
        if ($linkUrl != '') {
143
            $sql = "UPDATE $tblLink SET 
144
                    url = '$linkUrl'
145
                    WHERE id = $linkId AND c_id = $courseId AND session_id = $sessionId";
146
            $resLink = Database::query($sql);
147
148
            return $resLink;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $resLink returns the type Doctrine\DBAL\Driver\Statement which is incompatible with the documented return type boolean.
Loading history...
149
        }
150
151
        return false;
152
    }
153
154
    /**
155
     * Used to add a link or a category.
156
     *
157
     * @param string $type , "link" or "category"
158
     *
159
     * @todo replace strings by constants
160
     *
161
     * @author Patrick Cool <[email protected]>, Ghent University
162
     *
163
     * @return bool True on success, false on failure
164
     */
165
    public static function addlinkcategory($type)
166
    {
167
        $ok = true;
168
        $_course = api_get_course_info();
169
        $course_id = $_course['real_id'];
170
        $session_id = api_get_session_id();
171
172
        if ($type == 'link') {
173
            $title = Security::remove_XSS(stripslashes($_POST['title']));
174
            $urllink = Security::remove_XSS($_POST['url']);
175
            $description = Security::remove_XSS($_POST['description']);
176
            $selectcategory = Security::remove_XSS($_POST['category_id']);
177
178
            $onhomepage = 0;
179
            if (isset($_POST['on_homepage'])) {
180
                $onhomepage = Security::remove_XSS($_POST['on_homepage']);
181
            }
182
183
            $target = '_self'; // Default target.
184
            if (!empty($_POST['target'])) {
185
                $target = Security::remove_XSS($_POST['target']);
186
            }
187
188
            $urllink = trim($urllink);
189
            $title = trim($title);
190
            $description = trim($description);
191
192
            // We ensure URL to be absolute.
193
            if (strpos($urllink, '://') === false) {
194
                $urllink = 'http://'.$urllink;
195
            }
196
197
            // If the title is empty, we use the URL as title.
198
            if ($title == '') {
199
                $title = $urllink;
200
            }
201
202
            // If the URL is invalid, an error occurs.
203
            if (!api_valid_url($urllink, true)) {
204
                // A check against an absolute URL
205
                Display::addFlash(Display::return_message(get_lang('GiveURL'), 'error'));
206
207
                return false;
208
            } else {
209
                // Looking for the largest order number for this category.
210
                $link = new Link();
211
                $params = [
212
                    'c_id' => $course_id,
213
                    'url' => $urllink,
214
                    'title' => $title,
215
                    'description' => $description,
216
                    'category_id' => $selectcategory,
217
                    'on_homepage' => $onhomepage,
218
                    'target' => $target,
219
                    'session_id' => $session_id,
220
                ];
221
                $link_id = $link->save($params);
222
223
                if ((api_get_setting('search_enabled') == 'true') &&
224
                    $link_id && extension_loaded('xapian')
225
                ) {
226
                    require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
227
228
                    $course_int_id = $_course['real_id'];
229
                    $courseCode = $_course['code'];
230
                    $specific_fields = get_specific_field_list();
231
                    $ic_slide = new IndexableChunk();
232
233
                    // Add all terms to db.
234
                    $all_specific_terms = '';
235
                    foreach ($specific_fields as $specific_field) {
236
                        if (isset($_REQUEST[$specific_field['code']])) {
237
                            $sterms = trim($_REQUEST[$specific_field['code']]);
238
                            if (!empty($sterms)) {
239
                                $all_specific_terms .= ' '.$sterms;
240
                                $sterms = explode(',', $sterms);
241
                                foreach ($sterms as $sterm) {
242
                                    $ic_slide->addTerm(
243
                                        trim($sterm),
244
                                        $specific_field['code']
245
                                    );
246
                                    add_specific_field_value(
247
                                        $specific_field['id'],
248
                                        $courseCode,
249
                                        TOOL_LINK,
250
                                        $link_id,
251
                                        $sterm
252
                                    );
253
                                }
254
                            }
255
                        }
256
                    }
257
258
                    // Build the chunk to index.
259
                    $ic_slide->addValue('title', $title);
260
                    $ic_slide->addCourseId($courseCode);
261
                    $ic_slide->addToolId(TOOL_LINK);
262
                    $xapian_data = [
263
                        SE_COURSE_ID => $courseCode,
264
                        SE_TOOL_ID => TOOL_LINK,
265
                        SE_DATA => [
266
                            'link_id' => (int) $link_id,
267
                        ],
268
                        SE_USER => (int) api_get_user_id(),
269
                    ];
270
                    $ic_slide->xapian_data = serialize($xapian_data);
271
                    $description = $all_specific_terms.' '.$description;
272
                    $ic_slide->addValue('content', $description);
273
274
                    // Add category name if set.
275
                    if (isset($selectcategory) && $selectcategory > 0) {
276
                        $table_link_category = Database::get_course_table(
277
                            TABLE_LINK_CATEGORY
278
                        );
279
                        $sql_cat = 'SELECT * FROM %s WHERE id=%d AND c_id = %d LIMIT 1';
280
                        $sql_cat = sprintf(
281
                            $sql_cat,
282
                            $table_link_category,
283
                            (int) $selectcategory,
284
                            $course_int_id
285
                        );
286
                        $result = Database:: query($sql_cat);
287
                        if (Database:: num_rows($result) == 1) {
288
                            $row = Database:: fetch_array($result);
289
                            $ic_slide->addValue(
290
                                'category',
291
                                $row['category_title']
292
                            );
293
                        }
294
                    }
295
296
                    $di = new ChamiloIndexer();
297
                    isset($_POST['language']) ? $lang = Database:: escape_string(
298
                        $_POST['language']
299
                    ) : $lang = 'english';
300
                    $di->connectDb(null, null, $lang);
301
                    $di->addChunk($ic_slide);
302
303
                    // Index and return search engine document id.
304
                    $did = $di->index();
305
                    if ($did) {
306
                        // Save it to db.
307
                        $tbl_se_ref = Database::get_main_table(
308
                            TABLE_MAIN_SEARCH_ENGINE_REF
309
                        );
310
                        $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, search_did)
311
                                VALUES (NULL , \'%s\', \'%s\', %s, %s)';
312
                        $sql = sprintf(
313
                            $sql,
314
                            $tbl_se_ref,
315
                            $course_int_id,
316
                            $courseCode,
317
                            TOOL_LINK,
318
                            $link_id,
319
                            $did
320
                        );
321
                        Database:: query($sql);
322
                    }
323
                }
324
                Display::addFlash(Display::return_message(get_lang('LinkAdded')));
325
326
                return $link_id;
327
            }
328
        } elseif ($type == 'category') {
329
            $tbl_categories = Database::get_course_table(TABLE_LINK_CATEGORY);
330
331
            $category_title = trim($_POST['category_title']);
332
            $description = trim($_POST['description']);
333
334
            if (empty($category_title)) {
335
                echo Display::return_message(get_lang('GiveCategoryName'), 'error');
336
                $ok = false;
337
            } else {
338
                // Looking for the largest order number for this category.
339
                $result = Database:: query(
340
                    "SELECT MAX(display_order) FROM  $tbl_categories
341
                    WHERE c_id = $course_id "
342
                );
343
                list($orderMax) = Database:: fetch_row($result);
344
                $order = $orderMax + 1;
345
                $order = intval($order);
346
                $session_id = api_get_session_id();
347
348
                $params = [
349
                    'c_id' => $course_id,
350
                    'category_title' => $category_title,
351
                    'description' => $description,
352
                    'display_order' => $order,
353
                    'session_id' => $session_id,
354
                ];
355
                $linkId = Database::insert($tbl_categories, $params);
356
357
                if ($linkId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $linkId of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
358
                    // iid
359
                    $sql = "UPDATE $tbl_categories SET id = iid WHERE iid = $linkId";
360
                    Database:: query($sql);
361
362
                    // add link_category visibility
363
                    // course ID is taken from context in api_set_default_visibility
364
                    //api_set_default_visibility($linkId, TOOL_LINK_CATEGORY);
365
                    api_item_property_update(
366
                        $_course,
367
                        TOOL_LINK_CATEGORY,
368
                        $linkId,
369
                        'LinkCategoryAdded',
370
                        api_get_user_id()
371
                    );
372
                    api_set_default_visibility($linkId, TOOL_LINK_CATEGORY);
373
                }
374
375
                Display::addFlash(Display::return_message(get_lang('CategoryAdded')));
376
377
                return $linkId;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $linkId also could return the type integer which is incompatible with the documented return type boolean.
Loading history...
378
            }
379
        }
380
381
        return $ok;
382
    }
383
384
    /**
385
     * Used to delete a link or a category.
386
     *
387
     * @author Patrick Cool <[email protected]>, Ghent University
388
     *
389
     * @param int    $id
390
     * @param string $type The type of item to delete
391
     *
392
     * @return bool
393
     */
394
    public static function deletelinkcategory($id, $type)
395
    {
396
        $courseInfo = api_get_course_info();
397
        $tbl_link = Database::get_course_table(TABLE_LINK);
398
        $tbl_categories = Database::get_course_table(TABLE_LINK_CATEGORY);
399
400
        $course_id = $courseInfo['real_id'];
401
        $id = intval($id);
402
403
        if (empty($id)) {
404
            return false;
405
        }
406
407
        $result = false;
408
        switch ($type) {
409
            case 'link':
410
                // -> Items are no longer physically deleted,
411
                // but the visibility is set to 2 (in item_property).
412
                // This will make a restore function possible for the platform administrator.
413
                $sql = "UPDATE $tbl_link SET on_homepage='0'
414
                        WHERE c_id = $course_id AND id='".$id."'";
415
                Database:: query($sql);
416
417
                api_item_property_update(
418
                    $courseInfo,
419
                    TOOL_LINK,
420
                    $id,
421
                    'delete',
422
                    api_get_user_id()
423
                );
424
                self::delete_link_from_search_engine(api_get_course_id(), $id);
425
                Skill::deleteSkillsFromItem($id, ITEM_TYPE_LINK);
426
                Display::addFlash(Display::return_message(get_lang('LinkDeleted')));
427
                $result = true;
428
                break;
429
            case 'category':
430
                // First we delete the category itself and afterwards all the links of this category.
431
                $sql = "DELETE FROM ".$tbl_categories."
432
                        WHERE c_id = $course_id AND id='".$id."'";
433
                Database:: query($sql);
434
435
                $sql = "DELETE FROM ".$tbl_link."
436
                        WHERE c_id = $course_id AND category_id='".$id."'";
437
                Database:: query($sql);
438
439
                api_item_property_update(
440
                    $courseInfo,
441
                    TOOL_LINK_CATEGORY,
442
                    $id,
443
                    'delete',
444
                    api_get_user_id()
445
                );
446
447
                Display::addFlash(Display::return_message(get_lang('CategoryDeleted')));
448
                $result = true;
449
                break;
450
        }
451
452
        return $result;
453
    }
454
455
    /**
456
     * Removes a link from search engine database.
457
     *
458
     * @param string $course_id Course code
459
     * @param int    $link_id   Document id to delete
460
     */
461
    public static function delete_link_from_search_engine($course_id, $link_id)
462
    {
463
        // Remove from search engine if enabled.
464
        if (api_get_setting('search_enabled') === 'true') {
465
            $tbl_se_ref = Database::get_main_table(
466
                TABLE_MAIN_SEARCH_ENGINE_REF
467
            );
468
            $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
469
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_LINK, $link_id);
470
            $res = Database:: query($sql);
471
            if (Database:: num_rows($res) > 0) {
472
                $row = Database::fetch_array($res);
473
                $di = new ChamiloIndexer();
474
                $di->remove_document($row['search_did']);
475
            }
476
            $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
477
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_LINK, $link_id);
478
            Database:: query($sql);
479
480
            // Remove terms from db.
481
            require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
482
            delete_all_values_for_item($course_id, TOOL_DOCUMENT, $link_id);
483
        }
484
    }
485
486
    /**
487
     * Get link info.
488
     *
489
     * @param int $id
490
     *
491
     * @return array link info
492
     */
493
    public static function getLinkInfo($id)
494
    {
495
        $tbl_link = Database::get_course_table(TABLE_LINK);
496
        $course_id = api_get_course_int_id();
497
498
        if (empty($id) || empty($course_id)) {
499
            return [];
500
        }
501
502
        $sql = "SELECT * FROM $tbl_link
503
                WHERE c_id = $course_id AND id='".intval($id)."' ";
504
        $result = Database::query($sql);
505
        $data = [];
506
        if (Database::num_rows($result)) {
507
            $data = Database::fetch_array($result);
508
        }
509
510
        return $data;
511
    }
512
513
    /**
514
     * @param int   $id
515
     * @param array $values
516
     */
517
    public static function editLink($id, $values = [])
518
    {
519
        $tbl_link = Database::get_course_table(TABLE_LINK);
520
        $_course = api_get_course_info();
521
        $course_id = $_course['real_id'];
522
        $id = intval($id);
523
524
        $values['url'] = trim($values['url']);
525
        $values['title'] = trim($values['title']);
526
        $values['description'] = trim($values['description']);
527
        $values['target'] = empty($values['target']) ? '_self' : $values['target'];
528
        $values['on_homepage'] = isset($values['on_homepage']) ? $values['on_homepage'] : '';
529
530
        $categoryId = intval($values['category_id']);
531
532
        // We ensure URL to be absolute.
533
        if (strpos($values['url'], '://') === false) {
534
            $values['url'] = 'http://'.$_POST['url'];
535
        }
536
537
        // If the title is empty, we use the URL as title.
538
        if ($values['title'] == '') {
539
            $values['title'] = $values['url'];
540
        }
541
542
        // If the URL is invalid, an error occurs.
543
        if (!api_valid_url($values['url'], true)) {
544
            Display::addFlash(
545
                Display::return_message(get_lang('GiveURL'), 'error')
546
            );
547
548
            return false;
549
        }
550
551
        if (empty($id) || empty($course_id)) {
552
            return false;
553
        }
554
555
        // Finding the old category_id.
556
        $sql = "SELECT * FROM $tbl_link
557
                WHERE c_id = $course_id AND id='".$id."'";
558
        $result = Database:: query($sql);
559
        $row = Database:: fetch_array($result);
560
        $category_id = $row['category_id'];
561
562
        if ($category_id != $values['category_id']) {
563
            $sql = "SELECT MAX(display_order)
564
                    FROM $tbl_link 
565
                    WHERE
566
                        c_id = $course_id AND
567
                        category_id='".intval($values['category_id'])."'";
568
            $result = Database:: query($sql);
569
            list($max_display_order) = Database:: fetch_row($result);
570
            $max_display_order++;
571
        } else {
572
            $max_display_order = $row['display_order'];
573
        }
574
        $params = [
575
            'url' => $values['url'],
576
            'title' => $values['title'],
577
            'description' => $values['description'],
578
            'category_id' => $values['category_id'],
579
            'display_order' => $max_display_order,
580
            'on_homepage' => $values['on_homepage'],
581
            'target' => $values['target'],
582
            'category_id' => $values['category_id'],
583
        ];
584
585
        Database::update(
586
            $tbl_link,
587
            $params,
588
            ['c_id = ? AND id = ?' => [$course_id, $id]]
589
        );
590
591
        // Update search enchine and its values table if enabled.
592
        if (api_get_setting('search_enabled') == 'true') {
593
            $course_int_id = api_get_course_int_id();
594
            $course_id = api_get_course_id();
595
            $link_title = Database:: escape_string($values['title']);
596
            $link_description = Database:: escape_string($values['description']);
597
598
            // Actually, it consists on delete terms from db,
599
            // insert new ones, create a new search engine document, and remove the old one.
600
            // Get search_did.
601
            $tbl_se_ref = Database::get_main_table(
602
                TABLE_MAIN_SEARCH_ENGINE_REF
603
            );
604
            $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
605
            $sql = sprintf(
606
                $sql,
607
                $tbl_se_ref,
608
                $course_id,
609
                TOOL_LINK,
610
                $id
611
            );
612
            $res = Database:: query($sql);
613
614
            if (Database:: num_rows($res) > 0) {
615
                require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
616
617
                $se_ref = Database:: fetch_array($res);
618
                $specific_fields = get_specific_field_list();
619
                $ic_slide = new IndexableChunk();
620
621
                $all_specific_terms = '';
622
                foreach ($specific_fields as $specific_field) {
623
                    delete_all_specific_field_value(
624
                        $course_id,
625
                        $specific_field['id'],
626
                        TOOL_LINK,
627
                        $id
628
                    );
629
                    if (isset($_REQUEST[$specific_field['code']])) {
630
                        $sterms = trim(
631
                            $_REQUEST[$specific_field['code']]
632
                        );
633
                        if (!empty($sterms)) {
634
                            $all_specific_terms .= ' '.$sterms;
635
                            $sterms = explode(',', $sterms);
636
                            foreach ($sterms as $sterm) {
637
                                $ic_slide->addTerm(
638
                                    trim($sterm),
639
                                    $specific_field['code']
640
                                );
641
                                add_specific_field_value(
642
                                    $specific_field['id'],
643
                                    $course_id,
644
                                    TOOL_LINK,
645
                                    $id,
646
                                    $sterm
647
                                );
648
                            }
649
                        }
650
                    }
651
                }
652
653
                // Build the chunk to index.
654
                $ic_slide->addValue("title", $link_title);
655
                $ic_slide->addCourseId($course_id);
656
                $ic_slide->addToolId(TOOL_LINK);
657
                $xapian_data = [
658
                    SE_COURSE_ID => $course_id,
659
                    SE_TOOL_ID => TOOL_LINK,
660
                    SE_DATA => [
661
                        'link_id' => (int) $id,
662
                    ],
663
                    SE_USER => (int) api_get_user_id(),
664
                ];
665
                $ic_slide->xapian_data = serialize($xapian_data);
666
                $link_description = $all_specific_terms.' '.$link_description;
667
                $ic_slide->addValue('content', $link_description);
668
669
                // Add category name if set.
670
                if (isset($categoryId) && $categoryId > 0) {
671
                    $table_link_category = Database::get_course_table(
672
                        TABLE_LINK_CATEGORY
673
                    );
674
                    $sql_cat = 'SELECT * FROM %s WHERE id=%d and c_id = %d LIMIT 1';
675
                    $sql_cat = sprintf(
676
                        $sql_cat,
677
                        $table_link_category,
678
                        $categoryId,
679
                        $course_int_id
680
                    );
681
                    $result = Database:: query($sql_cat);
682
                    if (Database:: num_rows($result) == 1) {
683
                        $row = Database:: fetch_array($result);
684
                        $ic_slide->addValue(
685
                            'category',
686
                            $row['category_title']
687
                        );
688
                    }
689
                }
690
691
                $di = new ChamiloIndexer();
692
                isset($_POST['language']) ? $lang = Database:: escape_string($_POST['language']) : $lang = 'english';
693
                $di->connectDb(null, null, $lang);
694
                $di->remove_document($se_ref['search_did']);
695
                $di->addChunk($ic_slide);
696
697
                // Index and return search engine document id.
698
                $did = $di->index();
699
                if ($did) {
700
                    // Save it to db.
701
                    $sql = 'DELETE FROM %s
702
                            WHERE course_code=\'%s\'
703
                            AND tool_id=\'%s\'
704
                            AND ref_id_high_level=\'%s\'';
705
                    $sql = sprintf(
706
                        $sql,
707
                        $tbl_se_ref,
708
                        $course_id,
709
                        TOOL_LINK,
710
                        $id
711
                    );
712
                    Database:: query($sql);
713
                    $sql = 'INSERT INTO %s (c_id, id, course_code, tool_id, ref_id_high_level, search_did)
714
                            VALUES (NULL , \'%s\', \'%s\', %s, %s)';
715
                    $sql = sprintf(
716
                        $sql,
717
                        $tbl_se_ref,
718
                        $course_int_id,
719
                        $course_id,
720
                        TOOL_LINK,
721
                        $id,
722
                        $did
723
                    );
724
                    Database:: query($sql);
725
                }
726
            }
727
        }
728
729
        // "WHAT'S NEW" notification: update table last_toolEdit.
730
        api_item_property_update(
731
            $_course,
732
            TOOL_LINK,
733
            $id,
734
            'LinkUpdated',
735
            api_get_user_id()
736
        );
737
        Display::addFlash(Display::return_message(get_lang('LinkModded')));
738
    }
739
740
    /**
741
     * @param int   $id
742
     * @param array $values
743
     *
744
     * @return bool
745
     */
746
    public static function editCategory($id, $values)
747
    {
748
        $table = Database::get_course_table(TABLE_LINK_CATEGORY);
749
        $course_id = api_get_course_int_id();
750
        $id = intval($id);
751
752
        // This is used to put the modified info of the category-form into the database.
753
        $params = [
754
            'category_title' => $values['category_title'],
755
            'description' => $values['description'],
756
        ];
757
        Database::update(
758
            $table,
759
            $params,
760
            ['c_id = ? AND id = ?' => [$course_id, $id]]
761
        );
762
        Display::addFlash(Display::return_message(get_lang('CategoryModded')));
763
764
        return true;
765
    }
766
767
    /**
768
     * Changes the visibility of a link.
769
     *
770
     * @todo add the changing of the visibility of a course
771
     *
772
     * @author Patrick Cool <[email protected]>, Ghent University
773
     */
774
    public static function change_visibility_link($id, $scope)
775
    {
776
        $_course = api_get_course_info();
777
        $_user = api_get_user_info();
778
        if ($scope == TOOL_LINK) {
779
            api_item_property_update(
780
                $_course,
781
                TOOL_LINK,
782
                $id,
783
                $_GET['action'],
784
                $_user['user_id']
785
            );
786
            Display::addFlash(Display::return_message(get_lang('VisibilityChanged')));
787
        } elseif ($scope == TOOL_LINK_CATEGORY) {
788
            api_item_property_update(
789
                $_course,
790
                TOOL_LINK_CATEGORY,
791
                $id,
792
                $_GET['action'],
793
                $_user['user_id']
794
            );
795
            Display::addFlash(Display::return_message(get_lang('VisibilityChanged')));
796
        }
797
    }
798
799
    /**
800
     * Generate SQL to select all the links categories in the current course and
801
     * session.
802
     *
803
     * @param int  $courseId
804
     * @param int  $sessionId
805
     * @param bool $withBaseContent
806
     *
807
     * @return array
808
     */
809
    public static function getLinkCategories($courseId, $sessionId, $withBaseContent = true)
810
    {
811
        $tblLinkCategory = Database::get_course_table(TABLE_LINK_CATEGORY);
812
        $tblItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
813
        $courseId = intval($courseId);
814
        $courseInfo = api_get_course_info_by_id($courseId);
815
816
        // Condition for the session.
817
        $sessionCondition = api_get_session_condition(
818
            $sessionId,
819
            true,
820
            $withBaseContent,
821
            'linkcat.session_id'
822
        );
823
824
        // Getting links
825
        $sql = "SELECT *, linkcat.id
826
                FROM $tblLinkCategory linkcat
827
                WHERE
828
                    linkcat.c_id = $courseId
829
                    $sessionCondition
830
                ORDER BY linkcat.display_order DESC";
831
832
        $result = Database::query($sql);
833
        $categories = Database::store_result($result);
834
835
        $sql = "SELECT *, linkcat.id
836
                FROM $tblLinkCategory linkcat
837
                INNER JOIN $tblItemProperty ip
838
                ON (linkcat.id = ip.ref AND linkcat.c_id = ip.c_id)
839
                WHERE
840
                    ip.tool = '".TOOL_LINK_CATEGORY."' AND
841
                    (ip.visibility = '0' OR ip.visibility = '1')
842
                    $sessionCondition AND
843
                    linkcat.c_id = ".$courseId."
844
                ORDER BY linkcat.display_order DESC";
845
846
        $result = Database::query($sql);
847
848
        $categoryInItemProperty = [];
849
        if (Database::num_rows($result)) {
850
            while ($row = Database::fetch_array($result, 'ASSOC')) {
851
                $categoryInItemProperty[$row['id']] = $row;
852
            }
853
        }
854
855
        foreach ($categories as &$category) {
856
            if (!isset($categoryInItemProperty[$category['id']])) {
857
                api_item_property_update(
858
                    $courseInfo,
859
                    TOOL_LINK_CATEGORY,
860
                    $category['id'],
861
                    'LinkCategoryAdded',
862
                    api_get_user_id()
863
                );
864
                //api_set_default_visibility($category['id'], TOOL_LINK_CATEGORY);
865
            }
866
        }
867
868
        $sql = "SELECT DISTINCT linkcat.*, visibility
869
                FROM $tblLinkCategory linkcat
870
                INNER JOIN $tblItemProperty ip
871
                ON (linkcat.id = ip.ref AND linkcat.c_id = ip.c_id)
872
                WHERE
873
                    ip.tool = '".TOOL_LINK_CATEGORY."' AND
874
                    (ip.visibility = '0' OR ip.visibility = '1')
875
                    $sessionCondition AND
876
                    linkcat.c_id = ".$courseId."
877
                ORDER BY linkcat.display_order DESC
878
                ";
879
        $result = Database::query($sql);
880
881
        return Database::store_result($result, 'ASSOC');
882
    }
883
884
    /**
885
     * @param int $categoryId
886
     * @param $courseId
887
     * @param $sessionId
888
     * @param bool $withBaseContent
889
     *
890
     * @return array
891
     */
892
    public static function getLinksPerCategory(
893
        $categoryId,
894
        $courseId,
895
        $sessionId,
896
        $withBaseContent = true
897
    ) {
898
        $tbl_link = Database::get_course_table(TABLE_LINK);
899
        $TABLE_ITEM_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
900
        $courseId = (int) $courseId;
901
        $sessionId = (int) $sessionId;
902
        $categoryId = (int) $categoryId;
903
904
        // Condition for the session.
905
        $condition_session = api_get_session_condition(
906
            $sessionId,
907
            true,
908
            false,
909
            'ip.session_id'
910
        );
911
912
        if (!empty($sessionId)) {
913
            $conditionBaseSession = api_get_session_condition(
914
                0,
915
                true,
916
                $withBaseContent,
917
                'ip.session_id'
918
            );
919
            $condition = " AND 
920
                (
921
                    (ip.visibility = '1' $conditionBaseSession) OR
922
                     
923
                    (
924
                        (ip.visibility = '0' OR ip.visibility = '1')
925
                        $condition_session
926
                    )
927
                )
928
            ";
929
        } else {
930
            $condition = api_get_session_condition(
931
                0,
932
                true,
933
                false,
934
                'ip.session_id'
935
            );
936
            $condition .= " AND (ip.visibility = '0' OR ip.visibility = '1') $condition ";
937
        }
938
939
        $sql = "SELECT 
940
                    link.id,
941
                    ip.session_id,
942
                    link.session_id link_session_id,
943
                    url,
944
                    category_id,
945
                    visibility,
946
                    description,
947
                    title,
948
                    target,
949
                    on_homepage
950
                FROM $tbl_link link
951
                INNER JOIN $TABLE_ITEM_PROPERTY ip
952
                ON (link.id = ip.ref AND link.c_id = ip.c_id)
953
                WHERE
954
                    ip.tool = '".TOOL_LINK."' AND
955
                    link.category_id = '".$categoryId."' AND
956
                    link.c_id = $courseId AND
957
                    ip.c_id = $courseId
958
                    $condition
959
                ORDER BY link.display_order ASC, ip.session_id DESC";
960
961
        $result = Database:: query($sql);
962
963
        return Database::store_result($result);
964
    }
965
966
    /**
967
     * Displays all the links of a given category.
968
     *
969
     * @author Patrick Cool <[email protected]>, Ghent University
970
     * @author Julio Montoya
971
     *
972
     * @param $catid
973
     * @param int $courseId
974
     * @param int $session_id
975
     *
976
     * @return string
977
     */
978
    public static function showLinksPerCategory($catid, $courseId, $session_id)
979
    {
980
        global $token;
981
        $_user = api_get_user_info();
982
        $catid = intval($catid);
983
984
        $links = self::getLinksPerCategory($catid, $courseId, $session_id);
985
        $content = '';
986
        $numberOfLinks = count($links);
987
988
        if (!empty($links)) {
989
            $content .= '<div class="link list-group">';
990
            $i = 1;
991
            $linksAdded = [];
992
            foreach ($links as $myrow) {
993
                $linkId = $myrow['id'];
994
995
                if (in_array($linkId, $linksAdded)) {
996
                    continue;
997
                }
998
999
                $linksAdded[] = $linkId;
1000
                $categoryId = $myrow['category_id'];
1001
1002
                // Validation when belongs to a session.
1003
                $session_img = api_get_session_image(
1004
                    $myrow['link_session_id'],
1005
                    $_user['status']
1006
                );
1007
1008
                $toolbar = '';
1009
                $link_validator = '';
1010
                if (api_is_allowed_to_edit(null, true)) {
1011
                    $toolbar .= Display::toolbarButton(
1012
                        '',
1013
                        'javascript:void(0);',
1014
                        'check-circle-o',
1015
                        'default btn-sm',
1016
                        [
1017
                            'onclick' => "check_url('".$linkId."', '".addslashes($myrow['url'])."');",
1018
                            'title' => get_lang('CheckURL'),
1019
                        ]
1020
                    );
1021
1022
                    $link_validator .= Display::span(
1023
                        '',
1024
                        [
1025
                        'id' => 'url_id_'.$linkId,
1026
                        'class' => 'check-link',
1027
                        ]
1028
                    );
1029
1030
                    if ($session_id == $myrow['link_session_id']) {
1031
                        $url = api_get_self().'?'.api_get_cidreq().'&action=editlink&id='.$linkId;
1032
                        $title = get_lang('Edit');
1033
                        $toolbar .= Display::toolbarButton(
1034
                            '',
1035
                            $url,
1036
                            'pencil',
1037
                            'default btn-sm',
1038
                            [
1039
                                'title' => $title,
1040
                            ]
1041
                        );
1042
                    }
1043
1044
                    $urlVisibility = api_get_self().'?'.api_get_cidreq().
1045
                            '&sec_token='.$token.
1046
                            '&id='.$linkId.
1047
                            '&scope=link&category_id='.$categoryId;
1048
1049
                    switch ($myrow['visibility']) {
1050
                        case '1':
1051
                            $urlVisibility .= '&action=invisible';
1052
                            $title = get_lang('MakeInvisible');
1053
                            $toolbar .= Display::toolbarButton(
1054
                                '',
1055
                                $urlVisibility,
1056
                                'eye',
1057
                                'default btn-sm',
1058
                                [
1059
                                    'title' => $title,
1060
                                ]
1061
                            );
1062
                            break;
1063
                        case '0':
1064
                            $urlVisibility .= '&action=visible';
1065
                            $title = get_lang('MakeVisible');
1066
                            $toolbar .= Display::toolbarButton(
1067
                                '',
1068
                                $urlVisibility,
1069
                                'eye-slash',
1070
                                'primary btn-sm',
1071
                                [
1072
                                    'title' => $title,
1073
                                ]
1074
                            );
1075
                            break;
1076
                    }
1077
1078
                    if ($session_id == $myrow['link_session_id']) {
1079
                        $moveLinkParams = [
1080
                            'id' => $linkId,
1081
                            'scope' => 'category',
1082
                            'category_id' => $categoryId,
1083
                            'action' => 'move_link_up',
1084
                        ];
1085
1086
                        $toolbar .= Display::toolbarButton(
1087
                            get_lang('MoveUp'),
1088
                            api_get_self().'?'.api_get_cidreq().'&'.http_build_query($moveLinkParams),
1089
                            'level-up',
1090
                            'default',
1091
                            ['class' => 'btn-sm '.($i === 1 ? 'disabled' : '')],
1092
                            false
1093
                        );
1094
1095
                        $moveLinkParams['action'] = 'move_link_down';
1096
                        $toolbar .= Display::toolbarButton(
1097
                            get_lang('MoveDown'),
1098
                            api_get_self().'?'.api_get_cidreq().'&'.http_build_query($moveLinkParams),
1099
                            'level-down',
1100
                            'default',
1101
                            ['class' => 'btn-sm '.($i === $numberOfLinks ? 'disabled' : '')],
1102
                            false
1103
                        );
1104
1105
                        $url .= api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=deletelink&id='.$linkId.'&category_id='.$categoryId;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $url does not seem to be defined for all execution paths leading up to this point.
Loading history...
1106
                        $event = "javascript: if(!confirm('".get_lang('LinkDelconfirm')."'))return false;";
1107
                        $title = get_lang('Delete');
1108
1109
                        $toolbar .= Display::toolbarButton(
1110
                            '',
1111
                            $url,
1112
                            'trash',
1113
                            'default btn-sm',
1114
                            [
1115
                                'onclick' => $event,
1116
                                'title' => $title,
1117
                            ]
1118
                        );
1119
                    }
1120
                }
1121
1122
                $showLink = false;
1123
                $titleClass = '';
1124
                if ($myrow['visibility'] == '1') {
1125
                    $showLink = true;
1126
                } else {
1127
                    if (api_is_allowed_to_edit(null, true)) {
1128
                        $showLink = true;
1129
                        $titleClass = 'text-muted';
1130
                    }
1131
                }
1132
1133
                if ($showLink) {
1134
                    $iconLink = Display::return_icon(
1135
                        'url.png',
1136
                        get_lang('Link'),
1137
                        null,
1138
                        ICON_SIZE_SMALL
1139
                    );
1140
                    $url = api_get_path(WEB_CODE_PATH).'link/link_goto.php?'.api_get_cidreq().'&link_id='.$linkId.'&link_url='.urlencode($myrow['url']);
1141
                    $content .= '<div class="list-group-item">';
1142
                    $content .= '<div class="pull-right"><div class="btn-group">'.$toolbar.'</div></div>';
1143
                    $content .= '<h4 class="list-group-item-heading">';
1144
                    $content .= $iconLink;
1145
                    $content .= Display::tag(
1146
                        'a',
1147
                        Security::remove_XSS($myrow['title']),
1148
                        [
1149
                            'href' => $url,
1150
                            'target' => $myrow['target'],
1151
                            'class' => $titleClass,
1152
                        ]
1153
                    );
1154
                    $content .= $link_validator;
1155
                    $content .= $session_img;
1156
                    $content .= '</h4>';
1157
                    $content .= '<p class="list-group-item-text">'.$myrow['description'].'</p>';
1158
                    $content .= '</div>';
1159
                }
1160
                $i++;
1161
            }
1162
            $content .= '</div>';
1163
        }
1164
1165
        return $content;
1166
    }
1167
1168
    /**
1169
     * Displays the edit, delete and move icons.
1170
     *
1171
     * @param int   Category ID
1172
     * @param int $currentCategory
1173
     * @param int $countCategories
1174
     *
1175
     * @return string
1176
     *
1177
     * @author Patrick Cool <[email protected]>, Ghent University
1178
     */
1179
    public static function showCategoryAdminTools($category, $currentCategory, $countCategories)
1180
    {
1181
        $categoryId = $category['id'];
1182
        $token = null;
1183
        $tools = '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=editcategory&id='.$categoryId.'&category_id='.$categoryId.'" title='.get_lang('Modify').'">'.
1184
            Display:: return_icon(
1185
                'edit.png',
1186
                get_lang('Modify'),
1187
                [],
1188
                ICON_SIZE_SMALL
1189
            ).'</a>';
1190
1191
        // DISPLAY MOVE UP COMMAND only if it is not the top link.
1192
        if ($currentCategory != 0) {
1193
            $tools .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=up&up='.$categoryId.'&category_id='.$categoryId.'" title="'.get_lang('Up').'">'.
1194
                Display:: return_icon(
1195
                    'up.png',
1196
                    get_lang('Up'),
1197
                    [],
1198
                    ICON_SIZE_SMALL
1199
                ).'</a>';
1200
        } else {
1201
            $tools .= Display:: return_icon(
1202
                'up_na.png',
1203
                get_lang('Up'),
1204
                [],
1205
                ICON_SIZE_SMALL
1206
            ).'</a>';
1207
        }
1208
1209
        // DISPLAY MOVE DOWN COMMAND only if it is not the bottom link.
1210
        if ($currentCategory < $countCategories - 1) {
1211
            $tools .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=down&down='.$categoryId.'&category_id='.$categoryId.'">'.
1212
                Display:: return_icon(
1213
                    'down.png',
1214
                    get_lang('Down'),
1215
                    [],
1216
                    ICON_SIZE_SMALL
1217
                ).'</a>';
1218
        } else {
1219
            $tools .= Display:: return_icon(
1220
                'down_na.png',
1221
                get_lang('Down'),
1222
                [],
1223
                ICON_SIZE_SMALL
1224
            ).'</a>';
1225
        }
1226
1227
        $tools .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=deletecategory&id='.$categoryId."&category_id=$categoryId\"
1228
            onclick=\"javascript: if(!confirm('".get_lang('CategoryDelconfirm')."')) return false;\">".
1229
            Display:: return_icon(
1230
                'delete.png',
1231
                get_lang('Delete'),
1232
                [],
1233
                ICON_SIZE_SMALL
1234
            ).'</a>';
1235
1236
        return $tools;
1237
    }
1238
1239
    /**
1240
     * move a link or a linkcategory up or down.
1241
     *
1242
     * @param   int Category ID
1243
     * @param   int Course ID
1244
     * @param   int Session ID
1245
     *
1246
     * @author Patrick Cool <[email protected]>, Ghent University
1247
     *
1248
     * @todo support sessions
1249
     */
1250
    public static function movecatlink($action, $catlinkid, $courseId = null, $sessionId = null)
1251
    {
1252
        $tbl_categories = Database::get_course_table(TABLE_LINK_CATEGORY);
1253
1254
        if (is_null($courseId)) {
1255
            $courseId = api_get_course_int_id();
1256
        }
1257
        $courseId = intval($courseId);
1258
        if (is_null($sessionId)) {
1259
            $sessionId = api_get_session_id();
1260
        }
1261
        $sessionId = intval($sessionId);
1262
        $thiscatlinkId = intval($catlinkid);
1263
1264
        if ($action == 'down') {
1265
            $sortDirection = 'DESC';
1266
        }
1267
1268
        if ($action == 'up') {
1269
            $sortDirection = 'ASC';
1270
        }
1271
1272
        $movetable = $tbl_categories;
1273
1274
        if (!empty($sortDirection)) {
1275
            if (!in_array(trim(strtoupper($sortDirection)), ['ASC', 'DESC'])) {
1276
                $sortDirection = 'ASC';
1277
            }
1278
1279
            $sql = "SELECT id, display_order FROM $movetable
1280
                    WHERE c_id = $courseId
1281
                    ORDER BY display_order $sortDirection";
1282
            $linkresult = Database:: query($sql);
1283
            $thislinkOrder = 1;
1284
            while ($sortrow = Database:: fetch_array($linkresult)) {
1285
                // STEP 2 : FOUND THE NEXT LINK ID AND ORDER, COMMIT SWAP
1286
                // This part seems unlogic, but it isn't . We first look for the current link with the querystring ID
1287
                // and we know the next iteration of the while loop is the next one. These should be swapped.
1288
                if (isset($thislinkFound) && $thislinkFound) {
1289
                    $nextlinkId = $sortrow['id'];
1290
                    $nextlinkOrder = $sortrow['display_order'];
1291
1292
                    Database:: query(
1293
                        "UPDATE ".$movetable."
1294
                        SET display_order = '$nextlinkOrder'
1295
                        WHERE c_id = $courseId  AND id =  '$thiscatlinkId'"
1296
                    );
1297
                    Database:: query(
1298
                        "UPDATE ".$movetable."
1299
                        SET display_order = '$thislinkOrder'
1300
                        WHERE c_id = $courseId  AND id =  '$nextlinkId'"
1301
                    );
1302
1303
                    break;
1304
                }
1305
                if ($sortrow['id'] == $thiscatlinkId) {
1306
                    $thislinkOrder = $sortrow['display_order'];
1307
                    $thislinkFound = true;
1308
                }
1309
            }
1310
        }
1311
1312
        Display::addFlash(Display::return_message(get_lang('LinkMoved')));
1313
    }
1314
1315
    /**
1316
     * CSV file import functions.
1317
     *
1318
     * @author René Haentjens , Ghent University
1319
     *
1320
     * @param string $catname
1321
     *
1322
     * @return int
1323
     */
1324
    public static function get_cat($catname)
1325
    {
1326
        // Get category id (existing or make new).
1327
        $tbl_categories = Database::get_course_table(TABLE_LINK_CATEGORY);
1328
        $course_id = api_get_course_int_id();
1329
1330
        $result = Database:: query(
1331
            "SELECT id FROM ".$tbl_categories."
1332
            WHERE c_id = $course_id AND category_title='".Database::escape_string($catname)."'"
1333
        );
1334
        if (Database:: num_rows($result) >= 1 && ($row = Database:: fetch_array($result))) {
1335
            return $row['id']; // Several categories with same name: take the first.
1336
        }
1337
1338
        $result = Database:: query(
1339
            "SELECT MAX(display_order) FROM ".$tbl_categories." WHERE c_id = $course_id "
1340
        );
1341
        list($max_order) = Database:: fetch_row($result);
1342
1343
        $params = [
1344
            'c_id' => $course_id,
1345
            'category_title' => $catname,
1346
            'description' => '',
1347
            'display_order' => $max_order + 1,
1348
        ];
1349
        $id = Database::insert($tbl_categories, $params);
1350
1351
        return $id;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $id could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
1352
    }
1353
1354
    /**
1355
     * CSV file import functions.
1356
     *
1357
     * @author René Haentjens , Ghent University
1358
     *
1359
     * @param string $url
1360
     * @param string $title
1361
     * @param string $description
1362
     * @param string $on_homepage
1363
     * @param string $hidden
1364
     */
1365
    public static function put_link($url, $cat, $title, $description, $on_homepage, $hidden)
1366
    {
1367
        $_course = api_get_course_info();
1368
        $_user = api_get_user_info();
1369
1370
        $tbl_link = Database::get_course_table(TABLE_LINK);
1371
        $course_id = api_get_course_int_id();
1372
1373
        $urleq = "url='".Database:: escape_string($url)."'";
1374
        $cateq = "category_id=".intval($cat);
1375
1376
        $result = Database:: query(
1377
            "
1378
            SELECT id FROM $tbl_link
1379
            WHERE c_id = $course_id AND ".$urleq.' AND '.$cateq
1380
        );
1381
1382
        if (Database:: num_rows($result) >= 1 && ($row = Database:: fetch_array($result))) {
1383
            $sql = "UPDATE $tbl_link SET 
1384
                        title = '".Database:: escape_string($title)."', 
1385
                        description = '".Database:: escape_string($description)."'
1386
                    WHERE c_id = $course_id AND  id='".Database:: escape_string($row['id'])."'";
1387
            Database:: query($sql);
1388
1389
            $ipu = 'LinkUpdated';
1390
            $rv = 1; // 1 = upd
1391
        } else {
1392
            // Add new link
1393
            $result = Database:: query(
1394
                "SELECT MAX(display_order) FROM  $tbl_link
1395
                WHERE c_id = $course_id AND category_id='".intval($cat)."'"
1396
            );
1397
            list($max_order) = Database:: fetch_row($result);
1398
1399
            Database:: query(
1400
                "INSERT INTO $tbl_link (c_id, url, title, description, category_id, display_order, on_homepage)
1401
                VALUES (".api_get_course_int_id().",
1402
                '".Database:: escape_string($url)."',
1403
                '".Database:: escape_string($title)."',
1404
                '".Database:: escape_string($description)."',
1405
                '".intval($cat)."','".(intval($max_order) + 1)."',
1406
                '".intval($on_homepage).
1407
                "')"
1408
            );
1409
1410
            $id = Database:: insert_id();
1411
            $ipu = 'LinkAdded';
1412
            $rv = 2; // 2 = new
1413
        }
1414
1415
        api_item_property_update(
1416
            $_course,
1417
            TOOL_LINK,
1418
            $id,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id does not seem to be defined for all execution paths leading up to this point.
Loading history...
1419
            $ipu,
1420
            $_user['user_id']
1421
        );
1422
1423
        if ($hidden && $ipu == 'LinkAdded') {
1424
            api_item_property_update(
1425
                $_course,
1426
                TOOL_LINK,
1427
                $id,
1428
                'invisible',
1429
                $_user['user_id']
1430
            );
1431
        }
1432
1433
        return $rv;
1434
    }
1435
1436
    /**
1437
     * CSV file import functions.
1438
     *
1439
     * @author René Haentjens , Ghent University
1440
     */
1441
    public static function import_link($linkdata)
1442
    {
1443
        // url, category_id, title, description, ...
1444
        // Field names used in the uploaded file
1445
        $known_fields = [
1446
            'url',
1447
            'category',
1448
            'title',
1449
            'description',
1450
            'on_homepage',
1451
            'hidden',
1452
        ];
1453
1454
        $hide_fields = [
1455
            'kw',
1456
            'kwd',
1457
            'kwds',
1458
            'keyword',
1459
            'keywords',
1460
        ];
1461
1462
        // All other fields are added to description, as "name:value".
1463
        // Only one hide_field is assumed to be present, <> is removed from value.
1464
        if (!($url = trim($linkdata['url'])) || !($title = trim($linkdata['title']))) {
1465
            return 0; // 0 = fail
1466
        }
1467
1468
        $cat = ($catname = trim($linkdata['category'])) ? self::get_cat($catname) : 0;
1469
1470
        $regs = []; // Will be passed to ereg()
1471
        $d = '';
1472
        foreach ($linkdata as $key => $value) {
1473
            if (!in_array($key, $known_fields)) {
1474
                if (in_array($key, $hide_fields) && ereg(
0 ignored issues
show
Deprecated Code introduced by
The function ereg() has been deprecated: 5.3.0 Use preg_match() instead ( Ignorable by Annotation )

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

1474
                if (in_array($key, $hide_fields) && /** @scrutinizer ignore-deprecated */ ereg(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1475
                        '^<?([^>]*)>?$',
1476
                        $value,
1477
                        $regs
1478
                    )
1479
                ) { // possibly in <...>
1480
                    if (($kwlist = trim($regs[1])) != '') {
1481
                        $kw = '<i kw="'.htmlspecialchars($kwlist).'">';
1482
                    } else {
1483
                        $kw = '';
1484
                    }
1485
                    // i.e. assume only one of the $hide_fields will be present
1486
                    // and if found, hide the value as expando property of an <i> tag
1487
                } elseif (trim($value)) {
1488
                    $d .= ', '.$key.':'.$value;
1489
                }
1490
            }
1491
        }
1492
        if (!empty($d)) {
1493
            $d = substr($d, 2).' - ';
1494
        }
1495
1496
        return self::put_link(
1497
            $url,
1498
            $cat,
1499
            $title,
1500
            $kw.ereg_replace(
0 ignored issues
show
Deprecated Code introduced by
The function ereg_replace() has been deprecated: 5.3.0 Use preg_replace() instead ( Ignorable by Annotation )

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

1500
            $kw./** @scrutinizer ignore-deprecated */ ereg_replace(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
Comprehensibility Best Practice introduced by
The variable $kw does not seem to be defined for all execution paths leading up to this point.
Loading history...
1501
                '\[((/?(b|big|i|small|sub|sup|u))|br/)\]',
1502
                '<\\1>',
1503
                htmlspecialchars($d.$linkdata['description'])
1504
            ).($kw ? '</i>' : ''),
1505
            $linkdata['on_homepage'] ? '1' : '0',
1506
            $linkdata['hidden'] ? '1' : '0'
1507
        );
1508
        // i.e. allow some BBcode tags, e.g. [b]...[/b]
1509
    }
1510
1511
    /**
1512
     * This function checks if the url is a vimeo link.
1513
     *
1514
     * @author Julio Montoya
1515
     *
1516
     * @version 1.0
1517
     */
1518
    public static function isVimeoLink($url)
1519
    {
1520
        $isLink = strrpos($url, "vimeo.com");
1521
1522
        return $isLink;
1523
    }
1524
1525
    /**
1526
     * Get vimeo id from URL.
1527
     *
1528
     * @param string $url
1529
     *
1530
     * @return bool|mixed
1531
     */
1532
    public static function getVimeoLinkId($url)
1533
    {
1534
        $possibleUrls = [
1535
            'http://www.vimeo.com/',
1536
            'http://vimeo.com/',
1537
            'https://www.vimeo.com/',
1538
            'https://vimeo.com/',
1539
        ];
1540
        $url = str_replace($possibleUrls, '', $url);
1541
1542
        if (is_numeric($url)) {
1543
            return $url;
1544
        }
1545
1546
        return false;
1547
    }
1548
1549
    /**
1550
     * This function checks if the url is a youtube link.
1551
     *
1552
     * @author Jorge Frisancho
1553
     * @author Julio Montoya - Fixing code
1554
     *
1555
     * @version 1.0
1556
     */
1557
    public static function is_youtube_link($url)
1558
    {
1559
        $is_youtube_link = strrpos($url, "youtube") || strrpos(
1560
            $url,
1561
            "youtu.be"
1562
        );
1563
1564
        return $is_youtube_link;
1565
    }
1566
1567
    /**
1568
     * This function checks if the url is a PDF File link.
1569
     *
1570
     * @author Jorge Frisancho
1571
     * @author Alex Aragón - Fixing code
1572
     *
1573
     * @version 1.0
1574
     */
1575
    public static function isPdfLink($url)
1576
    {
1577
        $isPdfLink = strrpos(strtolower($url), '.pdf');
1578
1579
        return $isPdfLink;
1580
    }
1581
1582
    /**
1583
     * Get youtube id from an URL.
1584
     *
1585
     * @param string $url
1586
     *
1587
     * @return string
1588
     */
1589
    public static function get_youtube_video_id($url)
1590
    {
1591
        // This is the length of YouTube's video IDs
1592
        $len = 11;
1593
1594
        // The ID string starts after "v=", which is usually right after
1595
        // "youtube.com/watch?" in the URL
1596
        $pos = strpos($url, "v=");
1597
        $id = '';
1598
1599
        //If false try other options
1600
        if ($pos === false) {
1601
            $url_parsed = parse_url($url);
1602
1603
            //Youtube shortener
1604
            //http://youtu.be/ID
1605
            $pos = strpos($url, "youtu.be");
1606
1607
            if ($pos == false) {
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...
1608
                $id = '';
1609
            } else {
1610
                return substr($url_parsed['path'], 1);
1611
            }
1612
1613
            //if empty try the youtube.com/embed/ID
1614
            if (empty($id)) {
1615
                $pos = strpos($url, "embed");
1616
                if ($pos === false) {
1617
                    return '';
1618
                } else {
1619
                    return substr($url_parsed['path'], 7);
1620
                }
1621
            }
1622
        } else {
1623
            // Offset the start location to match the beginning of the ID string
1624
            $pos += 2;
1625
            // Get the ID string and return it
1626
            $id = substr($url, $pos, $len);
1627
1628
            return $id;
1629
        }
1630
    }
1631
1632
    /**
1633
     * @param int    $course_id
1634
     * @param int    $session_id
1635
     * @param int    $categoryId
1636
     * @param string $show
1637
     * @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...
1638
     */
1639
    public static function listLinksAndCategories(
1640
        $course_id,
1641
        $session_id,
1642
        $categoryId,
1643
        $show = 'none',
1644
        $token = null
1645
    ) {
1646
        $tbl_link = Database::get_course_table(TABLE_LINK);
1647
        $tblCIP = Database::get_course_table(TABLE_ITEM_PROPERTY);
1648
        $categoryId = intval($categoryId);
1649
1650
        /*	Action Links */
1651
        echo '<div class="actions">';
1652
        if (api_is_allowed_to_edit(null, true)) {
1653
            echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=addlink&category_id='.$categoryId.'">'.
1654
                Display::return_icon('new_link.png', get_lang('LinkAdd'), '', ICON_SIZE_MEDIUM).'</a>';
1655
            echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=addcategory&category_id='.$categoryId.'">'.
1656
                Display::return_icon('new_folder.png', get_lang('CategoryAdd'), '', ICON_SIZE_MEDIUM).'</a>';
1657
        }
1658
1659
        $categories = self::getLinkCategories($course_id, $session_id);
1660
        $countCategories = count($categories);
1661
        if (!empty($countCategories)) {
1662
            echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=list&show=none">';
1663
            echo Display::return_icon('forum_listview.png', get_lang('FlatView'), '', ICON_SIZE_MEDIUM).' </a>';
1664
1665
            echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=list&show=all">';
1666
            echo Display::return_icon('forum_nestedview.png', get_lang('NestedView'), '', ICON_SIZE_MEDIUM).'</a>';
1667
        }
1668
        echo '</div>';
1669
        $linksPerCategory = self::showLinksPerCategory(0, $course_id, $session_id);
1670
1671
        if (empty($countCategories)) {
1672
            echo $linksPerCategory;
1673
        } else {
1674
            if (!empty($linksPerCategory)) {
1675
                echo Display::panel($linksPerCategory, get_lang('NoCategory'));
1676
            }
1677
        }
1678
1679
        $counter = 0;
1680
        foreach ($categories as $myrow) {
1681
            // Student don't see invisible categories.
1682
            if (!api_is_allowed_to_edit(null, true)) {
1683
                if ($myrow['visibility'] == 0) {
1684
                    continue;
1685
                }
1686
            }
1687
1688
            // Validation when belongs to a session
1689
            $showChildren = $categoryId == $myrow['id'] || $show == 'all';
1690
            $myrow['description'] = $myrow['description'];
1691
1692
            $strVisibility = '';
1693
            $visibilityClass = null;
1694
            if ($myrow['visibility'] == '1') {
1695
                $strVisibility = '<a href="link.php?'.api_get_cidreq().'&sec_token='.$token.'&action=invisible&id='.$myrow['id'].'&scope='.TOOL_LINK_CATEGORY.'" title="'.get_lang('Hide').'">'.
1696
                    Display::return_icon('visible.png', get_lang('Hide'), [], ICON_SIZE_SMALL).'</a>';
1697
            } elseif ($myrow['visibility'] == '0') {
1698
                $visibilityClass = 'text-muted';
1699
                $strVisibility = ' <a href="link.php?'.api_get_cidreq().'&sec_token='.$token.'&action=visible&id='.$myrow['id'].'&scope='.TOOL_LINK_CATEGORY.'" title="'.get_lang('Show').'">'.
1700
                    Display::return_icon('invisible.png', get_lang('Show'), [], ICON_SIZE_SMALL).'</a>';
1701
            }
1702
1703
            $header = '';
1704
            if ($showChildren) {
1705
                $header .= '<a class="'.$visibilityClass.'" href="'.api_get_self().'?'.api_get_cidreq().'&category_id=">';
1706
                $header .= Display::return_icon('forum_nestedview.png');
1707
            } else {
1708
                $header .= '<a class="'.$visibilityClass.'" href="'.api_get_self().'?'.api_get_cidreq().'&category_id='.$myrow['id'].'">';
1709
                $header .= Display::return_icon('forum_listview.png');
1710
            }
1711
1712
            $header .= Security::remove_XSS($myrow['category_title']).'</a>';
1713
            $header .= '<div class="pull-right">';
1714
1715
            if (api_is_allowed_to_edit(null, true)) {
1716
                if ($session_id == $myrow['session_id']) {
1717
                    $header .= $strVisibility;
1718
                    $header .= self::showCategoryAdminTools($myrow, $counter, count($categories));
1719
                } else {
1720
                    $header .= get_lang('EditionNotAvailableFromSession');
1721
                }
1722
            }
1723
1724
            $childrenContent = '';
1725
            if ($showChildren) {
1726
                $childrenContent = self::showLinksPerCategory(
1727
                    $myrow['id'],
1728
                    api_get_course_int_id(),
1729
                    api_get_session_id()
1730
                );
1731
            }
1732
1733
            echo Display::panel($myrow['description'].$childrenContent, $header);
1734
1735
            $counter++;
1736
        }
1737
    }
1738
1739
    /**
1740
     * @param int    $linkId
1741
     * @param string $action
1742
     * @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...
1743
     *
1744
     * @return FormValidator
1745
     */
1746
    public static function getLinkForm($linkId, $action, $token = null)
1747
    {
1748
        $course_id = api_get_course_int_id();
1749
        $session_id = api_get_session_id();
1750
        $linkInfo = self::getLinkInfo($linkId);
1751
        $categoryId = isset($linkInfo['category_id']) ? $linkInfo['category_id'] : '';
1752
        $lpId = isset($_GET['lp_id']) ? Security::remove_XSS($_GET['lp_id']) : null;
1753
1754
        $form = new FormValidator(
1755
            'link',
1756
            'post',
1757
            api_get_self().'?action='.$action.
1758
            '&category_id='.$categoryId.
1759
            '&'.api_get_cidreq().
1760
            '&id='.$linkId.
1761
            '&sec_token='.$token
1762
        );
1763
1764
        if ($action == 'addlink') {
1765
            $form->addHeader(get_lang('LinkAdd'));
1766
        } else {
1767
            $form->addHeader(get_lang('LinkMod'));
1768
        }
1769
1770
        $target_link = '_blank';
1771
        $title = '';
1772
        $category = '';
1773
        $onhomepage = '';
1774
        $description = '';
1775
1776
        if (!empty($linkInfo)) {
1777
            $urllink = $linkInfo['url'];
1778
            $title = $linkInfo['title'];
1779
            $description = $linkInfo['description'];
1780
            $category = $linkInfo['category_id'];
1781
            if ($linkInfo['on_homepage'] != 0) {
1782
                $onhomepage = 1;
1783
            }
1784
            $target_link = $linkInfo['target'];
1785
        }
1786
1787
        $form->addHidden('id', $linkId);
1788
        $form->addText('url', 'URL');
1789
        $form->addRule('url', get_lang('GiveURL'), 'url');
1790
        $form->addText('title', get_lang('LinkName'));
1791
        $form->addTextarea('description', get_lang('Description'));
1792
1793
        $resultcategories = self::getLinkCategories($course_id, $session_id);
1794
        $options = ['0' => '--'];
1795
        if (!empty($resultcategories)) {
1796
            foreach ($resultcategories as $myrow) {
1797
                $options[$myrow['id']] = $myrow['category_title'];
1798
            }
1799
        }
1800
1801
        $form->addSelect('category_id', get_lang('Category'), $options);
1802
        $form->addCheckBox('on_homepage', null, get_lang('OnHomepage'));
1803
1804
        $targets = [
1805
            '_self' => get_lang('LinkOpenSelf'),
1806
            '_blank' => get_lang('LinkOpenBlank'),
1807
            '_parent' => get_lang('LinkOpenParent'),
1808
            '_top' => get_lang('LinkOpenTop'),
1809
        ];
1810
1811
        $form->addSelect(
1812
            'target',
1813
            [
1814
                get_lang('LinkTarget'),
1815
                get_lang('AddTargetOfLinkOnHomepage'),
1816
            ],
1817
            $targets
1818
        );
1819
1820
        $defaults = [
1821
            'url' => empty($urllink) ? 'http://' : Security::remove_XSS($urllink),
1822
            'title' => Security::remove_XSS($title),
1823
            'category_id' => $category,
1824
            'on_homepage' => $onhomepage,
1825
            'description' => $description,
1826
            'target' => $target_link,
1827
        ];
1828
1829
        if (api_get_setting('search_enabled') == 'true') {
1830
            require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
1831
            $specific_fields = get_specific_field_list();
1832
            $form->addCheckBox('index_document', get_lang('SearchFeatureDoIndexLink'), get_lang('Yes'));
1833
1834
            foreach ($specific_fields as $specific_field) {
1835
                $default_values = '';
1836
                if ($action == 'editlink') {
1837
                    $filter = [
1838
                        'field_id' => $specific_field['id'],
1839
                        'ref_id' => intval($_GET['id']),
1840
                        'tool_id' => '\''.TOOL_LINK.'\'',
1841
                    ];
1842
                    $values = get_specific_field_values_list($filter, ['value']);
1843
                    if (!empty($values)) {
1844
                        $arr_str_values = [];
1845
                        foreach ($values as $value) {
1846
                            $arr_str_values[] = $value['value'];
1847
                        }
1848
                        $default_values = implode(', ', $arr_str_values);
1849
                    }
1850
                }
1851
                $form->addText($specific_field['name'], $specific_field['code']);
1852
                $defaults[$specific_field['name']] = $default_values;
1853
            }
1854
        }
1855
1856
        $skillList = Skill::addSkillsToForm($form, ITEM_TYPE_LINK, $linkId);
1857
        $form->addHidden('lp_id', $lpId);
1858
        $form->addButtonSave(get_lang('SaveLink'), 'submitLink');
1859
        $defaults['skills'] = array_keys($skillList);
1860
        $form->setDefaults($defaults);
1861
1862
        return $form;
1863
    }
1864
1865
    /**
1866
     * @param int    $id
1867
     * @param string $action
1868
     *
1869
     * @return FormValidator
1870
     */
1871
    public static function getCategoryForm($id, $action)
1872
    {
1873
        $form = new FormValidator(
1874
            'category',
1875
            'post',
1876
            api_get_self().'?action='.$action.'&'.api_get_cidreq()
1877
        );
1878
1879
        $defaults = [];
1880
        if ($action == 'addcategory') {
1881
            $form->addHeader(get_lang('CategoryAdd'));
1882
            $my_cat_title = get_lang('CategoryAdd');
1883
        } else {
1884
            $form->addHeader(get_lang('CategoryMod'));
1885
            $my_cat_title = get_lang('CategoryMod');
1886
            $defaults = self::getCategory($id);
1887
        }
1888
        $form->addHidden('id', $id);
1889
        $form->addText('category_title', get_lang('CategoryName'));
1890
        $form->addTextarea('description', get_lang('Description'));
1891
        $form->addButtonSave($my_cat_title, 'submitCategory');
1892
        $form->setDefaults($defaults);
1893
1894
        return $form;
1895
    }
1896
1897
    /**
1898
     * @param int $id
1899
     *
1900
     * @return array
1901
     */
1902
    public static function getCategory($id)
1903
    {
1904
        $table = Database::get_course_table(TABLE_LINK_CATEGORY);
1905
        $id = intval($id);
1906
        $courseId = api_get_course_int_id();
1907
1908
        if (empty($id) || empty($courseId)) {
1909
            return [];
1910
        }
1911
        $sql = "SELECT * FROM $table 
1912
                WHERE id = $id AND c_id = $courseId";
1913
        $result = Database::query($sql);
1914
        $category = Database::fetch_array($result, 'ASSOC');
1915
1916
        return $category;
1917
    }
1918
1919
    /**
1920
     * Move a link up in its category.
1921
     *
1922
     * @param int $id
1923
     *
1924
     * @return bool
1925
     */
1926
    public static function moveLinkUp($id)
1927
    {
1928
        return self::moveLinkDisplayOrder($id, 'ASC');
1929
    }
1930
1931
    /**
1932
     * Move a link down in its category.
1933
     *
1934
     * @param int $id
1935
     *
1936
     * @return bool
1937
     */
1938
    public static function moveLinkDown($id)
1939
    {
1940
        return self::moveLinkDisplayOrder($id, 'DESC');
1941
    }
1942
1943
    /**
1944
     * @param string $url
1945
     *
1946
     * @return bool
1947
     */
1948
    public static function checkUrl($url)
1949
    {
1950
        // Check if curl is available.
1951
        if (!in_array('curl', get_loaded_extensions())) {
1952
            return false;
1953
        }
1954
1955
        // set URL and other appropriate options
1956
        $defaults = [
1957
            CURLOPT_URL => $url,
1958
            CURLOPT_FOLLOWLOCATION => true, // follow redirects accept youtube.com
1959
            CURLOPT_HEADER => 0,
1960
            CURLOPT_RETURNTRANSFER => true,
1961
            CURLOPT_TIMEOUT => 4,
1962
        ];
1963
1964
        $proxySettings = api_get_configuration_value('proxy_settings');
1965
1966
        if (!empty($proxySettings) &&
1967
            isset($proxySettings['curl_setopt_array'])
1968
        ) {
1969
            $defaults[CURLOPT_PROXY] = $proxySettings['curl_setopt_array']['CURLOPT_PROXY'];
1970
            $defaults[CURLOPT_PROXYPORT] = $proxySettings['curl_setopt_array']['CURLOPT_PROXYPORT'];
1971
        }
1972
1973
        // Create a new cURL resource
1974
        $ch = curl_init();
1975
        curl_setopt_array($ch, $defaults);
1976
1977
        // grab URL and pass it to the browser
1978
        ob_start();
1979
        $result = curl_exec($ch);
1980
        ob_get_clean();
1981
1982
        // close cURL resource, and free up system resources
1983
        curl_close($ch);
1984
1985
        return $result;
1986
    }
1987
1988
    /**
1989
     * Move a link inside its category (display_order field).
1990
     *
1991
     * @param int    $id        The link ID
1992
     * @param string $direction The direction to sort the links
1993
     *
1994
     * @return bool
1995
     */
1996
    private static function moveLinkDisplayOrder($id, $direction)
1997
    {
1998
        $em = Database::getManager();
1999
        /** @var CLink $link */
2000
        $link = $em->find('ChamiloCourseBundle:CLink', $id);
2001
2002
        if (!$link) {
0 ignored issues
show
introduced by
$link is of type Chamilo\CourseBundle\Entity\CLink, thus it always evaluated to true.
Loading history...
2003
            return false;
2004
        }
2005
2006
        $compareLinks = $em
2007
            ->getRepository('ChamiloCourseBundle:CLink')
2008
            ->findBy(
2009
                [
2010
                    'cId' => $link->getCId(),
2011
                    'categoryId' => $link->getCategoryId(),
2012
                ],
2013
                ['displayOrder' => $direction]
2014
            );
2015
2016
        /** @var CLink $prevLink */
2017
        $prevLink = null;
2018
2019
        /** @var CLink $compareLink */
2020
        foreach ($compareLinks as $compareLink) {
2021
            if ($compareLink->getId() !== $link->getId()) {
2022
                $prevLink = $compareLink;
2023
2024
                continue;
2025
            }
2026
2027
            if (!$prevLink) {
2028
                return false;
2029
            }
2030
2031
            $newPrevLinkDisplayOrder = $link->getDisplayOrder();
2032
            $newLinkDisplayOrder = $prevLink->getDisplayOrder();
2033
2034
            $link->setDisplayOrder($newLinkDisplayOrder);
2035
            $prevLink->setDisplayOrder($newPrevLinkDisplayOrder);
2036
2037
            $em->merge($prevLink);
2038
            $em->merge($link);
2039
            break;
2040
        }
2041
2042
        $em->flush();
2043
2044
        return true;
2045
    }
2046
}
2047