Passed
Pull Request — 1.10.x (#1110)
by
unknown
44:14
created

learnpath::prerequisites_match()   C

Complexity

Conditions 11
Paths 96

Size

Total Lines 55
Code Lines 33

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 55
rs 6.6153
cc 11
eloc 33
nc 96
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CourseBundle\Entity\CLpCategory;
5
use ChamiloSession as Session;
6
7
/**
8
 * Class learnpath
9
 * This class defines the parent attributes and methods for Chamilo learnpaths
10
 * and SCORM learnpaths. It is used by the scorm class.
11
 *
12
 * @package chamilo.learnpath
13
 * @author	Yannick Warnier <[email protected]>
14
 * @author	Julio Montoya   <[email protected]> Several improvements and fixes
15
 */
16
class learnpath
17
{
18
    public $attempt = 0; // The number for the current ID view.
19
    public $cc; // Course (code) this learnpath is located in. @todo change name for something more comprensible ...
20
    public $current; // Id of the current item the user is viewing.
21
    public $current_score; // The score of the current item.
22
    public $current_time_start; // The time the user loaded this resource (this does not mean he can see it yet).
23
    public $current_time_stop; // The time the user closed this resource.
24
    public $default_status = 'not attempted';
25
    public $encoding = 'UTF-8';
26
    public $error = '';
27
    public $extra_information = ''; // This string can be used by proprietary SCORM contents to store data about the current learnpath.
28
    public $force_commit = false; // For SCORM only - if set to true, will send a scorm LMSCommit() request on each LMSSetValue().
29
    public $index; // The index of the active learnpath_item in $ordered_items array.
30
    public $items = array();
31
    public $last; // item_id of last item viewed in the learning path.
32
    public $last_item_seen = 0; // In case we have already come in this learnpath, reuse the last item seen if authorized.
33
    public $license; // Which license this course has been given - not used yet on 20060522.
34
    public $lp_id; // DB ID for this learnpath.
35
    public $lp_view_id; // DB ID for lp_view
36
    public $log_file; // File where to log learnpath API msg.
37
    public $maker; // Which maker has conceived the content (ENI, Articulate, ...).
38
    public $message = '';
39
    public $mode = 'embedded'; // Holds the video display mode (fullscreen or embedded).
40
    public $name; // Learnpath name (they generally have one).
41
    public $ordered_items = array(); // List of the learnpath items in the order they are to be read.
42
    public $path = ''; // Path inside the scorm directory (if scorm).
43
    public $theme; // The current theme of the learning path.
44
    public $preview_image; // The current image of the learning path.
45
46
    // Tells if all the items of the learnpath can be tried again. Defaults to "no" (=1).
47
    public $prevent_reinit = 1;
48
49
    // Describes the mode of progress bar display.
50
    public $seriousgame_mode = 0;
51
    public $progress_bar_mode = '%';
52
53
    // Percentage progress as saved in the db.
54
    public $progress_db = '0';
55
    public $proximity; // Wether the content is distant or local or unknown.
56
    public $refs_list = array (); //list of items by ref => db_id. Used only for prerequisites match.
57
    // !!!This array (refs_list) is built differently depending on the nature of the LP.
58
    // If SCORM, uses ref, if Chamilo, uses id to keep a unique value.
59
    public $type; //type of learnpath. Could be 'dokeos', 'scorm', 'scorm2004', 'aicc', ...
60
    // TODO: Check if this type variable is useful here (instead of just in the controller script).
61
    public $user_id; //ID of the user that is viewing/using the course
62
    public $update_queue = array();
63
    public $scorm_debug = 0;
64
    public $arrMenu = array(); // Array for the menu items.
65
    public $debug = 0; // Logging level.
66
    public $lp_session_id = 0;
67
    public $lp_view_session_id = 0; // The specific view might be bound to a session.
68
    public $prerequisite = 0;
69
    public $use_max_score = 1; // 1 or 0
70
    public $subscribeUsers = 0; // Subscribe users or not
71
    public $created_on      = '';
72
    public $modified_on     = '';
73
    public $publicated_on   = '';
74
    public $expired_on      = '';
75
    public $ref = null;
76
    public $course_int_id;
77
    public $course_info = array();
78
    public $categoryId;
79
80
    /**
81
     * Constructor.
82
     * Needs a database handler, a course code and a learnpath id from the database.
83
     * Also builds the list of items into $this->items.
84
     * @param	string	$course Course code
85
     * @param	integer	$lp_id
86
     * @param	integer	$user_id
87
     * @return mixed True on success, false on error
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
88
     */
89
    public function __construct($course, $lp_id, $user_id)
90
    {
91
        $this->encoding = api_get_system_encoding();
92 View Code Duplication
        if ($this->debug > 0) {
93
            error_log('New LP - In learnpath::__construct('.$course.','.$lp_id.','.$user_id.')', 0);
94
        }
95
        if (empty($course)) {
96
            $this->error = 'Course code is empty';
97
            return false;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
98
        } else {
99
            $course_info = api_get_course_info($course);
100
            if (!empty($course_info)) {
101
                $this->cc = $course_info['code'];
102
                $this->course_info = $course_info;
103
                $course_id = $course_info['real_id'];
104
            } else {
105
                $this->error = 'Course code does not exist in database.';
106
                return false;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
107
            }
108
        }
109
110
        $this->set_course_int_id($course_id);
111
112
        // Check learnpath ID.
113
        if (empty($lp_id)) {
114
            $this->error = 'Learnpath ID is empty';
115
            return false;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
116
        } else {
117
            // TODO: Make it flexible to use any course_code (still using env course code here).
118
            $lp_table = Database::get_course_table(TABLE_LP_MAIN);
119
            $lp_id = intval($lp_id);
120
            $sql = "SELECT * FROM $lp_table
121
                    WHERE id = '$lp_id' AND c_id = $course_id";
122
            if ($this->debug > 2) {
123
                error_log('New LP - learnpath::__construct() '.__LINE__.' - Querying lp: '.$sql, 0);
124
            }
125
            $res = Database::query($sql);
126
127
            if (Database::num_rows($res) > 0) {
128
                $this->lp_id = $lp_id;
129
                $row = Database::fetch_array($res);
130
                $this->type = $row['lp_type'];
131
                $this->name = stripslashes($row['name']);
132
                $this->proximity = $row['content_local'];
133
                $this->theme = $row['theme'];
134
                $this->maker = $row['content_maker'];
135
                $this->prevent_reinit = $row['prevent_reinit'];
136
                $this->seriousgame_mode = $row['seriousgame_mode'];
137
                $this->license = $row['content_license'];
138
                $this->scorm_debug = $row['debug'];
139
                $this->js_lib = $row['js_lib'];
140
                $this->path = $row['path'];
141
                $this->preview_image = $row['preview_image'];
142
                $this->author = $row['author'];
143
                $this->hide_toc_frame = $row['hide_toc_frame'];
144
                $this->lp_session_id = $row['session_id'];
145
                $this->use_max_score = $row['use_max_score'];
146
                $this->subscribeUsers = $row['subscribe_users'];
147
                $this->created_on = $row['created_on'];
148
                $this->modified_on = $row['modified_on'];
149
                $this->ref = $row['ref'];
150
                $this->categoryId = $row['category_id'];
151
152
                if ($row['publicated_on'] != '0000-00-00 00:00:00') {
153
                    $this->publicated_on = $row['publicated_on'];
154
                }
155
156
                if ($row['expired_on'] != '0000-00-00 00:00:00') {
157
                    $this->expired_on  = $row['expired_on'];
158
                }
159 View Code Duplication
                if ($this->type == 2) {
160
                    if ($row['force_commit'] == 1) {
161
                        $this->force_commit = true;
162
                    }
163
                }
164
                $this->mode = $row['default_view_mod'];
165
            } else {
166
                $this->error = 'Learnpath ID does not exist in database ('.$sql.')';
167
168
                return false;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
169
            }
170
        }
171
172
        // Check user ID.
173
        if (empty($user_id)) {
174
            $this->error = 'User ID is empty';
175
176
            return false;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
177
        } else {
178
            $user_info = api_get_user_info($user_id);
179
            if (!empty($user_info)) {
180
                $this->user_id = $user_info['user_id'];
181
            } else {
182
                $this->error = 'User ID does not exist in database ('.$sql.')';
183
184
                return false;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
185
            }
186
        }
187
188
        // End of variables checking.
189
        $session_id = api_get_session_id();
190
        //  Get the session condition for learning paths of the base + session.
191
        $session = api_get_session_condition($session_id);
192
        // Now get the latest attempt from this user on this LP, if available, otherwise create a new one.
193
        $lp_table = Database::get_course_table(TABLE_LP_VIEW);
194
195
        // Selecting by view_count descending allows to get the highest view_count first.
196
        $sql = "SELECT * FROM $lp_table
197
                WHERE c_id = $course_id AND lp_id = '$lp_id' AND user_id = '$user_id' $session
198
                ORDER BY view_count DESC";
199
        $res = Database::query($sql);
200
        if ($this->debug > 2) {
201
            error_log('New LP - learnpath::__construct() ' . __LINE__ . ' - querying lp_view: ' . $sql, 0);
202
        }
203
204
        if (Database :: num_rows($res) > 0) {
205
            if ($this->debug > 2) {
206
                error_log('New LP - learnpath::__construct() ' . __LINE__ . ' - Found previous view', 0);
207
            }
208
            $row = Database :: fetch_array($res);
209
            $this->attempt = $row['view_count'];
210
            $this->lp_view_id = $row['id'];
211
            $this->last_item_seen = $row['last_item'];
212
            $this->progress_db = $row['progress'];
213
            $this->lp_view_session_id = $row['session_id'];
214
        } else if (!api_is_invitee()) {
215
            if ($this->debug > 2) {
216
                error_log('New LP - learnpath::__construct() ' . __LINE__ . ' - NOT Found previous view', 0);
217
            }
218
            $this->attempt = 1;
219
            $params = [
220
                'c_id' => $course_id,
221
                'lp_id' => $lp_id,
222
                'user_id' => $user_id,
223
                'view_count' => 1,
224
                'session_id' => $session_id,
225
                'last_item' => 0
226
            ];
227
            Database::insert($lp_table, $params);
228
            $this->lp_view_id = Database::insert_id();
229
230
            if ($this->debug > 2) {
231
                error_log('New LP - learnpath::__construct() ' . __LINE__ . ' - inserting new lp_view: ' . $sql, 0);
232
            }
233
234
            $sql = "UPDATE $lp_table SET id = iid WHERE iid = ".$this->lp_view_id;
235
            Database::query($sql);
236
        }
237
238
        // Initialise items.
239
        $lp_item_table = Database::get_course_table(TABLE_LP_ITEM);
240
        $sql = "SELECT * FROM $lp_item_table
241
                WHERE c_id = $course_id AND lp_id = '".$this->lp_id."'
242
                ORDER BY parent_item_id, display_order";
243
        $res = Database::query($sql);
244
245
        if ($this->debug > 2) {
246
            error_log('New LP - learnpath::__construct() ' . __LINE__ . ' - query lp items: ' . $sql, 0);
247
            error_log('-- Start while--', 0);
248
        }
249
250
        $lp_item_id_list = array();
251
252
        while ($row = Database::fetch_array($res)) {
253
            $lp_item_id_list[] = $row['id'];
254
            switch ($this->type) {
255 View Code Duplication
                case 3: //aicc
256
                    $oItem = new aiccItem('db', $row['id'], $course_id);
257
                    if (is_object($oItem)) {
258
                        $my_item_id = $oItem->get_id();
259
                        $oItem->set_lp_view($this->lp_view_id, $course_id);
260
                        $oItem->set_prevent_reinit($this->prevent_reinit);
261
                        // Don't use reference here as the next loop will make the pointed object change.
262
                        $this->items[$my_item_id] = $oItem;
263
                        $this->refs_list[$oItem->ref] = $my_item_id;
264
                        if ($this->debug > 2) {
265
                            error_log(
266
                                'New LP - learnpath::__construct() - ' .
267
                                'aicc object with id ' . $my_item_id .
268
                                ' set in items[]',
269
                                0
270
                            );
271
                        }
272
                    }
273
                    break;
274 View Code Duplication
                case 2:
275
                    $oItem = new scormItem('db', $row['id'], $course_id);
276
                    if (is_object($oItem)) {
277
                        $my_item_id = $oItem->get_id();
278
                        $oItem->set_lp_view($this->lp_view_id, $course_id);
279
                        $oItem->set_prevent_reinit($this->prevent_reinit);
280
                        // Don't use reference here as the next loop will make the pointed object change.
281
282
                        $this->items[$my_item_id] = $oItem;
283
284
                        $this->refs_list[$oItem->ref] = $my_item_id;
285
                        if ($this->debug > 2) {
286
                            error_log('New LP - object with id ' . $my_item_id . ' set in items[]', 0);
287
                        }
288
                    }
289
                    break;
290
                case 1:
291
                default:
292
                    if ($this->debug > 2) {
293
                        error_log('New LP - learnpath::__construct() ' . __LINE__ . ' - calling learnpathItem', 0);
294
                    }
295
                    $oItem = new learnpathItem($row['id'], $user_id, $course_id, $row);
296
297
                    if ($this->debug > 2) {
298
                        error_log('New LP - learnpath::__construct() ' . __LINE__ . ' - end calling learnpathItem', 0);
299
                    }
300
                    if (is_object($oItem)) {
301
                        $my_item_id = $oItem->get_id();
302
                        //$oItem->set_lp_view($this->lp_view_id); // Moved down to when we are sure the item_view exists.
303
                        $oItem->set_prevent_reinit($this->prevent_reinit);
304
                        // Don't use reference here as the next loop will make the pointed object change.
305
                        $this->items[$my_item_id] = $oItem;
306
                        $this->refs_list[$my_item_id] = $my_item_id;
307 View Code Duplication
                        if ($this->debug > 2) {
308
                            error_log(
309
                                'New LP - learnpath::__construct() ' . __LINE__ .
310
                                ' - object with id ' . $my_item_id . ' set in items[]',
311
                                0);
312
                        }
313
                    }
314
                    break;
315
            }
316
317
            // Setting the object level with variable $this->items[$i][parent]
318
            foreach ($this->items as $itemLPObject) {
319
                $level = learnpath::get_level_for_item($this->items, $itemLPObject->db_id);
320
                $itemLPObject->level = $level;
321
            }
322
323
            // Setting the view in the item object.
324
            if (is_object($this->items[$row['id']])) {
325
                $this->items[$row['id']]->set_lp_view($this->lp_view_id, $course_id);
326
                if ($this->items[$row['id']]->get_type() == TOOL_HOTPOTATOES) {
327
                    $this->items[$row['id']]->current_start_time = 0;
328
                    $this->items[$row['id']]->current_stop_time	= 0;
329
                }
330
            }
331
        }
332
333
        if ($this->debug > 2) {
334
            error_log('New LP - learnpath::__construct() ' . __LINE__ . ' ----- end while ----', 0);
335
        }
336
337
        if (!empty($lp_item_id_list)) {
338
            $lp_item_id_list_to_string = implode("','", $lp_item_id_list);
339
            if (!empty($lp_item_id_list_to_string)) {
340
                // Get last viewing vars.
341
                $lp_item_view_table = Database:: get_course_table(
342
                    TABLE_LP_ITEM_VIEW
343
                );
344
                // This query should only return one or zero result.
345
                $sql = "SELECT lp_item_id, status
346
                        FROM $lp_item_view_table
347
                        WHERE
348
                            c_id = $course_id AND
349
                            lp_view_id = ".$this->lp_view_id." AND
350
                            lp_item_id IN ('".$lp_item_id_list_to_string."')
351
                        ORDER BY view_count DESC ";
352
353
                if ($this->debug > 2) {
354
                    error_log(
355
                        'New LP - learnpath::__construct() - Selecting item_views: '.$sql,
356
                        0
357
                    );
358
                }
359
360
                $status_list = array();
361
                $res = Database::query($sql);
362
                while ($row = Database:: fetch_array($res)) {
363
                    $status_list[$row['lp_item_id']] = $row['status'];
364
                }
365
366
                foreach ($lp_item_id_list as $item_id) {
367
                    if (isset($status_list[$item_id])) {
368
                        $status = $status_list[$item_id];
369
                        if (is_object($this->items[$item_id])) {
370
                            $this->items[$item_id]->set_status($status);
371
                            if (empty($status)) {
372
                                $this->items[$item_id]->set_status(
373
                                    $this->default_status
374
                                );
375
                            }
376
                        }
377
                    } else {
378
                        if (!api_is_invitee()) {
379
                            if (is_object($this->items[$item_id])) {
380
                                $this->items[$item_id]->set_status(
381
                                    $this->default_status
382
                                );
383
                            }
384
385
                            // Add that row to the lp_item_view table so that we have something to show in the stats page.
386
                            $sql = "INSERT INTO $lp_item_view_table (c_id, lp_item_id, lp_view_id, view_count, status, start_time, total_time, score)
387
                                    VALUES ($course_id, ".$item_id.",".$this->lp_view_id.", 1, 'not attempted', '".time()."', 0, 0)";
388
389
                            if ($this->debug > 2) {
390
                                error_log(
391
                                    'New LP - learnpath::__construct() '.__LINE__.' - Inserting blank item_view : '.$sql,
392
                                    0
393
                                );
394
                            }
395
                            $this->items[$item_id]->set_lp_view(
396
                                $this->lp_view_id,
397
                                $course_id
398
                            );
399
400
                            Database::query($sql);
401
                            $insertId = Database::insert_id();
402
403
                            $sql = "UPDATE $lp_item_view_table SET id = iid
404
                                    WHERE iid = $insertId";
405
                            Database::query($sql);
406
                        }
407
                    }
408
                }
409
            }
410
        }
411
412
        $this->ordered_items = self::get_flat_ordered_items_list(
0 ignored issues
show
Documentation Bug introduced by
It seems like self::get_flat_ordered_i...et_id(), 0, $course_id) can also be of type false. However, the property $ordered_items is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
413
            $this->get_id(),
414
            0,
415
            $course_id
416
        );
417
        $this->max_ordered_items = 0;
418
        foreach ($this->ordered_items as $index => $dummy) {
0 ignored issues
show
Bug introduced by
The expression $this->ordered_items of type false|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
419
            if ($index > $this->max_ordered_items && !empty($dummy)) {
420
                $this->max_ordered_items = $index;
421
            }
422
        }
423
        // TODO: Define the current item better.
424
        $this->first();
425
        if ($this->debug > 2) {
426
            error_log('New LP - learnpath::__construct() ' . __LINE__ . ' - End of learnpath constructor for learnpath ' . $this->get_id(), 0);
427
        }
428
        return true;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
429
    }
430
431
    /**
432
     * @return string
433
     */
434
    public function getCourseCode()
435
    {
436
        return $this->cc;
437
    }
438
439
    /**
440
     * @return int
441
     */
442
    public function get_course_int_id()
443
    {
444
        return isset($this->course_int_id) ? $this->course_int_id : api_get_course_int_id();
445
    }
446
447
    /**
448
     * @param $course_id
449
     * @return int
450
     */
451
    public function set_course_int_id($course_id)
452
    {
453
        return $this->course_int_id = intval($course_id);
454
    }
455
456
    /**
457
     * Get the depth level of LP item
458
     * @param $in_tab_items
459
     * @param $in_current_item_id
460
     * @return int
461
     */
462
    private static function get_level_for_item($in_tab_items, $in_current_item_id)
463
    {
464
        $parent_item_id = $in_tab_items[$in_current_item_id]->parent;
465
        if ($parent_item_id == 0) {
466
            return 0;
467
        } else {
468
            return learnpath::get_level_for_item($in_tab_items, $parent_item_id) + 1;
469
        }
470
    }
471
472
    /**
473
     * Function rewritten based on old_add_item() from Yannick Warnier.
474
     * Due the fact that users can decide where the item should come, I had to overlook this function and
475
     * I found it better to rewrite it. Old function is still available.
476
     * Added also the possibility to add a description.
477
     *
478
     * @param int $parent
479
     * @param int $previous
480
     * @param string $type
481
     * @param int  resource ID (ref)
482
     * @param string $title
483
     * @param string $description
484
     * @param int $prerequisites
485
     * @param int $max_time_allowed
486
     * @param int $userId
487
     *
488
     * @return int
489
     */
490
    public function add_item(
491
        $parent,
492
        $previous,
493
        $type = 'dokeos_chapter',
494
        $id,
495
        $title,
496
        $description,
497
        $prerequisites = 0,
498
        $max_time_allowed = 0,
499
        $userId = 0
500
    ) {
501
        $course_id = $this->course_info['real_id'];
502
        if ($this->debug > 0) {
503
            error_log('New LP - In learnpath::add_item(' . $parent . ',' . $previous . ',' . $type . ',' . $id . ',' . $title . ')', 0);
504
        }
505
        if (empty($course_id)) {
506
            // Sometimes Oogie doesn't catch the course info but sets $this->cc
507
            $this->course_info = api_get_course_info($this->cc);
508
            $course_id = $this->course_info['real_id'];
509
        }
510
        $userId = empty($userId) ? api_get_user_id() : $userId;
511
        $sessionId = api_get_session_id();
512
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
513
        $_course = $this->course_info;
514
        $parent = intval($parent);
515
        $previous = intval($previous);
516
        $id = intval($id);
517
        $max_time_allowed = htmlentities($max_time_allowed);
518
        if (empty($max_time_allowed)) {
519
            $max_time_allowed = 0;
520
        }
521
        $sql = "SELECT COUNT(id) AS num
522
                FROM $tbl_lp_item
523
                WHERE
524
                    c_id = $course_id AND
525
                    lp_id = " . $this->get_id() . " AND
526
                    parent_item_id = " . $parent;
527
528
        $res_count = Database::query($sql);
529
        $row = Database :: fetch_array($res_count);
530
        $num = $row['num'];
531
532
        if ($num > 0) {
533
            if ($previous == 0) {
534
                $sql = "SELECT id, next_item_id, display_order
535
                        FROM " . $tbl_lp_item . "
536
                        WHERE
537
                            c_id = $course_id AND
538
                            lp_id = " . $this->get_id() . " AND
539
                            parent_item_id = " . $parent . " AND
540
                            previous_item_id = 0 OR
541
                            previous_item_id=" . $parent;
542
                $result = Database::query($sql);
543
                $row = Database :: fetch_array($result);
544
545
                $tmp_previous = 0;
546
                $next = $row['id'];
547
                $display_order = 0;
548
            } else {
549
                $previous = (int) $previous;
550
                $sql = "SELECT id, previous_item_id, next_item_id, display_order
551
						FROM $tbl_lp_item
552
                        WHERE
553
                            c_id = $course_id AND
554
                            lp_id = " . $this->get_id() . " AND
555
                            id = " . $previous;
556
557
                $result = Database::query($sql);
558
                $row = Database:: fetch_array($result);
559
560
                $tmp_previous = $row['id'];
561
                $next = $row['next_item_id'];
562
                $display_order = $row['display_order'];
563
            }
564
        } else {
565
            $tmp_previous = 0;
566
            $next = 0;
567
            $display_order = 0;
568
        }
569
570
        $id = intval($id);
571
        $typeCleaned = Database::escape_string($type);
572
        if ($type == 'quiz') {
573
            $sql = 'SELECT SUM(ponderation)
574
                    FROM ' . Database :: get_course_table(TABLE_QUIZ_QUESTION) . ' as quiz_question
575
                    INNER JOIN  ' . Database :: get_course_table(TABLE_QUIZ_TEST_QUESTION) . ' as quiz_rel_question
576
                    ON
577
                        quiz_question.id = quiz_rel_question.question_id AND
578
                        quiz_question.c_id = quiz_rel_question.c_id
579
                    WHERE
580
                        quiz_rel_question.exercice_id = '.$id." AND
581
                        quiz_question.c_id = $course_id AND
582
                        quiz_rel_question.c_id = $course_id ";
583
            $rsQuiz = Database::query($sql);
584
            $max_score = Database :: result($rsQuiz, 0, 0);
585
586
            // Disabling the exercise if we add it inside a LP
587
            $exercise = new Exercise($course_id);
588
            $exercise->read($id);
589
            $exercise->disable();
590
            $exercise->save();
591
        } else {
592
            $max_score = 100;
593
        }
594
595
        $params = array(
596
            "c_id" => $course_id,
597
            "lp_id" => $this->get_id(),
598
            "item_type" => $typeCleaned,
599
            "ref" => '',
600
            "title" => $title,
601
            "description" => $description,
602
            "path" => $id,
603
            "max_score" => $max_score,
604
            "parent_item_id" => $parent,
605
            "previous_item_id" => $previous,
606
            "next_item_id" => intval($next),
607
            "display_order" => $display_order + 1,
608
            "prerequisite" => $prerequisites,
609
            "max_time_allowed" => $max_time_allowed,
610
            'min_score' => 0,
611
            'launch_data' => '',
612
        );
613
614
        if ($prerequisites != 0) {
615
            $params['prerequisite'] = $prerequisites;
616
        }
617
618
        $new_item_id = Database::insert($tbl_lp_item, $params);
619
620
        if ($this->debug > 2) {
621
            error_log('New LP - Inserting chapter: ' . $new_item_id, 0);
622
        }
623
624
        if ($new_item_id) {
625
626
            $sql = "UPDATE $tbl_lp_item SET id = iid WHERE iid = $new_item_id";
627
            Database::query($sql);
628
629
            // Update the item that should come after the new item.
630
            $sql = " UPDATE $tbl_lp_item SET
631
                        previous_item_id =  $new_item_id,
632
                        next_item_id = $new_item_id,
633
                        id = $new_item_id
634
                     WHERE iid = $new_item_id";
635
            Database::query($sql);
636
637
            // Update all the items after the new item.
638
            $sql = "UPDATE " . $tbl_lp_item . "
639
                        SET display_order = display_order + 1
640
                    WHERE
641
                        c_id = $course_id AND
642
                        lp_id = " . $this->get_id() . " AND
643
                        id <> " . $new_item_id . " AND
644
                        parent_item_id = " . $parent . " AND
645
                        display_order > " . $display_order;
646
            Database::query($sql);
647
648
            // Update the item that should come after the new item.
649
            $sql = "UPDATE " . $tbl_lp_item . "
650
                    SET ref = " . $new_item_id . "
651
                    WHERE c_id = $course_id AND id = " . $new_item_id;
652
            Database::query($sql);
653
654
            // Upload audio.
655
            if (!empty($_FILES['mp3']['name'])) {
656
                // Create the audio folder if it does not exist yet.
657
                $filepath = api_get_path(SYS_COURSE_PATH) . $_course['path'] . '/document/';
658
                if (!is_dir($filepath . 'audio')) {
659
                    mkdir($filepath . 'audio', api_get_permissions_for_new_directories());
660
                    $audio_id = add_document(
661
                        $_course,
662
                        '/audio',
663
                        'folder',
664
                        0,
665
                        'audio',
666
                        '',
667
                        0,
668
                        true,
669
                        null,
670
                        $sessionId,
671
                        $userId
672
                    );
673
                    api_item_property_update(
674
                        $_course,
675
                        TOOL_DOCUMENT,
676
                        $audio_id,
677
                        'FolderCreated',
678
                        $userId,
679
                        null,
680
                        null,
681
                        null,
682
                        null,
683
                        $sessionId
684
                    );
685
                    api_item_property_update(
686
                        $_course,
687
                        TOOL_DOCUMENT,
688
                        $audio_id,
689
                        'invisible',
690
                        $userId,
691
                        null,
692
                        null,
693
                        null,
694
                        null,
695
                        $sessionId
696
                    );
697
                }
698
699
                $file_path = handle_uploaded_document(
700
                    $_course,
701
                    $_FILES['mp3'],
702
                    api_get_path(SYS_COURSE_PATH) . $_course['path'] . '/document',
703
                    '/audio',
704
                    $userId,
705
                    '',
706
                    '',
707
                    '',
708
                    '',
709
                    false
710
                );
711
712
                // Getting the filename only.
713
                $file_components = explode('/', $file_path);
714
                $file = $file_components[count($file_components) - 1];
715
716
                // Store the mp3 file in the lp_item table.
717
                $sql = "UPDATE $tbl_lp_item SET
718
                            audio = '" . Database::escape_string($file) . "'
719
                        WHERE id = '" . intval($new_item_id) . "'";
720
                Database::query($sql);
721
            }
722
        }
723
724
        return $new_item_id;
725
    }
726
727
    /**
728
     * Static admin function allowing addition of a learnpath to a course.
729
     * @param	string	Course code
730
     * @param	string	Learnpath name
731
     * @param	string	Learnpath description string, if provided
732
     * @param	string	Type of learnpath (default = 'guess', others = 'dokeos', 'aicc',...)
733
     * @param	string	Type of files origin (default = 'zip', others = 'dir','web_dir',...)
734
     * @param	string	Zip file containing the learnpath or directory containing the learnpath
735
     * @return	integer	The new learnpath ID on success, 0 on failure
736
     */
737
    public static function add_lp(
738
        $courseCode,
739
        $name,
740
        $description = '',
741
        $learnpath = 'guess',
742
        $origin = 'zip',
743
        $zipname = '',
744
        $publicated_on = '',
745
        $expired_on = '',
746
        $categoryId = 0,
747
        $userId = 0
748
    ) {
749
        global $charset;
750
751
        if (!empty($courseCode)) {
752
            $courseInfo = api_get_course_info($courseCode);
753
            $course_id = $courseInfo['real_id'];
754
        } else {
755
            $course_id = api_get_course_int_id();
756
            $courseInfo = api_get_course_info();
757
        }
758
759
        $tbl_lp = Database :: get_course_table(TABLE_LP_MAIN);
760
        // Check course code exists.
761
        // Check lp_name doesn't exist, otherwise append something.
762
        $i = 0;
763
        $name = Database::escape_string($name);
764
        $categoryId = intval($categoryId);
765
766
        // Session id.
767
        $session_id = api_get_session_id();
768
769
        $userId = empty($userId) ? api_get_user_id() : $userId;
770
771
        $check_name = "SELECT * FROM $tbl_lp
772
                       WHERE c_id = $course_id AND name = '$name'";
773
774
        $res_name = Database::query($check_name);
775
776
        if ($publicated_on == '0000-00-00 00:00:00' || empty($publicated_on)) {
777
            //by default the publication date is the same that the creation date
778
            //The behaviour above was changed due BT#2800
779
            global $_custom;
780
            if (isset($_custom['lps_hidden_when_no_start_date']) && $_custom['lps_hidden_when_no_start_date']) {
781
                $publicated_on = '';
782
            } else {
783
                $publicated_on = api_get_utc_datetime();
784
            }
785
        } else {
786
            $publicated_on = Database::escape_string(api_get_utc_datetime($publicated_on));
787
        }
788
789
        if ($expired_on == '0000-00-00 00:00:00' || empty($expired_on)) {
790
            $expired_on = '';
791
        } else {
792
            $expired_on = Database::escape_string(api_get_utc_datetime($expired_on));
793
        }
794
795
        while (Database :: num_rows($res_name)) {
0 ignored issues
show
Bug introduced by
It seems like $res_name can be null; however, num_rows() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
796
            // There is already one such name, update the current one a bit.
797
            $i++;
798
            $name = $name . ' - ' . $i;
799
            $check_name = "SELECT * FROM $tbl_lp WHERE c_id = $course_id AND name = '$name'";
800
            $res_name = Database::query($check_name);
801
        }
802
        // New name does not exist yet; keep it.
803
        // Escape description.
804
        // Kevin: added htmlentities().
805
        $description = Database::escape_string(api_htmlentities($description, ENT_QUOTES, $charset));
806
        $type = 1;
807
        switch ($learnpath) {
808
            case 'guess':
809
                break;
810
            case 'dokeos':
811
            case 'chamilo':
812
                $type = 1;
813
                break;
814
            case 'aicc':
815
                break;
816
        }
817
818
        switch ($origin) {
819
            case 'zip':
820
                // Check zip name string. If empty, we are currently creating a new Chamilo learnpath.
821
                break;
822
            case 'manual':
823
            default:
824
                $get_max = "SELECT MAX(display_order) FROM $tbl_lp WHERE c_id = $course_id";
825
                $res_max = Database::query($get_max);
826
                if (Database :: num_rows($res_max) < 1) {
827
                    $dsp = 1;
828
                } else {
829
                    $row = Database :: fetch_array($res_max);
830
                    $dsp = $row[0] + 1;
831
                }
832
833
                $params = [
834
                    'c_id' => $course_id,
835
                    'lp_type' => $type,
836
                    'name' => $name,
837
                    'description' => $description,
838
                    'path' => '',
839
                    'default_view_mod' => 'embedded',
840
                    'default_encoding' => 'UTF-8',
841
                    'display_order' => $dsp,
842
                    'content_maker' => 'Chamilo',
843
                    'content_local' => 'local',
844
                    'js_lib' => '',
845
                    'session_id' => $session_id,
846
                    'created_on' => api_get_utc_datetime(),
847
                    'modified_on'  => api_get_utc_datetime(),
848
                    'publicated_on' => $publicated_on,
849
                    'expired_on' => $expired_on,
850
                    'category_id' => $categoryId,
851
                    'force_commit' => 0,
852
                    'content_license' => '',
853
                    'debug' => 0,
854
                    'theme' => '',
855
                    'preview_image' => '',
856
                    'author' => '',
857
                    'prerequisite' => 0,
858
                    'hide_toc_frame' => 0,
859
                    'seriousgame_mode' => 0,
860
                    'autolaunch' => 0,
861
                    'max_attempts' => 0,
862
                    'subscribe_users' => 0
863
                ];
864
865
                $id = Database::insert($tbl_lp, $params);
866
867 View Code Duplication
                if ($id > 0) {
868
                    $sql = "UPDATE $tbl_lp SET id = iid WHERE iid = $id";
869
                    Database::query($sql);
870
871
                    // Insert into item_property.
872
                    api_item_property_update(
873
                        $courseInfo,
874
                        TOOL_LEARNPATH,
875
                        $id,
876
                        'LearnpathAdded',
877
                        $userId
878
                    );
879
                    api_set_default_visibility($id, TOOL_LEARNPATH, 0, $courseInfo, $session_id, $userId);
880
                    return $id;
881
                }
882
                break;
883
        }
884
    }
885
886
    /**
887
     * Auto completes the parents of an item in case it's been completed or passed
888
     * @param	integer	$item Optional ID of the item from which to look for parents
889
     */
890
    public function autocomplete_parents($item)
891
    {
892
        $debug = $this->debug;
893
894
        if ($debug) {
895
            error_log('Learnpath::autocomplete_parents()', 0);
896
        }
897
898
        if (empty($item)) {
899
            $item = $this->current;
900
        }
901
902
        $currentItem = $this->getItem($item);
903
        if ($currentItem) {
904
            $parent_id = $currentItem->get_parent();
905
            $parent = $this->getItem($parent_id);
906
            if ($parent) {
907
                // if $item points to an object and there is a parent.
908
                if ($debug) {
909
                    error_log(
910
                        'Autocompleting parent of item ' . $item . ' "'.$currentItem->get_title().'" (item ' . $parent_id . ' "'.$parent->get_title().'") ',
911
                        0
912
                    );
913
                }
914
915
                // New experiment including failed and browsed in completed status.
916
                //$current_status = $currentItem->get_status();
917
                //if ($currentItem->is_done() || $current_status == 'browsed' || $current_status == 'failed') {
918
                // Fixes chapter auto complete
919
                if (true) {
0 ignored issues
show
Bug introduced by
Avoid IF statements that are always true or false
Loading history...
920
                    // If the current item is completed or passes or succeeded.
921
                    $updateParentStatus = true;
922
                    if ($debug) {
923
                        error_log('Status of current item is alright', 0);
924
                    }
925
926
                    foreach ($parent->get_children() as $childItemId) {
927
                        $childItem = $this->getItem($childItemId);
928
929
                        // If children was not set try to get the info
930
                        if (empty($childItem->db_item_view_id)) {
931
                            $childItem->set_lp_view($this->lp_view_id, $this->course_int_id);
932
                        }
933
934
                        // Check all his brothers (parent's children) for completion status.
935
                        if ($childItemId != $item) {
936
                            if ($debug) {
937
                                error_log(
938
                                    'Looking at brother #'.$childItemId . ' "' . $childItem->get_title() . '", status is ' . $childItem->get_status(),
939
                                    0
940
                                );
941
                            }
942
                            // Trying completing parents of failed and browsed items as well.
943
                            if ($childItem->status_is(
944
                                array(
945
                                    'completed',
946
                                    'passed',
947
                                    'succeeded',
948
                                    'browsed',
949
                                    'failed'
950
                                )
951
                            )
952
                            ) {
953
                                // Keep completion status to true.
954
                                continue;
955
                            } else {
956
                                if ($debug > 2) {
957
                                    error_log(
958
                                        'Found one incomplete child of parent #' . $parent_id . ': child #'.$childItemId . ' "' . $childItem->get_title() . '", is ' . $childItem->get_status().' db_item_view_id:#'.$childItem->db_item_view_id,
959
                                        0
960
                                    );
961
                                }
962
                                $updateParentStatus = false;
963
                                break;
964
                            }
965
                        }
966
                    }
967
968
                    if ($updateParentStatus) {
969
                        // If all the children were completed:
970
                        $parent->set_status('completed');
971
                        $parent->save(false, $this->prerequisites_match($parent->get_id()));
972
                        // Force the status to "completed"
973
                        //$this->update_queue[$parent->get_id()] = $parent->get_status();
974
                        $this->update_queue[$parent->get_id()] = 'completed';
975
                        if ($debug) {
976
                            error_log(
977
                                'Added parent #'.$parent->get_id().' "'.$parent->get_title().'" to update queue status: completed '.
978
                                print_r($this->update_queue, 1),
979
                                0
980
                            );
981
                        }
982
                        // Recursive call.
983
                        $this->autocomplete_parents($parent->get_id());
984
                    }
985
                }
986
            } else {
987
                if ($debug) {
988
                    error_log("Parent #$parent_id does not exists");
989
                }
990
            }
991
        } else {
992
            if ($debug) {
993
                error_log("#$item is an item that doesn't have parents");
994
            }
995
        }
996
    }
997
998
    /**
999
     * Auto saves the current results into the database for the whole learnpath
1000
     */
1001
    public function autosave()
1002
    {
1003
        if ($this->debug > 0) {
1004
            error_log('New LP - In learnpath::autosave()', 0);
1005
        }
1006
        // TODO: Add save operations for the learnpath itself.
1007
    }
1008
1009
    /**
1010
     * Closes the current resource
1011
     *
1012
     * Stops the timer
1013
     * Saves into the database if required
1014
     * Clears the current resource data from this object
1015
     * @return	boolean	True on success, false on failure
1016
     */
1017
    public function close()
1018
    {
1019
        if ($this->debug > 0) {
1020
            error_log('New LP - In learnpath::close()', 0);
1021
        }
1022
        if (empty ($this->lp_id)) {
1023
            $this->error = 'Trying to close this learnpath but no ID is set';
1024
            return false;
1025
        }
1026
        $this->current_time_stop = time();
1027
        $this->ordered_items = array();
1028
        $this->index = 0;
1029
        unset ($this->lp_id);
1030
        //unset other stuff
1031
        return true;
1032
    }
1033
1034
    /**
1035
     * Static admin function allowing removal of a learnpath
1036
     * @param	array $courseInfo
1037
     * @param	integer	Learnpath ID
1038
     * @param	string	Whether to delete data or keep it (default: 'keep', others: 'remove')
1039
     * @return	boolean	True on success, false on failure (might change that to return number of elements deleted)
1040
     */
1041
    public function delete($courseInfo = null, $id = null, $delete = 'keep')
1042
    {
1043
        $course_id = api_get_course_int_id();
1044
        if (!empty($courseInfo)) {
1045
            $course_id = isset($courseInfo['real_id']) ? $courseInfo['real_id'] : $course_id;
1046
        }
1047
1048
        // TODO: Implement a way of getting this to work when the current object is not set.
1049
        // In clear: implement this in the item class as well (abstract class) and use the given ID in queries.
1050
        // If an ID is specifically given and the current LP is not the same, prevent delete.
1051
        if (!empty ($id) && ($id != $this->lp_id)) {
1052
            return false;
1053
        }
1054
1055
        $lp = Database:: get_course_table(TABLE_LP_MAIN);
1056
        $lp_item = Database:: get_course_table(TABLE_LP_ITEM);
1057
        $lp_view = Database:: get_course_table(TABLE_LP_VIEW);
1058
        $lp_item_view = Database:: get_course_table(TABLE_LP_ITEM_VIEW);
1059
1060
        // Delete lp item id.
1061
        foreach ($this->items as $id => $dummy) {
1062
            $sql = "DELETE FROM $lp_item_view
1063
                    WHERE c_id = $course_id AND lp_item_id = '" . $id . "'";
1064
            Database::query($sql);
1065
        }
1066
1067
        // Proposed by Christophe (nickname: clefevre)
1068
        $sql = "DELETE FROM $lp_item WHERE c_id = ".$course_id." AND lp_id = " . $this->lp_id;
1069
        Database::query($sql);
1070
1071
        $sql = "DELETE FROM $lp_view WHERE c_id = ".$course_id." AND lp_id = " . $this->lp_id;
1072
        Database::query($sql);
1073
1074
        self::toggle_publish($this->lp_id, 'i');
1075
1076
        if ($this->type == 2 || $this->type == 3) {
1077
            // This is a scorm learning path, delete the files as well.
1078
            $sql = "SELECT path FROM $lp
1079
                    WHERE c_id = ".$course_id." AND id = " . $this->lp_id;
1080
            $res = Database::query($sql);
1081
            if (Database :: num_rows($res) > 0) {
1082
                $row = Database :: fetch_array($res);
1083
                $path = $row['path'];
1084
                $sql = "SELECT id FROM $lp
1085
                        WHERE c_id = ".$course_id." AND path = '$path' AND id != " . $this->lp_id;
1086
                $res = Database::query($sql);
1087
                if (Database :: num_rows($res) > 0) { // Another learning path uses this directory, so don't delete it.
1088
                    if ($this->debug > 2) {
1089
                        error_log('New LP - In learnpath::delete(), found other LP using path ' . $path . ', keeping directory', 0);
1090
                    }
1091
                } else {
1092
                    // No other LP uses that directory, delete it.
1093
                    $course_rel_dir = api_get_course_path() . '/scorm/'; // scorm dir web path starting from /courses
1094
                    $course_scorm_dir = api_get_path(SYS_COURSE_PATH) . $course_rel_dir; // The absolute system path for this course.
1095
                    if ($delete == 'remove' && is_dir($course_scorm_dir . $path) and !empty ($course_scorm_dir)) {
1096
                        if ($this->debug > 2) {
1097
                            error_log('New LP - In learnpath::delete(), found SCORM, deleting directory: ' . $course_scorm_dir . $path, 0);
1098
                        }
1099
                        // Proposed by Christophe (clefevre).
1100
                        if (strcmp(substr($path, -2), "/.") == 0) {
1101
                            $path = substr($path, 0, -1); // Remove "." at the end.
1102
                        }
1103
                        //exec('rm -rf ' . $course_scorm_dir . $path); // See Bug #5208, this is not OS-portable way.
1104
                        rmdirr($course_scorm_dir . $path);
1105
                    }
1106
                }
1107
            }
1108
        }
1109
1110
        $tbl_tool = Database :: get_course_table(TABLE_TOOL_LIST);
1111
        $link = 'newscorm/lp_controller.php?action=view&lp_id='.$this->lp_id;
1112
        // Delete tools
1113
        $sql = "DELETE FROM $tbl_tool
1114
                WHERE c_id = ".$course_id." AND (link LIKE '$link%' AND image='scormbuilder.gif')";
1115
        Database::query($sql);
1116
1117
        $sql = "DELETE FROM $lp WHERE c_id = ".$course_id." AND id = " . $this->lp_id;
1118
        Database::query($sql);
1119
        // Updates the display order of all lps.
1120
        $this->update_display_order();
1121
1122
        api_item_property_update(
1123
            api_get_course_info(),
1124
            TOOL_LEARNPATH,
1125
            $this->lp_id,
1126
            'delete',
1127
            api_get_user_id()
1128
        );
1129
1130
        $link_info = GradebookUtils::is_resource_in_course_gradebook(api_get_course_id(), 4 , $id, api_get_session_id());
1131
        if ($link_info !== false) {
1132
            GradebookUtils::remove_resource_from_course_gradebook($link_info['id']);
1133
        }
1134
1135
        if (api_get_setting('search_enabled') == 'true') {
1136
            require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
1137
            delete_all_values_for_item($this->cc, TOOL_LEARNPATH, $this->lp_id);
1138
        }
1139
    }
1140
1141
    /**
1142
     * Removes all the children of one item - dangerous!
1143
     * @param	integer	$id Element ID of which children have to be removed
1144
     * @return	integer	Total number of children removed
1145
     */
1146
    public function delete_children_items($id)
1147
    {
1148
        $course_id = $this->course_info['real_id'];
1149
        if ($this->debug > 0) {
1150
            error_log('New LP - In learnpath::delete_children_items(' . $id . ')', 0);
1151
        }
1152
        $num = 0;
1153
        if (empty ($id) || $id != strval(intval($id))) {
1154
            return false;
1155
        }
1156
        $lp_item = Database :: get_course_table(TABLE_LP_ITEM);
1157
        $sql = "SELECT * FROM $lp_item WHERE c_id = ".$course_id." AND parent_item_id = $id";
1158
        $res = Database::query($sql);
1159
        while ($row = Database :: fetch_array($res)) {
1160
            $num += $this->delete_children_items($row['id']);
1161
            $sql_del = "DELETE FROM $lp_item WHERE c_id = ".$course_id." AND id = " . $row['id'];
1162
            Database::query($sql_del);
1163
            $num++;
1164
        }
1165
        return $num;
1166
    }
1167
1168
    /**
1169
     * Removes an item from the current learnpath
1170
     * @param	integer	$id Elem ID (0 if first)
1171
     * @param	integer	$remove Whether to remove the resource/data from the
1172
     * system or leave it (default: 'keep', others 'remove')
1173
     * @return	integer	Number of elements moved
1174
     * @todo implement resource removal
1175
     */
1176
    public function delete_item($id, $remove = 'keep')
1177
    {
1178
        $course_id = api_get_course_int_id();
1179
        if ($this->debug > 0) {
1180
            error_log('New LP - In learnpath::delete_item()', 0);
1181
        }
1182
        // TODO: Implement the resource removal.
1183
        if (empty ($id) || $id != strval(intval($id))) {
1184
            return false;
1185
        }
1186
        // First select item to get previous, next, and display order.
1187
        $lp_item = Database :: get_course_table(TABLE_LP_ITEM);
1188
        $sql_sel = "SELECT * FROM $lp_item WHERE c_id = ".$course_id." AND id = $id";
1189
        $res_sel = Database::query($sql_sel);
1190
        if (Database :: num_rows($res_sel) < 1) {
1191
            return false;
1192
        }
1193
        $row = Database :: fetch_array($res_sel);
1194
        $previous = $row['previous_item_id'];
1195
        $next = $row['next_item_id'];
1196
        $display = $row['display_order'];
1197
        $parent = $row['parent_item_id'];
1198
        $lp = $row['lp_id'];
1199
        // Delete children items.
1200
        $num = $this->delete_children_items($id);
1201
        if ($this->debug > 2) {
1202
            error_log('New LP - learnpath::delete_item() - deleted ' . $num . ' children of element ' . $id, 0);
1203
        }
1204
        // Now delete the item.
1205
        $sql_del = "DELETE FROM $lp_item WHERE c_id = $course_id AND id = $id";
1206
        if ($this->debug > 2) {
1207
            error_log('New LP - Deleting item: ' . $sql_del, 0);
1208
        }
1209
        Database::query($sql_del);
1210
        // Now update surrounding items.
1211
        $sql_upd = "UPDATE $lp_item SET next_item_id = $next
1212
                    WHERE c_id = ".$course_id." AND id = $previous";
1213
        Database::query($sql_upd);
1214
        $sql_upd = "UPDATE $lp_item SET previous_item_id = $previous
1215
                    WHERE c_id = ".$course_id." AND id = $next";
1216
        Database::query($sql_upd);
1217
        // Now update all following items with new display order.
1218
        $sql_all = "UPDATE $lp_item SET display_order = display_order-1
1219
                    WHERE c_id = ".$course_id." AND lp_id = $lp AND parent_item_id = $parent AND display_order > $display";
1220
        Database::query($sql_all);
1221
1222
        //Removing prerequisites since the item will not longer exist
1223
        $sql_all = "UPDATE $lp_item SET prerequisite = '' WHERE c_id = ".$course_id." AND prerequisite = $id";
1224
        Database::query($sql_all);
1225
1226
        // Remove from search engine if enabled.
1227
        if (api_get_setting('search_enabled') == 'true') {
1228
            $tbl_se_ref = Database :: get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
1229
            $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s AND ref_id_second_level=%d LIMIT 1';
1230
            $sql = sprintf($sql, $tbl_se_ref, $this->cc, TOOL_LEARNPATH, $lp, $id);
1231
            $res = Database::query($sql);
1232
            if (Database :: num_rows($res) > 0) {
1233
                $row2 = Database :: fetch_array($res);
1234
                require_once api_get_path(LIBRARY_PATH).'search/ChamiloIndexer.class.php';
1235
                $di = new ChamiloIndexer();
1236
                $di->remove_document((int) $row2['search_did']);
1237
            }
1238
            $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s AND ref_id_second_level=%d LIMIT 1';
1239
            $sql = sprintf($sql, $tbl_se_ref, $this->cc, TOOL_LEARNPATH, $lp, $id);
1240
            Database::query($sql);
1241
        }
1242
    }
1243
1244
    /**
1245
     * Updates an item's content in place
1246
     * @param   integer $id Element ID
1247
     * @param   integer $parent Parent item ID
1248
     * @param   integer $previous Previous item ID
1249
     * @param   string  $title Item title
1250
     * @param   string  $description Item description
1251
     * @param   string  $prerequisites Prerequisites (optional)
1252
     * @param   array   $audio The array resulting of the $_FILES[mp3] element
1253
     * @param   int     $max_time_allowed
1254
     * @param   string  $url
1255
     * @return  boolean True on success, false on error
1256
     */
1257
    public function edit_item(
1258
        $id,
1259
        $parent,
1260
        $previous,
1261
        $title,
1262
        $description,
1263
        $prerequisites = '0',
1264
        $audio = array(),
1265
        $max_time_allowed = 0,
1266
        $url = ''
1267
    ) {
1268
        $course_id = api_get_course_int_id();
1269
        $_course = api_get_course_info();
1270
1271
        if ($this->debug > 0) {
1272
            error_log('New LP - In learnpath::edit_item()', 0);
1273
        }
1274
        if (empty ($max_time_allowed)) {
1275
            $max_time_allowed = 0;
1276
        }
1277
        if (empty ($id) || ($id != strval(intval($id))) || empty ($title)) {
1278
            return false;
1279
        }
1280
1281
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
1282
        $sql_select = "SELECT * FROM " . $tbl_lp_item . " WHERE c_id = ".$course_id." AND id = " . $id;
1283
        $res_select = Database::query($sql_select);
1284
        $row_select = Database :: fetch_array($res_select);
1285
        $audio_update_sql = '';
1286
        if (is_array($audio) && !empty ($audio['tmp_name']) && $audio['error'] === 0) {
1287
            // Create the audio folder if it does not exist yet.
1288
            $filepath = api_get_path(SYS_COURSE_PATH) . $_course['path'] . '/document/';
1289 View Code Duplication
            if (!is_dir($filepath . 'audio')) {
1290
                mkdir($filepath . 'audio', api_get_permissions_for_new_directories());
1291
                $audio_id = add_document(
1292
                    $_course,
1293
                    '/audio',
1294
                    'folder',
1295
                    0,
1296
                    'audio'
1297
                );
1298
                api_item_property_update(
1299
                    $_course,
1300
                    TOOL_DOCUMENT,
1301
                    $audio_id,
1302
                    'FolderCreated',
1303
                    api_get_user_id(),
1304
                    null,
1305
                    null,
1306
                    null,
1307
                    null,
1308
                    api_get_session_id()
1309
                );
1310
                api_item_property_update(
1311
                    $_course,
1312
                    TOOL_DOCUMENT,
1313
                    $audio_id,
1314
                    'invisible',
1315
                    api_get_user_id(),
1316
                    null,
1317
                    null,
1318
                    null,
1319
                    null,
1320
                    api_get_session_id()
1321
                );
1322
            }
1323
1324
            // Upload file in documents.
1325
            $pi = pathinfo($audio['name']);
1326
            if ($pi['extension'] == 'mp3') {
1327
                $c_det = api_get_course_info($this->cc);
1328
                $bp = api_get_path(SYS_COURSE_PATH) . $c_det['path'] . '/document';
1329
                $path = handle_uploaded_document($c_det, $audio, $bp, '/audio', api_get_user_id(), 0, null, 0, 'rename', false, 0);
1330
                $path = substr($path, 7);
1331
                // Update reference in lp_item - audio path is the path from inside de document/audio/ dir.
1332
                $audio_update_sql = ", audio = '" . Database::escape_string($path) . "' ";
1333
            }
1334
        }
1335
1336
        $same_parent = ($row_select['parent_item_id'] == $parent) ? true : false;
1337
        $same_previous = ($row_select['previous_item_id'] == $previous) ? true : false;
1338
1339
        // TODO: htmlspecialchars to be checked for encoding related problems.
1340
        if ($same_parent && $same_previous) {
1341
            // Only update title and description.
1342
            $sql = "UPDATE " . $tbl_lp_item . "
1343
                    SET title = '" . Database::escape_string($title) . "',
1344
                        prerequisite = '" . $prerequisites . "',
1345
                        description = '" . Database::escape_string($description) . "'
1346
                        " . $audio_update_sql . ",
1347
                        max_time_allowed = '" . Database::escape_string($max_time_allowed) . "'
1348
                    WHERE c_id = ".$course_id." AND id = " . $id;
1349
            Database::query($sql);
1350
        } else {
1351
            $old_parent = $row_select['parent_item_id'];
1352
            $old_previous = $row_select['previous_item_id'];
1353
            $old_next = $row_select['next_item_id'];
1354
            $old_order = $row_select['display_order'];
1355
            $old_prerequisite = $row_select['prerequisite'];
1356
            $old_max_time_allowed = $row_select['max_time_allowed'];
1357
1358
            /* BEGIN -- virtually remove the current item id */
1359
            /* for the next and previous item it is like the current item doesn't exist anymore */
1360
1361
            if ($old_previous != 0) {
1362
                // Next
1363
                $sql = "UPDATE " . $tbl_lp_item . "
1364
                        SET next_item_id = " . $old_next . "
1365
                        WHERE c_id = ".$course_id." AND id = " . $old_previous;
1366
                Database::query($sql);
1367
            }
1368
1369
            if ($old_next != 0) {
1370
                // Previous
1371
                $sql = "UPDATE " . $tbl_lp_item . "
1372
                        SET previous_item_id = " . $old_previous . "
1373
                        WHERE c_id = ".$course_id." AND id = " . $old_next;
1374
                Database::query($sql);
1375
            }
1376
1377
            // display_order - 1 for every item with a display_order bigger then the display_order of the current item.
1378
            $sql = "UPDATE " . $tbl_lp_item . "
1379
                    SET display_order = display_order - 1
1380
                    WHERE
1381
                        c_id = ".$course_id." AND
1382
                        display_order > " . $old_order . " AND
1383
                        lp_id = " . $this->lp_id . " AND
1384
                        parent_item_id = " . $old_parent;
1385
            Database::query($sql);
1386
            /* END -- virtually remove the current item id */
1387
1388
            /* BEGIN -- update the current item id to his new location */
1389
1390
            if ($previous == 0) {
1391
                // Select the data of the item that should come after the current item.
1392
                $sql = "SELECT id, display_order
1393
                        FROM " . $tbl_lp_item . "
1394
                        WHERE
1395
                            c_id = ".$course_id." AND
1396
                            lp_id = " . $this->lp_id . " AND
1397
                            parent_item_id = " . $parent . " AND
1398
                            previous_item_id = " . $previous;
1399
                $res_select_old = Database::query($sql);
1400
                $row_select_old = Database::fetch_array($res_select_old);
1401
1402
                // If the new parent didn't have children before.
1403
                if (Database :: num_rows($res_select_old) == 0) {
1404
                    $new_next = 0;
1405
                    $new_order = 1;
1406
                } else {
1407
                    $new_next = $row_select_old['id'];
1408
                    $new_order = $row_select_old['display_order'];
1409
                }
1410
            } else {
1411
                // Select the data of the item that should come before the current item.
1412
                $sql = "SELECT next_item_id, display_order
1413
                        FROM " . $tbl_lp_item . "
1414
                        WHERE c_id = ".$course_id." AND id = " . $previous;
1415
                $res_select_old = Database::query($sql);
1416
                $row_select_old = Database :: fetch_array($res_select_old);
1417
                $new_next = $row_select_old['next_item_id'];
1418
                $new_order = $row_select_old['display_order'] + 1;
1419
            }
1420
1421
            // TODO: htmlspecialchars to be checked for encoding related problems.
1422
            // Update the current item with the new data.
1423
            $sql = "UPDATE " . $tbl_lp_item . "
1424
                    SET
1425
                        title = '" . Database::escape_string($title) . "',
1426
                        description = '" . Database::escape_string($description) . "',
1427
                        parent_item_id = " . $parent . ",
1428
                        previous_item_id = " . $previous . ",
1429
                        next_item_id = " . $new_next . ",
1430
                        display_order = " . $new_order . "
1431
                        " . $audio_update_sql . "
1432
                    WHERE c_id = ".$course_id." AND id = " . $id;
1433
            Database::query($sql);
1434
1435
            if ($previous != 0) {
1436
                // Update the previous item's next_item_id.
1437
                $sql = "UPDATE " . $tbl_lp_item . "
1438
                        SET next_item_id = " . $id . "
1439
                        WHERE c_id = ".$course_id." AND id = " . $previous;
1440
                Database::query($sql);
1441
            }
1442
1443
            if ($new_next != 0) {
1444
                // Update the next item's previous_item_id.
1445
                $sql = "UPDATE " . $tbl_lp_item . "
1446
                        SET previous_item_id = " . $id . "
1447
                        WHERE c_id = ".$course_id." AND id = " . $new_next;
1448
                Database::query($sql);
1449
            }
1450
1451
            if ($old_prerequisite != $prerequisites) {
1452
                $sql = "UPDATE " . $tbl_lp_item . "
1453
                        SET prerequisite = '" . $prerequisites . "'
1454
                        WHERE c_id = ".$course_id." AND id = " . $id;
1455
                Database::query($sql);
1456
            }
1457
1458
            if ($old_max_time_allowed != $max_time_allowed) {
1459
                // update max time allowed
1460
                $sql = "UPDATE " . $tbl_lp_item . "
1461
                        SET max_time_allowed = " . $max_time_allowed . "
1462
                        WHERE c_id = ".$course_id." AND id = " . $id;
1463
                Database::query($sql);
1464
            }
1465
1466
            // Update all the items with the same or a bigger display_order than the current item.
1467
            $sql = "UPDATE " . $tbl_lp_item . "
1468
                    SET display_order = display_order + 1
1469
                    WHERE
1470
                       c_id = ".$course_id." AND
1471
                       lp_id = " . $this->get_id() . " AND
1472
                       id <> " . $id . " AND
1473
                       parent_item_id = " . $parent . " AND
1474
                       display_order >= " . $new_order;
1475
1476
            Database::query($sql);
1477
        }
1478
1479
        if ($row_select['item_type'] == 'link') {
1480
            $link = new Link();
0 ignored issues
show
Bug introduced by
The call to Link::__construct() misses some required arguments starting with $id.
Loading history...
1481
            $linkId = $row_select['path'];
1482
            $link->updateLink($linkId, $url);
1483
        }
1484
    }
1485
1486
    /**
1487
     * Updates an item's prereq in place
1488
     * @param	integer	$id Element ID
1489
     * @param	string	$prerequisite_id Prerequisite Element ID
1490
     * @param	int 	$mastery_score Prerequisite min score
1491
     * @param	int 	$max_score Prerequisite max score
1492
     *
1493
     * @return	boolean	True on success, false on error
1494
     */
1495
    public function edit_item_prereq($id, $prerequisite_id, $mastery_score = 0, $max_score = 100)
1496
    {
1497
        $course_id = api_get_course_int_id();
1498
        if ($this->debug > 0) {
1499
            error_log('New LP - In learnpath::edit_item_prereq(' . $id . ',' . $prerequisite_id . ',' . $mastery_score . ',' . $max_score . ')', 0);
1500
        }
1501
1502
        if (empty($id) || ($id != strval(intval($id))) || empty ($prerequisite_id)) {
1503
            return false;
1504
        }
1505
1506
        $prerequisite_id = intval($prerequisite_id);
1507
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
1508
1509
        if (!is_numeric($mastery_score) || $mastery_score < 0) {
1510
            $mastery_score = 0;
1511
        }
1512
1513
        if (!is_numeric($max_score) || $max_score < 0) {
1514
            $max_score = 100;
1515
        }
1516
1517
        /*if ($mastery_score > $max_score) {
1518
            $max_score = $mastery_score;
1519
        }*/
1520
1521
        if (!is_numeric($prerequisite_id)) {
1522
            $prerequisite_id = 'NULL';
1523
        }
1524
1525
        $mastery_score = floatval($mastery_score);
1526
        $max_score = floatval($max_score);
1527
1528
        $sql = " UPDATE $tbl_lp_item
1529
                 SET
1530
                    prerequisite = $prerequisite_id ,
1531
                    prerequisite_min_score = $mastery_score ,
1532
                    prerequisite_max_score = $max_score
1533
                 WHERE c_id = $course_id AND id = $id";
1534
        Database::query($sql);
1535
1536
        if ($prerequisite_id != 'NULL' && $prerequisite_id != '') {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
1537
            // Will this be enough to ensure unicity?
1538
            /*$sql = " UPDATE $tbl_lp_item
1539
                     SET mastery_score = $mastery_score
1540
                     WHERE c_id = $course_id AND ref = '$prerequisite_id'";
1541
1542
            Database::query($sql);*/
1543
        }
1544
        // TODO: Update the item object (can be ignored for now because refreshed).
1545
        return true;
1546
    }
1547
1548
    /**
1549
     * Escapes a string with the available database escape function
1550
     * @param	string	String to escape
1551
     * @return	string	String escaped
1552
     * @deprecated use  Database::escape_string
1553
     */
1554
    public function escape_string($string)
1555
    {
1556
        return Database::escape_string($string);
1557
    }
1558
1559
    /**
1560
     * Static admin function exporting a learnpath into a zip file
1561
     * @param	string	Export type (scorm, zip, cd)
1562
     * @param	string	Course code
1563
     * @param	integer Learnpath ID
1564
     * @param	string	Zip file name
1565
     * @return	string	Zip file path (or false on error)
1566
     */
1567
    public function export_lp($type, $course, $id, $zipname)
1568
    {
1569
        if (empty($type) || empty($course) || empty($id) || empty($zipname)) {
1570
            return false;
1571
        }
1572
        $url = '';
1573
        switch ($type) {
1574
            case 'scorm':
1575
                break;
1576
            case 'zip':
1577
                break;
1578
            case 'cdrom':
1579
                break;
1580
        }
1581
        return $url;
1582
    }
1583
1584
    /**
1585
     * Gets all the chapters belonging to the same parent as the item/chapter given
1586
     * Can also be called as abstract method
1587
     * @param	integer	Item ID
1588
     * @return	array	A list of all the "brother items" (or an empty array on failure)
1589
     */
1590 View Code Duplication
    public function get_brother_chapters($id)
1591
    {
1592
        $course_id = api_get_course_int_id();
1593
        if ($this->debug > 0) {
1594
            error_log('New LP - In learnpath::get_brother_chapters()', 0);
1595
        }
1596
1597
        if (empty($id)|| $id != strval(intval($id))) {
1598
            return array ();
1599
        }
1600
1601
        $lp_item = Database :: get_course_table(TABLE_LP_ITEM);
1602
        $sql_parent = "SELECT * FROM $lp_item
1603
                       WHERE c_id = ".$course_id." AND id = $id AND item_type='dokeos_chapter'";
1604
        $res_parent = Database::query($sql_parent);
1605
        if (Database :: num_rows($res_parent) > 0) {
1606
            $row_parent = Database :: fetch_array($res_parent);
1607
            $parent = $row_parent['parent_item_id'];
1608
            $sql_bros = "SELECT * FROM $lp_item
1609
                        WHERE
1610
                            c_id = ".$course_id." AND
1611
                            parent_item_id = $parent AND
1612
                            id = $id AND
1613
                            item_type='dokeos_chapter'
1614
                        ORDER BY display_order";
1615
            $res_bros = Database::query($sql_bros);
1616
            $list = array ();
1617
            while ($row_bro = Database :: fetch_array($res_bros)) {
1618
                $list[] = $row_bro;
1619
            }
1620
            return $list;
1621
        }
1622
        return array ();
1623
    }
1624
1625
    /**
1626
     * Gets all the items belonging to the same parent as the item given
1627
     * Can also be called as abstract method
1628
     * @param	integer	Item ID
1629
     * @return	array	A list of all the "brother items" (or an empty array on failure)
1630
     */
1631 View Code Duplication
    public function get_brother_items($id)
1632
    {
1633
        $course_id = api_get_course_int_id();
1634
        if ($this->debug > 0) {
1635
            error_log('New LP - In learnpath::get_brother_items(' . $id . ')', 0);
1636
        }
1637
1638
        if (empty ($id) || $id != strval(intval($id))) {
1639
            return array ();
1640
        }
1641
1642
        $lp_item = Database :: get_course_table(TABLE_LP_ITEM);
1643
        $sql_parent = "SELECT * FROM $lp_item WHERE c_id = $course_id AND id = $id";
1644
        $res_parent = Database::query($sql_parent);
1645
        if (Database :: num_rows($res_parent) > 0) {
1646
            $row_parent = Database :: fetch_array($res_parent);
1647
            $parent = $row_parent['parent_item_id'];
1648
            $sql_bros = "SELECT * FROM $lp_item WHERE c_id = ".$course_id." AND parent_item_id = $parent
1649
                         ORDER BY display_order";
1650
            $res_bros = Database::query($sql_bros);
1651
            $list = array ();
1652
            while ($row_bro = Database :: fetch_array($res_bros)) {
1653
                $list[] = $row_bro;
1654
            }
1655
            return $list;
1656
        }
1657
        return array ();
1658
    }
1659
1660
    /**
1661
     * Get the specific prefix index terms of this learning path
1662
     * @param string $prefix
1663
     * @return  array Array of terms
1664
     */
1665
    public function get_common_index_terms_by_prefix($prefix)
1666
    {
1667
        require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
1668
        $terms = get_specific_field_values_list_by_prefix(
1669
            $prefix,
1670
            $this->cc,
1671
            TOOL_LEARNPATH,
1672
            $this->lp_id
1673
        );
1674
        $prefix_terms = array();
1675
        if (!empty($terms)) {
1676
            foreach ($terms as $term) {
1677
                $prefix_terms[] = $term['value'];
1678
            }
1679
        }
1680
        return $prefix_terms;
1681
    }
1682
1683
    /**
1684
     * Gets the number of items currently completed
1685
     * @return integer The number of items currently completed
1686
     */
1687
    public function get_complete_items_count()
1688
    {
1689
        if ($this->debug > 0) {
1690
            error_log('New LP - In learnpath::get_complete_items_count()', 0);
1691
        }
1692
        $i = 0;
1693
        $completedStatusList = array(
1694
            'completed',
1695
            'passed',
1696
            'succeeded',
1697
            'browsed',
1698
            'failed'
1699
        );
1700
1701
        foreach ($this->items as $id => $dummy) {
1702
            // Trying failed and browsed considered "progressed" as well.
1703
            if ($this->items[$id]->status_is($completedStatusList) &&
1704
                $this->items[$id]->get_type() != 'dokeos_chapter' &&
1705
                $this->items[$id]->get_type() != 'dir'
1706
            ) {
1707
                $i++;
1708
            }
1709
        }
1710
        return $i;
1711
    }
1712
1713
    /**
1714
     * Gets the current item ID
1715
     * @return	integer	The current learnpath item id
1716
     */
1717
    public function get_current_item_id()
1718
    {
1719
        $current = 0;
1720
        if ($this->debug > 0) {
1721
            error_log('New LP - In learnpath::get_current_item_id()', 0);
1722
        }
1723
        if (!empty($this->current)) {
1724
            $current = $this->current;
1725
        }
1726
        if ($this->debug > 2) {
1727
            error_log('New LP - In learnpath::get_current_item_id() - Returning ' . $current, 0);
1728
        }
1729
        return $current;
1730
    }
1731
1732
    /**
1733
     * Force to get the first learnpath item id
1734
     * @return	integer	The current learnpath item id
1735
     */
1736
    public function get_first_item_id()
1737
    {
1738
        $current = 0;
1739
        if (is_array($this->ordered_items)) {
1740
            $current = $this->ordered_items[0];
1741
        }
1742
        return $current;
1743
    }
1744
1745
    /**
1746
     * Gets the total number of items available for viewing in this SCORM
1747
     * @return	integer	The total number of items
1748
     */
1749
    public function get_total_items_count()
1750
    {
1751
        if ($this->debug > 0) {
1752
            error_log('New LP - In learnpath::get_total_items_count()', 0);
1753
        }
1754
        return count($this->items);
1755
    }
1756
1757
    /**
1758
     * Gets the total number of items available for viewing in this SCORM but without chapters
1759
     * @return	integer	The total no-chapters number of items
1760
     */
1761
    public function get_total_items_count_without_chapters()
1762
    {
1763
        if ($this->debug > 0) {
1764
            error_log('New LP - In learnpath::get_total_items_count_without_chapters()', 0);
1765
        }
1766
        $total = 0;
1767
        $typeListNotToCount = self::getChapterTypes();
1768
        foreach ($this->items as $temp2) {
1769
            if (!in_array($temp2->get_type(), $typeListNotToCount)) {
1770
                $total++;
1771
            }
1772
        }
1773
        return $total;
1774
    }
1775
1776
    /**
1777
     * Gets the first element URL.
1778
     * @return	string	URL to load into the viewer
1779
     */
1780
    public function first()
1781
    {
1782
        if ($this->debug > 0) {
1783
            error_log('New LP - In learnpath::first()', 0);
1784
            error_log('$this->last_item_seen '.$this->last_item_seen);
1785
        }
1786
1787
        // Test if the last_item_seen exists and is not a dir.
1788
        if (count($this->ordered_items) == 0) {
1789
            $this->index = 0;
1790
        }
1791
1792
        if ($this->debug > 0) {
1793
            if (isset($this->items[$this->last_item_seen])) {
1794
                $status = $this->items[$this->last_item_seen]->get_status();
1795
            }
1796
            error_log('status '.$status);
1797
        }
1798
1799
        if (!empty($this->last_item_seen) &&
1800
            !empty($this->items[$this->last_item_seen]) &&
1801
            $this->items[$this->last_item_seen]->get_type() != 'dir' &&
1802
            $this->items[$this->last_item_seen]->get_type() != 'dokeos_chapter'
1803
            //with this change (below) the LP will NOT go to the next item, it will take lp item we left
1804
            //&& !$this->items[$this->last_item_seen]->is_done()
1805
        ) {
1806
1807
            if ($this->debug > 2) {
1808
                error_log('New LP - In learnpath::first() - Last item seen is ' . $this->last_item_seen.' of type '.$this->items[$this->last_item_seen]->get_type(), 0);
1809
            }
1810
            $index = -1;
1811
            foreach ($this->ordered_items as $myindex => $item_id) {
1812
                if ($item_id == $this->last_item_seen) {
1813
                    $index = $myindex;
1814
                    break;
1815
                }
1816
            }
1817
            if ($index == -1) {
1818
                // Index hasn't changed, so item not found - panic (this shouldn't happen).
1819
                if ($this->debug > 2) {
1820
                    error_log('New LP - Last item (' . $this->last_item_seen . ') was found in items but not in ordered_items, panic!', 0);
1821
                }
1822
                return false;
1823
            } else {
1824
                $this->last     = $this->last_item_seen;
1825
                $this->current  = $this->last_item_seen;
1826
                $this->index    = $index;
1827
            }
1828
        } else {
1829
            if ($this->debug > 2) {
1830
                error_log('New LP - In learnpath::first() - No last item seen', 0);
1831
            }
1832
            $index = 0;
1833
            // Loop through all ordered items and stop at the first item that is
1834
            // not a directory *and* that has not been completed yet.
1835
            while ( !empty($this->ordered_items[$index]) AND
1836
                is_a($this->items[$this->ordered_items[$index]], 'learnpathItem') AND
1837
                (
1838
                    $this->items[$this->ordered_items[$index]]->get_type() == 'dir' OR
1839
                    $this->items[$this->ordered_items[$index]]->get_type() == 'dokeos_chapter' OR
1840
                    $this->items[$this->ordered_items[$index]]->is_done() === true
1841
                ) AND $index < $this->max_ordered_items) {
1842
                $index++;
1843
            }
1844
            $this->last     = $this->current;
1845
            // current is
1846
            $this->current  = isset($this->ordered_items[$index]) ? $this->ordered_items[$index] : null;
1847
            $this->index    = $index;
1848
            if ($this->debug > 2) {
1849
                error_log('$index ' . $index);
1850
            }
1851 View Code Duplication
            if ($this->debug > 2) {
1852
                error_log('New LP - In learnpath::first() - No last item seen. New last = ' . $this->last . '(' . $this->ordered_items[$index] . ')', 0);
1853
            }
1854
        }
1855
        if ($this->debug > 2) {
1856
            error_log('New LP - In learnpath::first() - First item is ' . $this->get_current_item_id());
1857
        }
1858
    }
1859
1860
    /**
1861
     * Gets the information about an item in a format usable as JavaScript to update
1862
     * the JS API by just printing this content into the <head> section of the message frame
1863
     * @param	int $item_id
1864
     * @return	string
1865
     */
1866
    public function get_js_info($item_id = '')
1867
    {
1868
        if ($this->debug > 0) {
1869
            error_log('New LP - In learnpath::get_js_info(' . $item_id . ')', 0);
1870
        }
1871
1872
        $info = '';
1873
        $item_id = intval($item_id);
1874
1875
        if (!empty($item_id) && is_object($this->items[$item_id])) {
1876
            //if item is defined, return values from DB
1877
            $oItem = $this->items[$item_id];
1878
            $info .= '<script language="javascript">';
1879
            $info .= "top.set_score(" . $oItem->get_score() . ");\n";
1880
            $info .= "top.set_max(" . $oItem->get_max() . ");\n";
1881
            $info .= "top.set_min(" . $oItem->get_min() . ");\n";
1882
            $info .= "top.set_lesson_status('" . $oItem->get_status() . "');";
1883
            $info .= "top.set_session_time('" . $oItem->get_scorm_time('js') . "');";
1884
            $info .= "top.set_suspend_data('" . $oItem->get_suspend_data() . "');";
1885
            $info .= "top.set_saved_lesson_status('" . $oItem->get_status() . "');";
1886
            $info .= "top.set_flag_synchronized();";
1887
            $info .= '</script>';
1888
            if ($this->debug > 2) {
1889
                error_log('New LP - in learnpath::get_js_info(' . $item_id . ') - returning: ' . $info, 0);
1890
            }
1891
            return $info;
1892
1893
        } else {
1894
1895
            // If item_id is empty, just update to default SCORM data.
1896
            $info .= '<script language="javascript">';
1897
            $info .= "top.set_score(" . learnpathItem :: get_score() . ");\n";
1898
            $info .= "top.set_max(" . learnpathItem :: get_max() . ");\n";
1899
            $info .= "top.set_min(" . learnpathItem :: get_min() . ");\n";
1900
            $info .= "top.set_lesson_status('" . learnpathItem :: get_status() . "');";
1901
            $info .= "top.set_session_time('" . learnpathItem :: getScormTimeFromParameter('js') . "');";
1902
            $info .= "top.set_suspend_data('" . learnpathItem :: get_suspend_data() . "');";
1903
            $info .= "top.set_saved_lesson_status('" . learnpathItem :: get_status() . "');";
1904
            $info .= "top.set_flag_synchronized();";
1905
            $info .= '</script>';
1906
            if ($this->debug > 2) {
1907
                error_log('New LP - in learnpath::get_js_info(' . $item_id . ') - returning: ' . $info, 0);
1908
            }
1909
            return $info;
1910
        }
1911
    }
1912
1913
    /**
1914
     * Gets the js library from the database
1915
     * @return	string	The name of the javascript library to be used
1916
     */
1917
    public function get_js_lib()
1918
    {
1919
        $lib = '';
1920
        if (!empty ($this->js_lib)) {
1921
            $lib = $this->js_lib;
1922
        }
1923
        return $lib;
1924
    }
1925
1926
    /**
1927
     * Gets the learnpath database ID
1928
     * @return	integer	Learnpath ID in the lp table
1929
     */
1930
    public function get_id()
1931
    {
1932
        if (!empty ($this->lp_id)) {
1933
            return $this->lp_id;
1934
        } else {
1935
            return 0;
1936
        }
1937
    }
1938
1939
    /**
1940
     * Gets the last element URL.
1941
     * @return string URL to load into the viewer
1942
     */
1943
    public function get_last()
1944
    {
1945
        if ($this->debug > 0) {
1946
            error_log('New LP - In learnpath::get_last()', 0);
1947
        }
1948
        //This is just in case the lesson doesn't cointain a valid scheme, just to avoid "Notices"
1949
        if (count($this->ordered_items) > 0) {
1950
            $this->index = count($this->ordered_items) - 1;
1951
            return $this->ordered_items[$this->index];
1952
        }
1953
1954
        return false;
1955
    }
1956
1957
    /**
1958
     * Gets the navigation bar for the learnpath display screen
1959
     * @return	string	The HTML string to use as a navigation bar
1960
     */
1961
    public function get_navigation_bar($idBar = null, $display=null) {
1962
        if ($this->debug > 0) {
1963
            error_log('New LP - In learnpath::get_navigation_bar()', 0);
1964
        }
1965
        if(empty($idBar)){
1966
            $idBar='control-top';
1967
        }
1968
        /* if(empty($display)){
1969
            $display='display:block';
1970
        } */
1971
        $navbar = null;
1972
        $lp_id = $this->lp_id;
1973
        $mycurrentitemid = $this->get_current_item_id();
1974
1975
        if ($this->mode == 'fullscreen') {
1976
            $navbar = '
1977
                  <span id="'.$idBar.'" class="buttons">
1978
                    <a class="icon-toolbar" href="lp_controller.php?action=stats&'.api_get_cidreq(true).'&lp_id='.$lp_id.'" onclick="window.parent.API.save_asset();return true;" target="content_name" title="stats" id="stats_link">
1979
                        <span class="fa fa-info"></span><span class="sr-only">' . get_lang('Reporting') . '</span>
1980
                    </a>
1981
                    <a class="icon-toolbar" id="scorm-previous" href="#" onclick="switch_item(' . $mycurrentitemid . ',\'previous\');return false;" title="previous">
1982
                        <span class="fa fa-chevron-left"></span><span class="sr-only">' . get_lang('ScormPrevious') . '</span>
1983
                    </a>
1984
                    <a class="icon-toolbar" id="scorm-next" href="#" onclick="switch_item(' . $mycurrentitemid . ',\'next\');return false;" title="next">
1985
                        <span class="fa fa-chevron-right"></span><span class="sr-only">' . get_lang('ScormNext') . '</span>
1986
                    </a>
1987
                    <a class="icon-toolbar" id="view-embedded" href="lp_controller.php?action=mode&mode=embedded" target="_top" title="embedded mode">
1988
                        <span class="fa fa-columns"></span><span class="sr-only">' . get_lang('ScormExitFullScreen') . '</span>
1989
                    </a>
1990
                  </span>';
1991
1992
        } else {
1993
            $navbar = '
1994
                <span id="'.$idBar.'" class="buttons text-right">
1995
                    <a class="icon-toolbar" href="lp_controller.php?action=stats&'.api_get_cidreq(true).'&lp_id='.$lp_id.'" onclick="window.parent.API.save_asset();return true;" target="content_name" title="stats" id="stats_link">
1996
                        <span class="fa fa-info"></span><span class="sr-only">' . get_lang('Reporting') . '</span>
1997
                    </a>
1998
                    <a class="icon-toolbar" id="scorm-previous" href="#" onclick="switch_item(' . $mycurrentitemid . ',\'previous\');return false;" title="previous">
1999
                        <span class="fa fa-chevron-left"></span><span class="sr-only">' . get_lang('ScormPrevious') . '</span>
2000
                    </a>
2001
                    <a class="icon-toolbar" id="scorm-next" href="#" onclick="switch_item(' . $mycurrentitemid . ',\'next\');return false;" title="next">
2002
                        <span class="fa fa-chevron-right"></span><span class="sr-only">' . get_lang('ScormNext') . '</span>
2003
                    </a>
2004
                </span>';
2005
        }
2006
2007
        return $navbar;
2008
    }
2009
2010
    /**
2011
     * Gets the next resource in queue (url).
2012
     * @return	string	URL to load into the viewer
2013
     */
2014
    public function get_next_index()
2015
    {
2016
        if ($this->debug > 0) {
2017
            error_log('New LP - In learnpath::get_next_index()', 0);
2018
        }
2019
        // TODO
2020
        $index = $this->index;
2021
        $index++;
2022 View Code Duplication
        if ($this->debug > 2) {
2023
            error_log('New LP - Now looking at ordered_items[' . ($index) . '] - type is ' . $this->items[$this->ordered_items[$index]]->type, 0);
2024
        }
2025
        while (!empty ($this->ordered_items[$index]) AND ($this->items[$this->ordered_items[$index]]->get_type() == 'dir' || $this->items[$this->ordered_items[$index]]->get_type() == 'dokeos_chapter') AND $index < $this->max_ordered_items) {
2026
            $index++;
2027
            if ($index == $this->max_ordered_items){
2028
                if ($this->items[$this->ordered_items[$index]]->get_type() == 'dir' || $this->items[$this->ordered_items[$index]]->get_type() == 'dokeos_chapter') {
2029
                    return $this->index;
2030
                } else {
2031
                    return $index;
2032
                }
2033
            }
2034
        }
2035
        if (empty ($this->ordered_items[$index])) {
2036
            return $this->index;
2037
        }
2038
        if ($this->debug > 2) {
2039
            error_log('New LP - index is now ' . $index, 0);
2040
        }
2041
        return $index;
2042
    }
2043
2044
    /**
2045
     * Gets item_id for the next element
2046
     * @return	integer	Next item (DB) ID
2047
     */
2048
    public function get_next_item_id()
2049
    {
2050
        if ($this->debug > 0) {
2051
            error_log('New LP - In learnpath::get_next_item_id()', 0);
2052
        }
2053
        $new_index = $this->get_next_index();
2054
        if (!empty ($new_index)) {
2055
            if (isset ($this->ordered_items[$new_index])) {
2056
                if ($this->debug > 2) {
2057
                    error_log('New LP - In learnpath::get_next_index() - Returning ' . $this->ordered_items[$new_index], 0);
2058
                }
2059
                return $this->ordered_items[$new_index];
2060
            }
2061
        }
2062
        if ($this->debug > 2) {
2063
            error_log('New LP - In learnpath::get_next_index() - Problem - Returning 0', 0);
2064
        }
2065
        return 0;
2066
    }
2067
2068
    /**
2069
     * Returns the package type ('scorm','aicc','scorm2004','dokeos','ppt'...)
2070
     *
2071
     * Generally, the package provided is in the form of a zip file, so the function
2072
     * has been written to test a zip file. If not a zip, the function will return the
2073
     * default return value: ''
2074
     * @param	string	the path to the file
2075
     * @param	string 	the original name of the file
2076
     * @return	string	'scorm','aicc','scorm2004','dokeos' or '' if the package cannot be recognized
2077
     */
2078
    public static function get_package_type($file_path, $file_name)
2079
    {
2080
        // Get name of the zip file without the extension.
2081
        $file_info = pathinfo($file_name);
2082
        $filename = $file_info['basename']; // Name including extension.
2083
        $extension = $file_info['extension']; // Extension only.
2084
2085
        if (!empty($_POST['ppt2lp']) && !in_array(strtolower($extension), array(
2086
                'dll',
2087
                'exe'
2088
            ))) {
2089
            return 'oogie';
2090
        }
2091
        if (!empty($_POST['woogie']) && !in_array(strtolower($extension), array(
2092
                'dll',
2093
                'exe'
2094
            ))) {
2095
            return 'woogie';
2096
        }
2097
2098
        // Filename without its extension.
2099
        $file_base_name = str_replace('.' . $extension, '', $filename);
2100
2101
        $zipFile = new PclZip($file_path);
2102
        // Check the zip content (real size and file extension).
2103
        $zipContentArray = $zipFile->listContent();
2104
        $package_type = '';
2105
        $at_root = false;
2106
        $manifest = '';
2107
        $aicc_match_crs = 0;
2108
        $aicc_match_au = 0;
2109
        $aicc_match_des = 0;
2110
        $aicc_match_cst = 0;
2111
2112
        // The following loop should be stopped as soon as we found the right imsmanifest.xml (how to recognize it?).
2113
        if (is_array($zipContentArray) && count($zipContentArray) > 0) {
2114
            foreach ($zipContentArray as $thisContent) {
2115
                if (preg_match('~.(php.*|phtml)$~i', $thisContent['filename'])) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
2116
                    // New behaviour: Don't do anything. These files will be removed in scorm::import_package.
2117
                } elseif (stristr($thisContent['filename'], 'imsmanifest.xml') !== false) {
2118
                    $manifest = $thisContent['filename']; // Just the relative directory inside scorm/
2119
                    $package_type = 'scorm';
2120
                    break; // Exit the foreach loop.
2121
                } elseif (
2122
                    preg_match('/aicc\//i', $thisContent['filename']) ||
2123
                    in_array(strtolower(pathinfo($thisContent['filename'], PATHINFO_EXTENSION)), array( 'crs','au','des','cst'))
2124
                ) {
2125
                    $ext = strtolower(pathinfo($thisContent['filename'], PATHINFO_EXTENSION));
2126
                    switch ($ext) {
2127
                        case 'crs':
2128
                            $aicc_match_crs = 1;
2129
                            break;
2130
                        case 'au':
2131
                            $aicc_match_au = 1;
2132
                            break;
2133
                        case 'des':
2134
                            $aicc_match_des = 1;
2135
                            break;
2136
                        case 'cst':
2137
                            $aicc_match_cst = 1;
2138
                            break;
2139
                        default:
2140
                            break;
2141
                    }
2142
                    //break; // Don't exit the loop, because if we find an imsmanifest afterwards, we want it, not the AICC.
2143
                } else {
2144
                    $package_type = '';
2145
                }
2146
            }
2147
        }
2148
        if (empty($package_type) && 4 == ($aicc_match_crs + $aicc_match_au + $aicc_match_des + $aicc_match_cst)) {
2149
            // If found an aicc directory... (!= false means it cannot be false (error) or 0 (no match)).
2150
            $package_type = 'aicc';
2151
        }
2152
        return $package_type;
2153
    }
2154
2155
    /**
2156
     * Gets the previous resource in queue (url). Also initialises time values for this viewing
2157
     * @return string URL to load into the viewer
2158
     */
2159
    public function get_previous_index()
2160
    {
2161
        if ($this->debug > 0) {
2162
            error_log('New LP - In learnpath::get_previous_index()', 0);
2163
        }
2164
        $index = $this->index;
2165
        if (isset ($this->ordered_items[$index -1])) {
2166
            $index--;
2167
            while (isset($this->ordered_items[$index]) && ($this->items[$this->ordered_items[$index]]->get_type() == 'dir' || $this->items[$this->ordered_items[$index]]->get_type() == 'dokeos_chapter')) {
2168
                $index--;
2169
                if ($index < 0) {
2170
                    return $this->index;
2171
                }
2172
            }
2173
        } else {
2174
            if ($this->debug > 2) {
2175
                error_log('New LP - get_previous_index() - there was no previous index available, reusing ' . $index, 0);
2176
            }
2177
            // There is no previous item.
2178
        }
2179
        return $index;
2180
    }
2181
2182
    /**
2183
     * Gets item_id for the next element
2184
     * @return	integer	Previous item (DB) ID
2185
     */
2186
    public function get_previous_item_id()
2187
    {
2188
        if ($this->debug > 0) {
2189
            error_log('New LP - In learnpath::get_previous_item_id()', 0);
2190
        }
2191
        $new_index = $this->get_previous_index();
2192
        return $this->ordered_items[$new_index];
2193
    }
2194
2195
    /**
2196
     * Gets the progress value from the progress_db attribute
2197
     * @return	integer	Current progress value
2198
     */
2199
    public function get_progress()
2200
    {
2201
        if ($this->debug > 0) {
2202
            error_log('New LP - In learnpath::get_progress()', 0);
2203
        }
2204
        if (!empty ($this->progress_db)) {
2205
            return $this->progress_db;
2206
        }
2207
        return 0;
2208
    }
2209
2210
    /**
2211
     * Returns the HTML necessary to print a mediaplayer block inside a page
2212
     * @return string	The mediaplayer HTML
2213
     */
2214
    public function get_mediaplayer($autostart = 'true')
2215
    {
2216
        $course_id = api_get_course_int_id();
2217
        $_course = api_get_course_info();
2218
        $tbl_lp_item 		= Database :: get_course_table(TABLE_LP_ITEM);
2219
        $tbl_lp_item_view 	= Database :: get_course_table(TABLE_LP_ITEM_VIEW);
2220
2221
        // Getting all the information about the item.
2222
        $sql = "SELECT * FROM ".$tbl_lp_item." as lp
2223
                INNER JOIN ".$tbl_lp_item_view." as lp_view
2224
                ON lp.id = lp_view.lp_item_id
2225
                WHERE
2226
                    lp.id = '".$_SESSION['oLP']->current."' AND
2227
                    lp.c_id = $course_id AND
2228
                    lp_view.c_id = $course_id";
2229
        $result = Database::query($sql);
2230
        $row 	= Database::fetch_assoc($result);
2231
        $output = '';
2232
2233
        if (!empty ($row['audio'])) {
2234
2235
            $list = $_SESSION['oLP']->get_toc();
2236
            $type_quiz = false;
2237
2238
            foreach($list as $toc) {
2239
                if ($toc['id'] == $_SESSION['oLP']->current && ($toc['type']=='quiz') ) {
2240
                    $type_quiz = true;
2241
                }
2242
            }
2243
2244
            if ($type_quiz) {
2245
                if ($_SESSION['oLP']->prevent_reinit == 1) {
2246
                    $row['status'] === 'completed' ? $autostart_audio = 'false' : $autostart_audio = 'true';
2247
                } else {
2248
                    $autostart_audio = $autostart;
2249
                }
2250
            } else {
2251
                $autostart_audio = 'true';
2252
            }
2253
2254
            $courseInfo = api_get_course_info();
2255
2256
            $audio = $row['audio'];
2257
2258
            $file = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/audio/'.$audio;
2259
            $url = api_get_path(WEB_COURSE_PATH).$courseInfo['path'].'/document/audio/'.$audio.'?'.api_get_cidreq();
2260
2261
            if (!file_exists($file)) {
2262
                $lpPathInfo = $_SESSION['oLP']->generate_lp_folder(api_get_course_info());
2263
                $file = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document'.$lpPathInfo['dir'].$audio;
2264
                $url = api_get_path(WEB_COURSE_PATH).$_course['path'].'/document'.$lpPathInfo['dir'].$audio.'?'.api_get_cidreq();
2265
            }
2266
2267
            $player = Display::getMediaPlayer(
2268
                $file,
2269
                array(
2270
                    'id' => 'lp_audio_media_player',
2271
                    'url' => $url,
2272
                    'autoplay' => $autostart_audio,
2273
                    'width' => '100%'
2274
                )
2275
            );
2276
2277
            // The mp3 player.
2278
            $output  = '<div id="container">';
2279
            $output .= $player;
2280
            $output .= '</div>';
2281
        }
2282
2283
        return $output;
2284
    }
2285
2286
    /**
2287
     * Checks if the learning path is visible for student after the progress
2288
     * of its prerequisite is completed, considering the time availability and
2289
     * the LP visibility.
2290
     * @param int $lp_id
2291
     * @param int $student_id
2292
     * @param string Course code (optional)
2293
     * @param int $sessionId
2294
     * @return	bool
2295
     */
2296
    public static function is_lp_visible_for_student(
2297
        $lp_id,
2298
        $student_id,
2299
        $courseCode = null,
2300
        $sessionId = null
2301
    ) {
2302
        $lp_id = (int)$lp_id;
2303
        $courseInfo = api_get_course_info($courseCode);
2304
        $sessionId = intval($sessionId);
2305
2306
        if (empty($sessionId)) {
2307
            $sessionId = api_get_session_id();
2308
        }
2309
2310
        $tbl_learnpath = Database::get_course_table(TABLE_LP_MAIN);
2311
        // Get current prerequisite
2312
        $sql = "SELECT id, prerequisite, subscribe_users, publicated_on, expired_on
2313
                FROM $tbl_learnpath
2314
                WHERE c_id = ".$courseInfo['real_id']." AND id = $lp_id";
2315
2316
        $itemInfo = api_get_item_property_info(
2317
            $courseInfo['real_id'],
2318
            TOOL_LEARNPATH,
2319
            $lp_id,
2320
            $sessionId
2321
        );
2322
2323
        // If the item was deleted.
2324
        if (isset($itemInfo['visibility']) && $itemInfo['visibility'] == 2) {
2325
            return false;
2326
        }
2327
2328
        $rs  = Database::query($sql);
2329
        $now = time();
2330
        if (Database::num_rows($rs) > 0) {
2331
            $row = Database::fetch_array($rs, 'ASSOC');
2332
2333
            $prerequisite = $row['prerequisite'];
2334
            $is_visible = true;
2335
2336
            if (!empty($prerequisite)) {
2337
                $progress = self::getProgress(
2338
                    $prerequisite,
2339
                    $student_id,
2340
                    $courseInfo['real_id'],
2341
                    $sessionId
2342
                );
2343
                $progress = intval($progress);
2344
                if ($progress < 100) {
2345
                    $is_visible = false;
2346
                }
2347
            }
2348
2349
            // Also check the time availability of the LP
2350
            if ($is_visible) {
2351
                // Adding visibility restrictions
2352 View Code Duplication
                if (!empty($row['publicated_on']) &&
2353
                    $row['publicated_on'] != '0000-00-00 00:00:00'
2354
                ) {
2355
                    if ($now < api_strtotime($row['publicated_on'], 'UTC')) {
2356
                        //api_not_allowed();
2357
                        $is_visible = false;
2358
                    }
2359
                }
2360
2361
                // Blocking empty start times see BT#2800
2362
                global $_custom;
2363
                if (isset($_custom['lps_hidden_when_no_start_date']) &&
2364
                    $_custom['lps_hidden_when_no_start_date']
2365
                ) {
2366
                    if (empty($row['publicated_on']) || $row['publicated_on'] == '0000-00-00 00:00:00') {
2367
                        //api_not_allowed();
2368
                        $is_visible = false;
2369
                    }
2370
                }
2371
2372 View Code Duplication
                if (!empty($row['expired_on']) && $row['expired_on'] != '0000-00-00 00:00:00') {
2373
                    if ($now > api_strtotime($row['expired_on'], 'UTC')) {
2374
                        //api_not_allowed();
2375
                        $is_visible = false;
2376
                    }
2377
                }
2378
            }
2379
2380
            // Check if the subscription users/group to a LP is ON
2381
            if (isset($row['subscribe_users']) && $row['subscribe_users'] == 1) {
2382
                // Try group
2383
                $is_visible = false;
2384
2385
                // Checking only the user visibility
2386
                $userVisibility = api_get_item_visibility(
2387
                    $courseInfo,
2388
                    'learnpath',
2389
                    $row['id'],
2390
                    $sessionId,
2391
                    $student_id,
2392
                    'LearnpathSubscription'
2393
                );
2394
2395
                if ($userVisibility == 1) {
2396
                    $is_visible = true;
2397
                } else {
2398
                    $userGroups = GroupManager::getAllGroupPerUserSubscription($student_id);
2399
                    if (!empty($userGroups)) {
2400
                        foreach ($userGroups as $groupInfo) {
2401
                            $groupId = $groupInfo['iid'];
2402
2403
                            $userVisibility = api_get_item_visibility(
2404
                                $courseInfo,
2405
                                'learnpath',
2406
                                $row['id'],
2407
                                $sessionId,
2408
                                null,
2409
                                'LearnpathSubscription',
2410
                                $groupId
2411
                            );
2412
2413
                            if ($userVisibility == 1) {
2414
                                $is_visible = true;
2415
                                break;
2416
                            }
2417
                        }
2418
                    }
2419
                }
2420
            }
2421
2422
            return $is_visible;
2423
        }
2424
2425
        return false;
2426
    }
2427
2428
    /**
2429
     * @param int $lpId
2430
     * @param int $userId
2431
     * @param int $courseId
2432
     * @param int $sessionId
2433
     * @return int
2434
     */
2435
    public static function getProgress($lpId, $userId, $courseId, $sessionId = 0)
2436
    {
2437
        $lpId = intval($lpId);
2438
        $userId = intval($userId);
2439
        $courseId = intval($courseId);
2440
        $sessionId = intval($sessionId);
2441
        $progress = 0;
2442
2443
        $sessionCondition = api_get_session_condition($sessionId);
2444
        $table = Database :: get_course_table(TABLE_LP_VIEW);
2445
        $sql = "SELECT * FROM $table
2446
                WHERE
2447
                    c_id = ".$courseId." AND
2448
                    lp_id = $lpId AND
2449
                    user_id = $userId $sessionCondition";
2450
        $res = Database::query($sql);
2451
        if (Database :: num_rows($res) > 0) {
2452
            $row = Database:: fetch_array($res);
2453
            $progress = $row['progress'];
2454
        }
2455
        return $progress;
2456
2457
    }
2458
2459
    /**
2460
     * Displays a progress bar
2461
     * completed so far.
2462
     * @param	integer	$percentage Progress value to display
2463
     * @param	string	$text_add Text to display near the progress value
2464
     * @return	string	HTML string containing the progress bar
2465
     */
2466
    public static function get_progress_bar($percentage = -1, $text_add = '')
2467
    {
2468
        $text = $percentage . $text_add;
2469
        $output = '<div class="progress">
2470
                        <div id="progress_bar_value" class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="' .$percentage. '" aria-valuemin="0" aria-valuemax="100" style="width: '.$text.';">
2471
                        '. $text .'
2472
                        </div>
2473
                    </div>';
2474
2475
        return $output;
2476
    }
2477
2478
    /**
2479
     * @param string $mode can be '%' or 'abs'
2480
     * otherwise this value will be used $this->progress_bar_mode
2481
     * @return string
2482
     */
2483
    public function getProgressBar($mode = null)
2484
    {
2485
        list($percentage, $text_add) = $this->get_progress_bar_text($mode);
2486
        return self::get_progress_bar($percentage, $text_add);
2487
    }
2488
2489
    /**
2490
     * Gets the progress bar info to display inside the progress bar.
2491
     * Also used by scorm_api.php
2492
     * @param	string	$mode Mode of display (can be '%' or 'abs').abs means
2493
     * we display a number of completed elements per total elements
2494
     * @param	integer	$add Additional steps to fake as completed
2495
     * @return	list array Percentage or number and symbol (% or /xx)
2496
     */
2497
    public function get_progress_bar_text($mode = '', $add = 0)
2498
    {
2499
        if ($this->debug > 0) {
2500
            error_log('New LP - In learnpath::get_progress_bar_text()', 0);
2501
        }
2502
        if (empty($mode)) {
2503
            $mode = $this->progress_bar_mode;
2504
        }
2505
        $total_items = $this->get_total_items_count_without_chapters();
2506
        if ($this->debug > 2) {
2507
            error_log('New LP - Total items available in this learnpath: ' . $total_items, 0);
2508
        }
2509
        $completeItems = $this->get_complete_items_count();
2510
        if ($this->debug > 2) {
2511
            error_log('New LP - Items completed so far: ' . $completeItems, 0);
2512
        }
2513
        if ($add != 0) {
2514
            $completeItems += $add;
2515
            if ($this->debug > 2) {
2516
                error_log('New LP - Items completed so far (+modifier): ' . $completeItems, 0);
2517
            }
2518
        }
2519
        $text = '';
2520
        if ($completeItems > $total_items) {
2521
            $completeItems = $total_items;
2522
        }
2523
        $percentage = 0;
2524
        if ($mode == '%') {
2525
            if ($total_items > 0) {
2526
                $percentage = ((float) $completeItems / (float) $total_items) * 100;
2527
            } else {
2528
                $percentage = 0;
2529
            }
2530
            $percentage = number_format($percentage, 0);
2531
            $text = '%';
2532
        } elseif ($mode == 'abs') {
2533
            $percentage = $completeItems;
2534
            $text = '/' . $total_items;
2535
        }
2536
2537
        return array(
2538
            $percentage,
2539
            $text
2540
        );
2541
    }
2542
2543
    /**
2544
     * Gets the progress bar mode
2545
     * @return	string	The progress bar mode attribute
2546
     */
2547
    public function get_progress_bar_mode()
2548
    {
2549
        if ($this->debug > 0) {
2550
            error_log('New LP - In learnpath::get_progress_bar_mode()', 0);
2551
        }
2552
        if (!empty ($this->progress_bar_mode)) {
2553
            return $this->progress_bar_mode;
2554
        } else {
2555
            return '%';
2556
        }
2557
    }
2558
2559
    /**
2560
     * Gets the learnpath proximity (remote or local)
2561
     * @return	string	Learnpath proximity
2562
     */
2563
    public function get_proximity()
2564
    {
2565
        if ($this->debug > 0) {
2566
            error_log('New LP - In learnpath::get_proximity()', 0);
2567
        }
2568
        if (!empty ($this->proximity)) {
2569
            return $this->proximity;
2570
        } else {
2571
            return '';
2572
        }
2573
    }
2574
2575
    /**
2576
     * Gets the learnpath theme (remote or local)
2577
     * @return	string	Learnpath theme
2578
     */
2579
    public function get_theme()
2580
    {
2581
        if ($this->debug > 0) {
2582
            error_log('New LP - In learnpath::get_theme()', 0);
2583
        }
2584
        if (!empty ($this->theme)) {
2585
            return $this->theme;
2586
        } else {
2587
            return '';
2588
        }
2589
    }
2590
2591
    /**
2592
     * Gets the learnpath session id
2593
     * @return	string	Learnpath theme
2594
     */
2595
    public function get_lp_session_id()
2596
    {
2597
        if ($this->debug > 0) {
2598
            error_log('New LP - In learnpath::get_lp_session_id()', 0);
2599
        }
2600
        if (!empty ($this->lp_session_id)) {
2601
            return $this->lp_session_id;
2602
        } else {
2603
            return 0;
2604
        }
2605
    }
2606
2607
    /**
2608
     * Gets the learnpath image
2609
     * @return	string	Web URL of the LP image
2610
     */
2611
    public function get_preview_image()
2612
    {
2613
        if ($this->debug > 0) {
2614
            error_log('New LP - In learnpath::get_preview_image()', 0);
2615
        }
2616
        if (!empty($this->preview_image)) {
2617
            return $this->preview_image;
2618
        } else {
2619
            return '';
2620
        }
2621
    }
2622
2623
    /**
2624
     * @param string $size
2625
     * @param string $path_type
2626
     * @return bool|string
2627
     */
2628
    public function get_preview_image_path($size = null, $path_type = 'web')
2629
    {
2630
        $preview_image = $this->get_preview_image();
2631
        if (isset($preview_image) && !empty($preview_image)) {
2632
            $image_sys_path = api_get_path(SYS_COURSE_PATH).$this->course_info['path'].'/upload/learning_path/images/';
2633
            $image_path = api_get_path(WEB_COURSE_PATH).$this->course_info['path'].'/upload/learning_path/images/';
2634
2635
            if (isset($size)) {
2636
                $info = pathinfo($preview_image);
2637
                $image_custom_size = $info['filename'].'.'.$size.'.'.$info['extension'];
2638
                if (file_exists($image_sys_path.$image_custom_size)) {
2639
                    if ($path_type == 'web') {
2640
                        return $image_path.$image_custom_size;
2641
                    } else {
2642
                        return $image_sys_path.$image_custom_size;
2643
                    }
2644
                }
2645
            } else {
2646
                if ($path_type == 'web') {
2647
                    return $image_path.$preview_image;
2648
                } else {
2649
                    return $image_sys_path.$preview_image;
2650
                }
2651
            }
2652
        }
2653
2654
        return false;
2655
    }
2656
2657
    /**
2658
     * Gets the learnpath author
2659
     * @return string	LP's author
2660
     */
2661
    public function get_author()
2662
    {
2663
        if ($this->debug > 0) {
2664
            error_log('New LP - In learnpath::get_author()', 0);
2665
        }
2666
        if (!empty ($this->author)) {
2667
            return $this->author;
2668
        } else {
2669
            return '';
2670
        }
2671
    }
2672
2673
    /**
2674
     * Gets the learnpath author
2675
     * @return	string	LP's author
2676
     */
2677
    public function get_hide_toc_frame()
2678
    {
2679
        if ($this->debug > 0) {
2680
            error_log('New LP - In learnpath::get_author()', 0);
2681
        }
2682
        if (!empty ($this->hide_toc_frame)) {
2683
            return $this->hide_toc_frame;
2684
        } else {
2685
            return '';
2686
        }
2687
    }
2688
2689
    /**
2690
     * Generate a new prerequisites string for a given item. If this item was a sco and
2691
     * its prerequisites were strings (instead of IDs), then transform those strings into
2692
     * IDs, knowing that SCORM IDs are kept in the "ref" field of the lp_item table.
2693
     * Prefix all item IDs that end-up in the prerequisites string by "ITEM_" to use the
2694
     * same rule as the scorm_export() method
2695
     * @param	integer		Item ID
2696
     * @return	string		Prerequisites string ready for the export as SCORM
2697
     */
2698
    public function get_scorm_prereq_string($item_id)
2699
    {
2700
        if ($this->debug > 0) {
2701
            error_log('New LP - In learnpath::get_scorm_prereq_string()', 0);
2702
        }
2703
        if (!is_object($this->items[$item_id])) {
2704
            return false;
2705
        }
2706
        /** @var learnpathItem $oItem */
2707
        $oItem = $this->items[$item_id];
2708
        $prereq = $oItem->get_prereq_string();
2709
2710
        if (empty($prereq)) {
2711
            return '';
2712
        }
2713
        if (preg_match('/^\d+$/', $prereq) && is_object($this->items[$prereq])) {
2714
            // If the prerequisite is a simple integer ID and this ID exists as an item ID,
2715
            // then simply return it (with the ITEM_ prefix).
2716
            //return 'ITEM_' . $prereq;
2717
            return $this->items[$prereq]->ref;
2718
        } else {
2719
            if (isset($this->refs_list[$prereq])) {
2720
                // It's a simple string item from which the ID can be found in the refs list,
2721
                // so we can transform it directly to an ID for export.
2722
                return $this->items[$this->refs_list[$prereq]]->ref;
2723
            } else if (isset($this->refs_list['ITEM_'.$prereq])) {
2724
                return $this->items[$this->refs_list['ITEM_'.$prereq]]->ref;
2725
            } else {
2726
                // The last case, if it's a complex form, then find all the IDs (SCORM strings)
2727
                // and replace them, one by one, by the internal IDs (chamilo db)
2728
                // TODO: Modify the '*' replacement to replace the multiplier in front of it
2729
                // by a space as well.
2730
                $find = array (
2731
                    '&',
2732
                    '|',
2733
                    '~',
2734
                    '=',
2735
                    '<>',
2736
                    '{',
2737
                    '}',
2738
                    '*',
2739
                    '(',
2740
                    ')'
2741
                );
2742
                $replace = array (
2743
                    ' ',
2744
                    ' ',
2745
                    ' ',
2746
                    ' ',
2747
                    ' ',
2748
                    ' ',
2749
                    ' ',
2750
                    ' ',
2751
                    ' ',
2752
                    ' '
2753
                );
2754
                $prereq_mod = str_replace($find, $replace, $prereq);
2755
                $ids = explode(' ', $prereq_mod);
2756
                foreach ($ids as $id) {
2757
                    $id = trim($id);
2758
                    if (isset ($this->refs_list[$id])) {
2759
                        $prereq = preg_replace('/[^a-zA-Z_0-9](' . $id . ')[^a-zA-Z_0-9]/', 'ITEM_' . $this->refs_list[$id], $prereq);
2760
                    }
2761
                }
2762
2763
                return $prereq;
2764
            }
2765
        }
2766
    }
2767
2768
    /**
2769
     * Returns the XML DOM document's node
2770
     * @param	resource	Reference to a list of objects to search for the given ITEM_*
2771
     * @param	string		The identifier to look for
2772
     * @return	mixed		The reference to the element found with that identifier. False if not found
2773
     */
2774
    public function get_scorm_xml_node(& $children, $id)
2775
    {
2776
        for ($i = 0; $i < $children->length; $i++) {
2777
            $item_temp = $children->item($i);
2778
            if ($item_temp->nodeName == 'item') {
2779
                if ($item_temp->getAttribute('identifier') == $id) {
2780
                    return $item_temp;
2781
                }
2782
            }
2783
            $subchildren = $item_temp->childNodes;
2784
            if ($subchildren->length > 0) {
2785
                $val = $this->get_scorm_xml_node($subchildren, $id);
2786
                if (is_object($val)) {
2787
2788
                    return $val;
2789
                }
2790
            }
2791
        }
2792
2793
        return false;
2794
    }
2795
2796
    /**
2797
     * Returns a usable array of stats related to the current learnpath and user
2798
     * @return array	Well-formatted array containing status for the current learnpath
2799
     */
2800
    public function get_stats()
2801
    {
2802
        if ($this->debug > 0) {
2803
            error_log('New LP - In learnpath::get_stats()', 0);
2804
        }
2805
    }
2806
2807
    /**
2808
     * Static method. Can be re-implemented by children. Gives an array of statistics for
2809
     * the given course (for all learnpaths and all users)
2810
     * @param	string	Course code
2811
     * @return array	Well-formatted array containing status for the course's learnpaths
2812
     */
2813
    public function get_stats_course($course)
2814
    {
2815
        //if ($this->debug > 0) { error_log('New LP - In learnpath::get_stats_course()', 0); }
2816
        // TODO
2817
    }
2818
2819
    /**
2820
     * Static method. Can be re-implemented by children. Gives an array of statistics for
2821
     * the given course and learnpath (for all users)
2822
     * @param	string	Course code
2823
     * @param	integer	Learnpath ID
2824
     * @return array	Well-formatted array containing status for the specified learnpath
2825
     */
2826
    public function get_stats_lp($course, $lp)
2827
    {
2828
        //if ($this->debug > 0) { error_log('New LP - In learnpath::get_stats_lp()', 0); }
2829
        // TODO
2830
    }
2831
2832
    /**
2833
     * Static method. Can be re-implemented by children. Gives an array of statistics for
2834
     * the given course, learnpath and user.
2835
     * @param	string	Course code
2836
     * @param	integer	Learnpath ID
2837
     * @param	integer	User ID
2838
     * @return array	Well-formatted array containing status for the specified learnpath and user
2839
     */
2840
    public function get_stats_lp_user($course, $lp, $user)
2841
    {
2842
        //if ($this->debug > 0) { error_log('New LP - In learnpath::get_stats_lp_user()', 0); }
2843
        // TODO
2844
    }
2845
2846
    /**
2847
     * Static method. Can be re-implemented by children. Gives an array of statistics for
2848
     * the given course and learnpath (for all users)
2849
     * @param	string	Course code
2850
     * @param	integer	User ID
2851
     * @return array	Well-formatted array containing status for the user's learnpaths
2852
     */
2853
    public function get_stats_user($course, $user) {
2854
        //if ($this->debug > 0) { error_log('New LP - In learnpath::get_stats_user()', 0); }
2855
        // TODO
2856
    }
2857
2858
    /**
2859
     * Gets the status list for all LP's items
2860
     * @return	array	Array of [index] => [item ID => current status]
2861
     */
2862
    public function get_items_status_list()
2863
    {
2864
        if ($this->debug > 0) {
2865
            error_log('New LP - In learnpath::get_items_status_list()', 0);
2866
        }
2867
        $list = array ();
2868
        foreach ($this->ordered_items as $item_id) {
2869
            $list[] = array (
2870
                $item_id => $this->items[$item_id]->get_status()
2871
            );
2872
        }
2873
        return $list;
2874
    }
2875
2876
    /**
2877
     * Return the number of interactions for the given learnpath Item View ID.
2878
     * This method can be used as static.
2879
     * @param	integer	Item View ID
2880
     * @param   integer course id
2881
     * @return	integer	Number of interactions
2882
     */
2883 View Code Duplication
    public static function get_interactions_count_from_db($lp_iv_id, $course_id)
2884
    {
2885
        $table = Database :: get_course_table(TABLE_LP_IV_INTERACTION);
2886
        $lp_iv_id = intval($lp_iv_id);
2887
        $course_id = intval($course_id);
2888
2889
        $sql = "SELECT count(*) FROM $table
2890
                WHERE c_id = $course_id AND lp_iv_id = $lp_iv_id";
2891
        $res = Database::query($sql);
2892
        $num = 0;
2893
        if (Database::num_rows($res)) {
2894
            $row = Database::fetch_array($res);
2895
            $num = $row[0];
2896
        }
2897
        return $num;
2898
    }
2899
2900
    /**
2901
     * Return the interactions as an array for the given lp_iv_id.
2902
     * This method can be used as static.
2903
     * @param	integer	Learnpath Item View ID
2904
     * @return	array
2905
     * @todo 	Transcode labels instead of switching to HTML (which requires to know the encoding of the LP)
2906
     */
2907
    public static function get_iv_interactions_array($lp_iv_id)
2908
    {
2909
        $course_id = api_get_course_int_id();
2910
        $list = array();
2911
        $table = Database :: get_course_table(TABLE_LP_IV_INTERACTION);
2912
2913
        if (empty($lp_iv_id)) {
2914
            return array();
2915
        }
2916
2917
        $sql = "SELECT * FROM $table
2918
                WHERE c_id = ".$course_id." AND lp_iv_id = $lp_iv_id
2919
                ORDER BY order_id ASC";
2920
        $res = Database::query($sql);
2921
        $num = Database :: num_rows($res);
2922
        if ($num > 0) {
2923
            $list[] = array (
2924
                'order_id' => api_htmlentities(get_lang('Order'), ENT_QUOTES),
2925
                'id' => api_htmlentities(get_lang('InteractionID'), ENT_QUOTES),
2926
                'type' => api_htmlentities(get_lang('Type'), ENT_QUOTES),
2927
                'time' => api_htmlentities(get_lang('TimeFinished'), ENT_QUOTES),
2928
                'correct_responses' => api_htmlentities(get_lang('CorrectAnswers'), ENT_QUOTES),
2929
                'student_response' => api_htmlentities(get_lang('StudentResponse'), ENT_QUOTES),
2930
                'result' => api_htmlentities(get_lang('Result'), ENT_QUOTES),
2931
                'latency' => api_htmlentities(get_lang('LatencyTimeSpent'), ENT_QUOTES)
2932
            );
2933
            while ($row = Database :: fetch_array($res)) {
2934
                $list[] = array (
2935
                    'order_id' => ($row['order_id'] + 1),
2936
                    'id' => urldecode($row['interaction_id']), //urldecode because they often have %2F or stuff like that
2937
                    'type' => $row['interaction_type'],
2938
                    'time' => $row['completion_time'],
2939
                    //'correct_responses' => $row['correct_responses'],
2940
                    'correct_responses' => '', // Hide correct responses from students.
2941
                    'student_response' => $row['student_response'],
2942
                    'result' => $row['result'],
2943
                    'latency' => $row['latency']
2944
                );
2945
            }
2946
        }
2947
2948
        return $list;
2949
    }
2950
2951
    /**
2952
     * Return the number of objectives for the given learnpath Item View ID.
2953
     * This method can be used as static.
2954
     * @param	integer	Item View ID
2955
     * @return	integer	Number of objectives
2956
     */
2957 View Code Duplication
    public static function get_objectives_count_from_db($lp_iv_id, $course_id)
2958
    {
2959
        $table = Database :: get_course_table(TABLE_LP_IV_OBJECTIVE);
2960
        $course_id = intval($course_id);
2961
        $lp_iv_id = intval($lp_iv_id);
2962
        $sql = "SELECT count(*) FROM $table
2963
                WHERE c_id = $course_id AND lp_iv_id = $lp_iv_id";
2964
        //@todo seems that this always returns 0
2965
        $res = Database::query($sql);
2966
        $num = 0;
2967
        if (Database::num_rows($res)) {
2968
            $row = Database :: fetch_array($res);
2969
            $num = $row[0];
2970
        }
2971
2972
        return $num;
2973
    }
2974
2975
    /**
2976
     * Return the objectives as an array for the given lp_iv_id.
2977
     * This method can be used as static.
2978
     * @param	integer	Learnpath Item View ID
2979
     * @return	array
2980
     * @todo 	Translate labels
2981
     */
2982
    public static function get_iv_objectives_array($lp_iv_id = 0)
2983
    {
2984
        $course_id = api_get_course_int_id();
2985
        $table = Database :: get_course_table(TABLE_LP_IV_OBJECTIVE);
2986
        $sql = "SELECT * FROM $table
2987
                WHERE c_id = $course_id AND lp_iv_id = $lp_iv_id
2988
                ORDER BY order_id ASC";
2989
        $res = Database::query($sql);
2990
        $num = Database :: num_rows($res);
2991
        $list = array();
2992
        if ($num > 0) {
2993
            $list[] = array(
2994
                'order_id' => api_htmlentities(get_lang('Order'), ENT_QUOTES),
2995
                'objective_id' => api_htmlentities(get_lang('ObjectiveID'), ENT_QUOTES),
2996
                'score_raw' => api_htmlentities(get_lang('ObjectiveRawScore'), ENT_QUOTES),
2997
                'score_max' => api_htmlentities(get_lang('ObjectiveMaxScore'), ENT_QUOTES),
2998
                'score_min' => api_htmlentities(get_lang('ObjectiveMinScore'), ENT_QUOTES),
2999
                'status' => api_htmlentities(get_lang('ObjectiveStatus'), ENT_QUOTES)
3000
            );
3001
            while ($row = Database :: fetch_array($res)) {
3002
                $list[] = array (
3003
                    'order_id' => ($row['order_id'] + 1),
3004
                    'objective_id' => urldecode($row['objective_id']), // urldecode() because they often have %2F or stuff like that.
3005
                    'score_raw' => $row['score_raw'],
3006
                    'score_max' => $row['score_max'],
3007
                    'score_min' => $row['score_min'],
3008
                    'status' => $row['status']
3009
                );
3010
            }
3011
        }
3012
3013
        return $list;
3014
    }
3015
3016
    /**
3017
     * Generate and return the table of contents for this learnpath. The (flat) table returned can be
3018
     * used by get_html_toc() to be ready to display
3019
     * @return	array	TOC as a table with 4 elements per row: title, link, status and level
3020
     */
3021
    public function get_toc()
3022
    {
3023
        if ($this->debug > 0) {
3024
            error_log('learnpath::get_toc()', 0);
3025
        }
3026
        $toc = array();
3027
        foreach ($this->ordered_items as $item_id) {
3028
            if ($this->debug > 2) {
3029
                error_log('learnpath::get_toc(): getting info for item ' . $item_id, 0);
3030
            }
3031
            // TODO: Change this link generation and use new function instead.
3032
            $toc[] = array (
3033
                'id'            => $item_id,
3034
                'title'         => $this->items[$item_id]->get_title(),
3035
                'status'        => $this->items[$item_id]->get_status(),
3036
                'level'         => $this->items[$item_id]->get_level(),
3037
                'type'          => $this->items[$item_id]->get_type(),
3038
                'description'   => $this->items[$item_id]->get_description(),
3039
                'path'          => $this->items[$item_id]->get_path(),
3040
            );
3041
        }
3042
        if ($this->debug > 2) {
3043
            error_log('New LP - In learnpath::get_toc() - TOC array: ' . print_r($toc, true), 0);
3044
        }
3045
        return $toc;
3046
    }
3047
3048
    /**
3049
     * Generate and return the table of contents for this learnpath. The JS
3050
     * table returned is used inside of scorm_api.php
3051
     * @return  string  A JS array vairiable construction
3052
     */
3053
    public function get_items_details_as_js($varname = 'olms.lms_item_types')
3054
    {
3055
        if ($this->debug > 0) {
3056
            error_log('New LP - In learnpath::get_items_details_as_js()', 0);
3057
        }
3058
        $toc = $varname.' = new Array();';
3059
        foreach ($this->ordered_items as $item_id) {
3060
            $toc.= $varname."['i$item_id'] = '".$this->items[$item_id]->get_type()."';";
3061
        }
3062
        if ($this->debug > 2) {
3063
            error_log('New LP - In learnpath::get_items_details_as_js() - TOC array: ' . print_r($toc, true), 0);
3064
        }
3065
        return $toc;
3066
    }
3067
3068
    /**
3069
     * Gets the learning path type
3070
     * @param	boolean		Return the name? If false, return the ID. Default is false.
3071
     * @return	mixed		Type ID or name, depending on the parameter
3072
     */
3073
    public function get_type($get_name = false)
3074
    {
3075
        $res = false;
3076
        if ($this->debug > 0) {
3077
            error_log('New LP - In learnpath::get_type()', 0);
3078
        }
3079
        if (!empty ($this->type)) {
3080
            if ($get_name) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
3081
                // Get it from the lp_type table in main db.
3082
            } else {
3083
                $res = $this->type;
3084
            }
3085
        }
3086
        if ($this->debug > 2) {
3087
            error_log('New LP - In learnpath::get_type() - Returning ' . ($res ? $res : 'false'), 0);
3088
        }
3089
        return $res;
3090
    }
3091
3092
    /**
3093
     * Gets the learning path type as static method
3094
     * @param	boolean		Return the name? If false, return the ID. Default is false.
3095
     * @return	mixed		Type ID or name, depending on the parameter
3096
     */
3097
    public static function get_type_static($lp_id = 0)
3098
    {
3099
        $course_id = api_get_course_int_id();
3100
        $tbl_lp = Database :: get_course_table(TABLE_LP_MAIN);
3101
        $lp_id = intval($lp_id);
3102
        $sql = "SELECT lp_type FROM $tbl_lp
3103
                WHERE c_id = $course_id AND id = '" . $lp_id . "'";
3104
        $res = Database::query($sql);
3105
        if ($res === false) {
3106
            return null;
3107
        }
3108
        if (Database :: num_rows($res) <= 0) {
3109
            return null;
3110
        }
3111
        $row = Database :: fetch_array($res);
3112
        return $row['lp_type'];
3113
    }
3114
3115
    /**
3116
     * Gets a flat list of item IDs ordered for display (level by level ordered by order_display)
3117
     * This method can be used as abstract and is recursive
3118
     * @param	integer	Learnpath ID
3119
     * @param	integer	Parent ID of the items to look for
3120
     * @return	mixed	Ordered list of item IDs or false on error
3121
     */
3122
    public static function get_flat_ordered_items_list($lp, $parent = 0, $course_id = null)
3123
    {
3124
        if (empty($course_id)) {
3125
            $course_id = api_get_course_int_id();
3126
        } else {
3127
            $course_id = intval($course_id);
3128
        }
3129
        $list = array();
3130
3131
        if (empty($lp)) {
3132
            return false;
3133
        }
3134
3135
        $lp = intval($lp);
3136
        $parent = intval($parent);
3137
3138
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
3139
        $sql = "SELECT id FROM $tbl_lp_item
3140
                WHERE c_id = $course_id AND lp_id = $lp AND parent_item_id = $parent
3141
                ORDER BY display_order";
3142
3143
        $res = Database::query($sql);
3144
        while ($row = Database :: fetch_array($res)) {
3145
            $sublist = learnpath :: get_flat_ordered_items_list($lp, $row['id'], $course_id);
3146
            $list[] = $row['id'];
3147
            foreach ($sublist as $item) {
3148
                $list[] = $item;
3149
            }
3150
        }
3151
        return $list;
3152
    }
3153
3154
    /**
3155
     * @return array
3156
     */
3157
    public static function getChapterTypes()
3158
    {
3159
        return array(
3160
            'dokeos_chapter',
3161
            'dokeos_module',
3162
            'chapter',
3163
            'dir'
3164
        );
3165
    }
3166
3167
    /**
3168
     * Uses the table generated by get_toc() and returns an HTML-formatted string ready to display
3169
     * @return	string	HTML TOC ready to display
3170
     */
3171
    public function get_html_toc($toc_list = null)
3172
    {
3173
        $is_allowed_to_edit = api_is_allowed_to_edit(null, true, false, false);
3174
3175
        if ($this->debug > 0) {
3176
            error_log('In learnpath::get_html_toc()', 0);
3177
        }
3178
        if (empty($toc_list)) {
3179
            $toc_list = $this->get_toc();
3180
        }
3181
        //$html = '<div id="scorm_title" class="scorm-heading">'.Security::remove_XSS($this->get_name()) . '</div>';
3182
        $html = '<div class="scorm-body">';
3183
3184
3185
        $html .= '<div id="inner_lp_toc" class="inner_lp_toc scrollbar-light">';
3186
        require_once 'resourcelinker.inc.php';
3187
3188
        // Temporary variables.
3189
        $mycurrentitemid = $this->get_current_item_id();
3190
        $color_counter = 0;
3191
        $i = 0;
3192
3193
        foreach ($toc_list as $item) {
3194
3195
            // Style Status
3196
            $class_name = [
3197
                'not attempted' => 'scorm_not_attempted',
3198
                'incomplete' => 'scorm_not_attempted',
3199
                'failed' => 'scorm_failed',
3200
                'completed' => 'scorm_completed',
3201
                'passed' => 'scorm_completed',
3202
                'succeeded' => 'scorm_completed',
3203
                'browsed' => 'scorm_completed',
3204
            ];
3205
3206
            $scorm_color_background = 'row_odd';
3207
            $style_item = '';
3208
3209
            if ($color_counter % 2 == 0) {
3210
                $scorm_color_background = 'row_even';
3211
            }
3212
3213
            $dirTypes = self::getChapterTypes();
3214
3215
            if (in_array($item['type'], $dirTypes)) {
3216
                $scorm_color_background ='scorm_item_section ';
3217
                $style_item = '';
3218
            }
3219
            if ($item['id'] == $this->current) {
3220
                $scorm_color_background = 'scorm_item_normal '.$scorm_color_background.' scorm_highlight';
3221
            } elseif (!in_array($item['type'], $dirTypes)) {
3222
                $scorm_color_background = 'scorm_item_normal '.$scorm_color_background.' ';
3223
            }
3224
3225
            $html .= '<div id="toc_' . $item['id'] . '" class="' . $scorm_color_background . ' '.$class_name[$item['status']].' ">';
3226
3227
            // Learning path title
3228
            $title = $item['title'];
3229
            if (empty ($title)) {
3230
                $title = rl_get_resource_name(api_get_course_id(), $this->get_id(), $item['id']);
3231
            }
3232
            $title = Security::remove_XSS($title);
3233
3234
            // Learning path personalization
3235
            // build the LP tree
3236
            // The anchor atoc_ will let us center the TOC on the currently viewed item &^D
3237
            $description = $item['description'];
3238
            if (empty($description)) {
3239
                $description = $title;
3240
            }
3241
            if (in_array($item['type'], $dirTypes)) {
3242
                // Chapters
3243
                $html .= '<div class="'.$style_item.' scorm_section_level_'.$item['level'].'" title="'.$description.'" >';
3244
            } else {
3245
                $html .= '<div class="'.$style_item.' scorm_item_level_'.$item['level'].' scorm_type_'.learnpath::format_scorm_type_item($item['type']).'" title="'.$description.'" >';
3246
                $html .= '<a name="atoc_'.$item['id'].'"></a>';
3247
            }
3248
3249
            if (in_array($item['type'], $dirTypes)) {
3250
                // Chapter
3251
                // if you want to put an image before, you should use css
3252
                $html .= stripslashes($title);
3253
            } else {
3254
                $this->get_link('http', $item['id'], $toc_list);
3255
                $html .= '<a class="items-list" href="#" onclick="switch_item(' .$mycurrentitemid . ',' .$item['id'] . ');' .'return false;" >' . stripslashes($title) . '</a>';
3256
            }
3257
            $html .= "</div>";
3258
3259
            if ($scorm_color_background != '') {
3260
                $html .= '</div>';
3261
            }
3262
3263
            $color_counter++;
3264
        }
3265
        $html .= "</div>";
3266
        $html .= "</div>";
3267
        return $html;
3268
    }
3269
3270
    /**
3271
     * Returns an HTML-formatted string ready to display with teacher buttons
3272
     * in LP view menu
3273
     * @return	string	HTML TOC ready to display
3274
     */
3275
    public function get_teacher_toc_buttons()
3276
    {
3277
        $is_allowed_to_edit = api_is_allowed_to_edit(null, true, false, false);
3278
        $hide_teacher_icons_lp = api_get_configuration_value('hide_teacher_icons_lp');
3279
        $html = '';
3280
3281
        if ($is_allowed_to_edit && $hide_teacher_icons_lp == false) {
3282
            $gradebook = '';
3283
            if (!empty($_GET['gradebook'])) {
3284
                $gradebook = Security:: remove_XSS($_GET['gradebook']);
3285
            }
3286
            if ($this->get_lp_session_id() == api_get_session_id()) {
3287
                $html .= '<div id="actions_lp" class="actions_lp"><hr>';
3288
                $html .= '<div class="btn-group">';
3289
                $html .= "<a class='btn btn-sm btn-default' href='lp_controller.php?" . api_get_cidreq()."&gradebook=$gradebook&action=build&lp_id=" . $this->lp_id . "&isStudentView=false' target='_parent'>" .
3290
                    Display::returnFontAwesomeIcon('street-view') . get_lang('Overview') . "</a>";
3291
                $html .= "<a class='btn btn-sm btn-default' href='lp_controller.php?" . api_get_cidreq()."&action=add_item&type=step&lp_id=" . $this->lp_id . "&isStudentView=false' target='_parent'>" .
3292
                    Display::returnFontAwesomeIcon('pencil') . get_lang('Edit') . "</a>";
3293
                $html .= '<a class="btn btn-sm btn-default" href="lp_controller.php?'.api_get_cidreq()."&gradebook=$gradebook&action=edit&lp_id=" . $this->lp_id.'&isStudentView=false">' .
3294
                    Display::returnFontAwesomeIcon('cog') . get_lang('Settings').'</a>';
3295
                $html .= '</div>';
3296
                $html .= '</div>';
3297
            }
3298
        }
3299
        return $html;
3300
3301
    }
3302
    /**
3303
     * Gets the learnpath maker name - generally the editor's name
3304
     * @return	string	Learnpath maker name
3305
     */
3306
    public function get_maker()
3307
    {
3308
        if ($this->debug > 0) {
3309
            error_log('New LP - In learnpath::get_maker()', 0);
3310
        }
3311
        if (!empty ($this->maker)) {
3312
            return $this->maker;
3313
        } else {
3314
            return '';
3315
        }
3316
    }
3317
3318
    /**
3319
     * Gets the learnpath name/title
3320
     * @return	string	Learnpath name/title
3321
     */
3322 View Code Duplication
    public function get_name()
3323
    {
3324
        if ($this->debug > 0) {
3325
            error_log('New LP - In learnpath::get_name()', 0);
3326
        }
3327
        if (!empty ($this->name)) {
3328
            return $this->name;
3329
        } else {
3330
            return 'N/A';
3331
        }
3332
    }
3333
3334
    /**
3335
     * Gets a link to the resource from the present location, depending on item ID.
3336
     * @param	string	$type Type of link expected
3337
     * @param	integer	$item_id Learnpath item ID
3338
     * @return	string	$provided_toc Link to the lp_item resource
3339
     */
3340
    public function get_link($type = 'http', $item_id = null, $provided_toc = false)
3341
    {
3342
        $course_id = $this->get_course_int_id();
3343
3344 View Code Duplication
        if ($this->debug > 0) {
3345
            error_log('New LP - In learnpath::get_link(' . $type . ',' . $item_id . ')', 0);
3346
        }
3347 View Code Duplication
        if (empty($item_id)) {
3348
            if ($this->debug > 2) {
3349
                error_log('New LP - In learnpath::get_link() - no item id given in learnpath::get_link(), using current: ' . $this->get_current_item_id(), 0);
3350
            }
3351
            $item_id = $this->get_current_item_id();
3352
        }
3353
3354 View Code Duplication
        if (empty($item_id)) {
3355
            if ($this->debug > 2) {
3356
                error_log('New LP - In learnpath::get_link() - no current item id found in learnpath object', 0);
3357
            }
3358
            //still empty, this means there was no item_id given and we are not in an object context or
3359
            //the object property is empty, return empty link
3360
            $item_id = $this->first();
3361
            return '';
3362
        }
3363
3364
        $file = '';
3365
        $lp_table = Database::get_course_table(TABLE_LP_MAIN);
3366
        $lp_item_table = Database::get_course_table(TABLE_LP_ITEM);
3367
        $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW);
3368
        $item_id = intval($item_id);
3369
3370
        $sql = "SELECT
3371
                    l.lp_type as ltype,
3372
                    l.path as lpath,
3373
                    li.item_type as litype,
3374
                    li.path as lipath,
3375
                    li.parameters as liparams
3376
        		FROM $lp_table l
3377
                INNER JOIN $lp_item_table li
3378
                    ON (li.lp_id = l.id AND l.c_id = $course_id AND li.c_id = $course_id )
3379
        		WHERE li.id = $item_id ";
3380
        if ($this->debug > 2) {
3381
            error_log('New LP - In learnpath::get_link() - selecting item ' . $sql, 0);
3382
        }
3383
        $res = Database::query($sql);
3384
        if (Database :: num_rows($res) > 0) {
3385
            $row = Database :: fetch_array($res);
3386
            $lp_type = $row['ltype'];
3387
            $lp_path = $row['lpath'];
3388
            $lp_item_type = $row['litype'];
3389
            $lp_item_path = $row['lipath'];
3390
            $lp_item_params = $row['liparams'];
3391
3392
            if (empty($lp_item_params) && strpos($lp_item_path, '?') !== false) {
3393
                list($lp_item_path, $lp_item_params) = explode('?', $lp_item_path);
3394
            }
3395
            $sys_course_path = api_get_path(SYS_COURSE_PATH) . api_get_course_path();
3396
            if ($type == 'http') {
3397
                $course_path = api_get_path(WEB_COURSE_PATH) . api_get_course_path(); //web path
3398
            } else {
3399
                $course_path = $sys_course_path; //system path
3400
            }
3401
3402
            // Fixed issue BT#1272 - If the item type is a Chamilo Item (quiz, link, etc), then change the lp type to thread it as a normal Chamilo LP not a SCO.
3403
            if (in_array($lp_item_type, array('quiz', 'document', 'final_item', 'link', 'forum', 'thread', 'student_publication'))) {
3404
                $lp_type = 1;
3405
            }
3406
3407
            if ($this->debug > 2) {
3408
                error_log('New LP - In learnpath::get_link() - $lp_type ' . $lp_type, 0);
3409
                error_log('New LP - In learnpath::get_link() - $lp_item_type ' . $lp_item_type, 0);
3410
            }
3411
3412
            // Now go through the specific cases to get the end of the path
3413
            // @todo Use constants instead of int values.
3414
            switch ($lp_type) {
3415
                case 1 :
3416
                    if ($lp_item_type == 'dokeos_chapter') {
3417
                        $file = 'lp_content.php?type=dir';
3418
                    } else {
3419
                        require_once 'resourcelinker.inc.php';
3420
                        $file = rl_get_resource_link_for_learnpath(
3421
                            $course_id,
3422
                            $this->get_id(),
3423
                            $item_id,
3424
                            $this->get_view_id()
3425
                        );
3426
3427
                        if ($this->debug > 0) {
3428
                            error_log('rl_get_resource_link_for_learnpath - file: ' . $file, 0);
3429
                        }
3430
3431
                        if ($lp_item_type == 'link') {
3432
                            if (Link::is_youtube_link($file)) {
3433
                                $src  = Link::get_youtube_video_id($file);
3434
                                $file = api_get_path(WEB_CODE_PATH).'newscorm/embed.php?type=youtube&source='.$src;
3435
                            } elseif (Link::isVimeoLink($file)) {
3436
                                $src  = Link::getVimeoLinkId($file);
3437
                                $file = api_get_path(WEB_CODE_PATH).'newscorm/embed.php?type=vimeo&source='.$src;
3438
                            } else {
3439
                                // If the current site is HTTPS and the link is
3440
                                // HTTP, browsers will refuse opening the link
3441
                                $urlId = api_get_current_access_url_id();
3442
                                $url = api_get_access_url($urlId, false);
3443
                                $protocol = substr($url['url'], 0, 5);
3444
                                if ($protocol === 'https') {
3445
                                    $linkProtocol = substr($file, 0, 5);
3446
                                    if ($linkProtocol === 'http:') {
3447
                                        //this is the special intervention case
3448
                                        $file = api_get_path(WEB_CODE_PATH).'newscorm/embed.php?type=nonhttps&source=' .  urlencode($file);
3449
                                    }
3450
                                }
3451
                            }
3452
                        } else {
3453
                            // Check how much attempts of a exercise exits in lp
3454
                            $lp_item_id = $this->get_current_item_id();
3455
                            $lp_view_id = $this->get_view_id();
3456
3457
                            $prevent_reinit = null;
3458
                            if (isset($this->items[$this->current])) {
3459
                                $prevent_reinit = $this->items[$this->current]->get_prevent_reinit();
3460
                            }
3461
3462
                            if (empty($provided_toc)) {
3463
                                if ($this->debug > 0) {
3464
                                    error_log('In learnpath::get_link() Loading get_toc ', 0);
3465
                                }
3466
                                $list = $this->get_toc();
3467
                            } else {
3468
                                if ($this->debug > 0) {
3469
                                    error_log('In learnpath::get_link() Loading get_toc from "cache" ', 0);
3470
                                }
3471
                                $list = $provided_toc;
3472
                            }
3473
3474
                            $type_quiz = false;
3475
3476 View Code Duplication
                            foreach ($list as $toc) {
0 ignored issues
show
Bug introduced by
The expression $list of type array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
3477
                                if ($toc['id'] == $lp_item_id && ($toc['type'] == 'quiz')) {
3478
                                    $type_quiz = true;
3479
                                }
3480
                            }
3481
3482
                            if ($type_quiz) {
3483
                                $lp_item_id = intval($lp_item_id);
3484
                                $lp_view_id = intval($lp_view_id);
3485
                                $sql = "SELECT count(*) FROM $lp_item_view_table
3486
                                        WHERE
3487
                                            c_id = $course_id AND
3488
                                            lp_item_id='" . $lp_item_id . "' AND
3489
                                            lp_view_id ='" . $lp_view_id . "' AND
3490
                                            status='completed'";
3491
                                $result = Database::query($sql);
3492
                                $row_count = Database :: fetch_row($result);
3493
                                $count_item_view = (int) $row_count[0];
3494
                                $not_multiple_attempt = 0;
3495
                                if ($prevent_reinit === 1 && $count_item_view > 0) {
3496
                                    $not_multiple_attempt = 1;
3497
                                }
3498
                                $file .= '&not_multiple_attempt=' . $not_multiple_attempt;
3499
                            }
3500
3501
                            $tmp_array = explode('/', $file);
3502
                            $document_name = $tmp_array[count($tmp_array) - 1];
3503
                            if (strpos($document_name, '_DELETED_')) {
3504
                                $file = 'blank.php?error=document_deleted';
3505
                            }
3506
                        }
3507
                    }
3508
                    break;
3509
                case 2 :
3510
                    if ($this->debug > 2) {
3511
                        error_log('New LP - In learnpath::get_link() ' . __LINE__ . ' - Item type: ' . $lp_item_type, 0);
3512
                    }
3513
3514
                    if ($lp_item_type != 'dir') {
3515
                        // Quite complex here:
3516
                        // We want to make sure 'http://' (and similar) links can
3517
                        // be loaded as is (withouth the Chamilo path in front) but
3518
                        // some contents use this form: resource.htm?resource=http://blablabla
3519
                        // which means we have to find a protocol at the path's start, otherwise
3520
                        // it should not be considered as an external URL.
3521
3522
                        //if ($this->prerequisites_match($item_id)) {
3523
                        if (preg_match('#^[a-zA-Z]{2,5}://#', $lp_item_path) != 0) {
3524
                            if ($this->debug > 2) {
3525
                                error_log('New LP - In learnpath::get_link() ' . __LINE__ . ' - Found match for protocol in ' . $lp_item_path, 0);
3526
                            }
3527
                            // Distant url, return as is.
3528
                            $file = $lp_item_path;
3529
                        } else {
3530
                            if ($this->debug > 2) {
3531
                                error_log('New LP - In learnpath::get_link() ' . __LINE__ . ' - No starting protocol in ' . $lp_item_path, 0);
3532
                            }
3533
                            // Prevent getting untranslatable urls.
3534
                            $lp_item_path = preg_replace('/%2F/', '/', $lp_item_path);
3535
                            $lp_item_path = preg_replace('/%3A/', ':', $lp_item_path);
3536
                            // Prepare the path.
3537
                            $file = $course_path . '/scorm/' . $lp_path . '/' . $lp_item_path;
3538
                            // TODO: Fix this for urls with protocol header.
3539
                            $file = str_replace('//', '/', $file);
3540
                            $file = str_replace(':/', '://', $file);
3541
                            if (substr($lp_path, -1) == '/') {
3542
                                $lp_path = substr($lp_path, 0, -1);
3543
                            }
3544
3545
                            if (!is_file(realpath($sys_course_path . '/scorm/' . $lp_path . '/' . $lp_item_path))) {
3546
                                // if file not found.
3547
                                $decoded = html_entity_decode($lp_item_path);
3548
                                list ($decoded) = explode('?', $decoded);
3549
                                if (!is_file(realpath($sys_course_path . '/scorm/' . $lp_path . '/' . $decoded))) {
3550
                                    require_once 'resourcelinker.inc.php';
3551
                                    $file = rl_get_resource_link_for_learnpath(
3552
                                        $course_id,
3553
                                        $this->get_id(),
3554
                                        $item_id,
3555
                                        $this->get_view_id()
3556
                                    );
3557
                                    if (empty($file)) {
3558
                                        $file = 'blank.php?error=document_not_found';
3559
                                    } else {
3560
                                        $tmp_array = explode('/', $file);
3561
                                        $document_name = $tmp_array[count($tmp_array) - 1];
3562
                                        if (strpos($document_name, '_DELETED_')) {
3563
                                            $file = 'blank.php?error=document_deleted';
3564
                                        } else {
3565
                                            $file = 'blank.php?error=document_not_found';
3566
                                        }
3567
                                    }
3568
                                } else {
3569
                                    $file = $course_path . '/scorm/' . $lp_path . '/' . $decoded;
3570
                                }
3571
                            }
3572
                        }
3573
3574
                        // We want to use parameters if they were defined in the imsmanifest
3575
                        if (strpos($file, 'blank.php') === false) {
3576
                            $file .= (strstr($file, '?') === false ? '?' : '') . $lp_item_params;
3577
                        }
3578
                    } else {
3579
                        $file = 'lp_content.php?type=dir';
3580
                    }
3581
                    break;
3582
                case 3 :
3583
                    if ($this->debug > 2) {
3584
                        error_log('New LP - In learnpath::get_link() ' . __LINE__ . ' - Item type: ' . $lp_item_type, 0);
3585
                    }
3586
                    // Formatting AICC HACP append URL.
3587
                    $aicc_append = '?aicc_sid=' . urlencode(session_id()) . '&aicc_url=' . urlencode(api_get_path(WEB_CODE_PATH) . 'newscorm/aicc_hacp.php') . '&';
3588
                    if (!empty($lp_item_params)) {
3589
                        $aicc_append .= $lp_item_params . '&';
3590
                    }
3591
                    if ($lp_item_type != 'dir') {
3592
                        // Quite complex here:
3593
                        // We want to make sure 'http://' (and similar) links can
3594
                        // be loaded as is (withouth the Chamilo path in front) but
3595
                        // some contents use this form: resource.htm?resource=http://blablabla
3596
                        // which means we have to find a protocol at the path's start, otherwise
3597
                        // it should not be considered as an external URL.
3598
3599
                        if (preg_match('#^[a-zA-Z]{2,5}://#', $lp_item_path) != 0) {
3600
                            if ($this->debug > 2) {
3601
                                error_log('New LP - In learnpath::get_link() ' . __LINE__ . ' - Found match for protocol in ' . $lp_item_path, 0);
3602
                            }
3603
                            // Distant url, return as is.
3604
                            $file = $lp_item_path;
3605
                            // Enabled and modified by Ivan Tcholakov, 16-OCT-2008.
3606
                            /*
3607
                            if (stristr($file,'<servername>') !== false) {
3608
                                $file = str_replace('<servername>', $course_path.'/scorm/'.$lp_path.'/', $lp_item_path);
3609
                            }
3610
                            */
3611
                            if (stripos($file, '<servername>') !== false) {
3612
                                //$file = str_replace('<servername>',$course_path.'/scorm/'.$lp_path.'/',$lp_item_path);
3613
                                $web_course_path = str_replace('https://', '', str_replace('http://', '', $course_path));
3614
                                $file = str_replace('<servername>', $web_course_path . '/scorm/' . $lp_path, $lp_item_path);
3615
                            }
3616
                            //
3617
                            $file .= $aicc_append;
3618
                        } else {
3619
                            if ($this->debug > 2) {
3620
                                error_log('New LP - In learnpath::get_link() ' . __LINE__ . ' - No starting protocol in ' . $lp_item_path, 0);
3621
                            }
3622
                            // Prevent getting untranslatable urls.
3623
                            $lp_item_path = preg_replace('/%2F/', '/', $lp_item_path);
3624
                            $lp_item_path = preg_replace('/%3A/', ':', $lp_item_path);
3625
                            // Prepare the path - lp_path might be unusable because it includes the "aicc" subdir name.
3626
                            $file = $course_path . '/scorm/' . $lp_path . '/' . $lp_item_path;
3627
                            // TODO: Fix this for urls with protocol header.
3628
                            $file = str_replace('//', '/', $file);
3629
                            $file = str_replace(':/', '://', $file);
3630
                            $file .= $aicc_append;
3631
                        }
3632
                    } else {
3633
                        $file = 'lp_content.php?type=dir';
3634
                    }
3635
                    break;
3636
                case 4 :
3637
                    break;
3638
                default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
3639
                    break;
3640
            }
3641
            // Replace &amp; by & because &amp; will break URL with params
3642
            $file = !empty($file) ? str_replace('&amp;', '&', $file) : '';
3643
        }
3644
        if ($this->debug > 2) {
3645
            error_log('New LP - In learnpath::get_link() - returning "' . $file . '" from get_link', 0);
3646
        }
3647
        return $file;
3648
    }
3649
3650
    /**
3651
     * Gets the latest usable view or generate a new one
3652
     * @param	integer	Optional attempt number. If none given, takes the highest from the lp_view table
3653
     * @return	integer	DB lp_view id
3654
     */
3655
    public function get_view($attempt_num = 0)
3656
    {
3657
        if ($this->debug > 0) {
3658
            error_log('New LP - In learnpath::get_view()', 0);
3659
        }
3660
        $search = '';
3661
        // Use $attempt_num to enable multi-views management (disabled so far).
3662
        if ($attempt_num != 0 AND intval(strval($attempt_num)) == $attempt_num) {
3663
            $search = 'AND view_count = ' . $attempt_num;
3664
        }
3665
        // When missing $attempt_num, search for a unique lp_view record for this lp and user.
3666
        $lp_view_table = Database :: get_course_table(TABLE_LP_VIEW);
3667
3668
        $course_id = api_get_course_int_id();
3669
        $sessionId = api_get_session_id();
3670
3671
        $sql = "SELECT id, view_count FROM $lp_view_table
3672
        		WHERE
3673
        		    c_id = " . $course_id . " AND
3674
        		    lp_id = " . $this->get_id() . " AND
3675
        		    user_id = " . $this->get_user_id() . " AND
3676
        		    session_id = $sessionId
3677
        		    $search
3678
                ORDER BY view_count DESC";
3679
        $res = Database::query($sql);
3680
        if (Database :: num_rows($res) > 0) {
3681
            $row = Database :: fetch_array($res);
3682
            $this->lp_view_id = $row['id'];
3683
        } else if (!api_is_invitee()) {
3684
            // There is no database record, create one.
3685
            $sql = "INSERT INTO $lp_view_table (c_id, lp_id,user_id, view_count, session_id) VALUES
3686
            		($course_id, " . $this->get_id() . "," . $this->get_user_id() . ", 1, $sessionId)";
3687
            Database::query($sql);
3688
            $id = Database :: insert_id();
3689
            $this->lp_view_id = $id;
3690
3691
            $sql = "UPDATE $lp_view_table SET id = iid WHERE iid = $id";
3692
            Database::query($sql);
3693
        }
3694
3695
        return $this->lp_view_id;
3696
    }
3697
3698
    /**
3699
     * Gets the current view id
3700
     * @return	integer	View ID (from lp_view)
3701
     */
3702
    public function get_view_id()
3703
    {
3704
        if ($this->debug > 0) {
3705
            error_log('New LP - In learnpath::get_view_id()', 0);
3706
        }
3707
        if (!empty ($this->lp_view_id)) {
3708
            return $this->lp_view_id;
3709
        } else {
3710
            return 0;
3711
        }
3712
    }
3713
3714
    /**
3715
     * Gets the update queue
3716
     * @return	array	Array containing IDs of items to be updated by JavaScript
3717
     */
3718
    public function get_update_queue()
3719
    {
3720
        if ($this->debug > 0) {
3721
            error_log('New LP - In learnpath::get_update_queue()', 0);
3722
        }
3723
        return $this->update_queue;
3724
    }
3725
3726
    /**
3727
     * Gets the user ID
3728
     * @return	integer	User ID
3729
     */
3730 View Code Duplication
    public function get_user_id()
3731
    {
3732
        if ($this->debug > 0) {
3733
            error_log('New LP - In learnpath::get_user_id()', 0);
3734
        }
3735
        if (!empty ($this->user_id)) {
3736
            return $this->user_id;
3737
        } else {
3738
            return false;
3739
        }
3740
    }
3741
3742
    /**
3743
     * Checks if any of the items has an audio element attached
3744
     * @return  bool    True or false
3745
     */
3746
    public function has_audio()
3747
    {
3748
        if ($this->debug > 1) {
3749
            error_log('New LP - In learnpath::has_audio()', 0);
3750
        }
3751
        $has = false;
3752
        foreach ($this->items as $i => $item) {
3753
            if (!empty ($this->items[$i]->audio)) {
3754
                $has = true;
3755
                break;
3756
            }
3757
        }
3758
        return $has;
3759
    }
3760
3761
    /**
3762
     * Logs a message into a file
3763
     * @param	string 	Message to log
3764
     * @return	boolean	True on success, false on error or if msg empty
3765
     */
3766
    public function log($msg)
3767
    {
3768
        if ($this->debug > 0) {
3769
            error_log('New LP - In learnpath::log()', 0);
3770
        }
3771
        // TODO
3772
        $this->error .= $msg;
3773
        return true;
3774
    }
3775
3776
    /**
3777
     * Moves an item up and down at its level
3778
     * @param	integer	Item to move up and down
3779
     * @param	string	Direction 'up' or 'down'
3780
     * @return	integer	New display order, or false on error
3781
     */
3782
    public function move_item($id, $direction)
3783
    {
3784
        $course_id = api_get_course_int_id();
3785
        if ($this->debug > 0) {
3786
            error_log('New LP - In learnpath::move_item(' . $id . ',' . $direction . ')', 0);
3787
        }
3788
        if (empty($id) || empty($direction)) {
3789
            return false;
3790
        }
3791
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
3792
        $sql_sel = "SELECT *
3793
                    FROM " . $tbl_lp_item . "
3794
                    WHERE c_id = ".$course_id." AND id = " . $id;
3795
        $res_sel = Database::query($sql_sel);
3796
        // Check if elem exists.
3797
        if (Database :: num_rows($res_sel) < 1) {
3798
            return false;
3799
        }
3800
        // Gather data.
3801
        $row = Database :: fetch_array($res_sel);
3802
        $previous = $row['previous_item_id'];
3803
        $next = $row['next_item_id'];
3804
        $display = $row['display_order'];
3805
        $parent = $row['parent_item_id'];
3806
        $lp = $row['lp_id'];
3807
        // Update the item (switch with previous/next one).
3808
        switch ($direction) {
3809
            case 'up':
3810
                if ($this->debug > 2) {
3811
                    error_log('Movement up detected', 0);
3812
                }
3813
                if ($display <= 1) { /*do nothing*/
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
3814
                } else {
3815
                    $sql_sel2 = "SELECT * FROM $tbl_lp_item
3816
                                 WHERE c_id = ".$course_id." AND id = $previous";
3817
3818
                    if ($this->debug > 2) {
3819
                        error_log('Selecting previous: ' . $sql_sel2, 0);
3820
                    }
3821
                    $res_sel2 = Database::query($sql_sel2);
3822
                    if (Database :: num_rows($res_sel2) < 1) {
3823
                        $previous_previous = 0;
3824
                    }
3825
                    // Gather data.
3826
                    $row2 = Database :: fetch_array($res_sel2);
3827
                    $previous_previous = $row2['previous_item_id'];
3828
                    // Update previous_previous item (switch "next" with current).
3829 View Code Duplication
                    if ($previous_previous != 0) {
3830
                        $sql_upd2 = "UPDATE $tbl_lp_item SET
3831
                                        next_item_id = $id
3832
                                    WHERE c_id = ".$course_id." AND id = $previous_previous";
3833
                        if ($this->debug > 2) {
3834
                            error_log($sql_upd2, 0);
3835
                        }
3836
                        Database::query($sql_upd2);
3837
                    }
3838
                    // Update previous item (switch with current).
3839 View Code Duplication
                    if ($previous != 0) {
3840
                        $sql_upd2 = "UPDATE $tbl_lp_item SET
3841
                                    next_item_id = $next,
3842
                                    previous_item_id = $id,
3843
                                    display_order = display_order +1
3844
                                    WHERE c_id = ".$course_id." AND id = $previous";
3845
                        if ($this->debug > 2) {
3846
                            error_log($sql_upd2, 0);
3847
                        }
3848
                        Database::query($sql_upd2);
3849
                    }
3850
3851
                    // Update current item (switch with previous).
3852 View Code Duplication
                    if ($id != 0) {
3853
                        $sql_upd2 = "UPDATE $tbl_lp_item SET
3854
                                        next_item_id = $previous,
3855
                                        previous_item_id = $previous_previous,
3856
                                        display_order = display_order-1
3857
                                    WHERE c_id = ".$course_id." AND id = $id";
3858
                        if ($this->debug > 2) {
3859
                            error_log($sql_upd2, 0);
3860
                        }
3861
                        Database::query($sql_upd2);
3862
                    }
3863
                    // Update next item (new previous item).
3864 View Code Duplication
                    if ($next != 0) {
3865
                        $sql_upd2 = "UPDATE $tbl_lp_item SET previous_item_id = $previous
3866
                                     WHERE c_id = ".$course_id." AND id = $next";
3867
                        if ($this->debug > 2) {
3868
                            error_log($sql_upd2, 0);
3869
                        }
3870
                        Database::query($sql_upd2);
3871
                    }
3872
                    $display = $display -1;
3873
                }
3874
                break;
3875
            case 'down':
3876
                if ($this->debug > 2) {
3877
                    error_log('Movement down detected', 0);
3878
                }
3879
                if ($next == 0) { /* Do nothing. */
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
3880
                } else {
3881
                    $sql_sel2 = "SELECT * FROM $tbl_lp_item WHERE c_id = ".$course_id." AND id = $next";
3882
                    if ($this->debug > 2) {
3883
                        error_log('Selecting next: ' . $sql_sel2, 0);
3884
                    }
3885
                    $res_sel2 = Database::query($sql_sel2);
3886
                    if (Database :: num_rows($res_sel2) < 1) {
3887
                        $next_next = 0;
3888
                    }
3889
                    // Gather data.
3890
                    $row2 = Database :: fetch_array($res_sel2);
3891
                    $next_next = $row2['next_item_id'];
3892
                    // Update previous item (switch with current).
3893 View Code Duplication
                    if ($previous != 0) {
3894
                        $sql_upd2 = "UPDATE $tbl_lp_item SET next_item_id = $next
3895
                                     WHERE c_id = ".$course_id." AND id = $previous";
3896
                        Database::query($sql_upd2);
3897
                    }
3898
                    // Update current item (switch with previous).
3899 View Code Duplication
                    if ($id != 0) {
3900
                        $sql_upd2 = "UPDATE $tbl_lp_item SET
3901
                                     previous_item_id = $next, next_item_id = $next_next, display_order = display_order+1
3902
                                     WHERE c_id = ".$course_id." AND id = $id";
3903
                        Database::query($sql_upd2);
3904
                    }
3905
3906
                    // Update next item (new previous item).
3907 View Code Duplication
                    if ($next != 0) {
3908
                        $sql_upd2 = "UPDATE $tbl_lp_item SET
3909
                                     previous_item_id = $previous, next_item_id = $id, display_order = display_order-1
3910
                                     WHERE c_id = ".$course_id." AND id = $next";
3911
                        Database::query($sql_upd2);
3912
                    }
3913
3914
                    // Update next_next item (switch "previous" with current).
3915 View Code Duplication
                    if ($next_next != 0) {
3916
                        $sql_upd2 = "UPDATE $tbl_lp_item SET
3917
                                     previous_item_id = $id
3918
                                     WHERE c_id = ".$course_id." AND id = $next_next";
3919
                        Database::query($sql_upd2);
3920
                    }
3921
                    $display = $display +1;
3922
                }
3923
                break;
3924
            default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
3925
                return false;
3926
        }
3927
        return $display;
3928
    }
3929
3930
    /**
3931
     * Move a learnpath up (display_order)
3932
     * @param	integer	$lp_id Learnpath ID
3933
     */
3934
    public static function move_up($lp_id)
3935
    {
3936
        $course_id = api_get_course_int_id();
3937
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
3938
        $sql = "SELECT * FROM $lp_table
3939
                WHERE c_id = ".$course_id."
3940
                ORDER BY display_order";
3941
        $res = Database::query($sql);
3942
        if ($res === false)
3943
            return false;
3944
        $lps = array ();
3945
        $lp_order = array ();
3946
        $num = Database :: num_rows($res);
3947
        // First check the order is correct, globally (might be wrong because
3948
        // of versions < 1.8.4)
3949 View Code Duplication
        if ($num > 0) {
3950
            $i = 1;
3951
            while ($row = Database :: fetch_array($res)) {
3952
                if ($row['display_order'] != $i) { // If we find a gap in the order, we need to fix it.
3953
                    $need_fix = true;
3954
                    $sql_u = "UPDATE $lp_table SET display_order = $i
3955
                              WHERE c_id = ".$course_id." AND id = " . $row['id'];
3956
                    Database::query($sql_u);
3957
                }
3958
                $row['display_order'] = $i;
3959
                $lps[$row['id']] = $row;
3960
                $lp_order[$i] = $row['id'];
3961
                $i++;
3962
            }
3963
        }
3964
        if ($num > 1) { // If there's only one element, no need to sort.
3965
            $order = $lps[$lp_id]['display_order'];
3966
            if ($order > 1) { // If it's the first element, no need to move up.
3967
                $sql_u1 = "UPDATE $lp_table SET display_order = $order
3968
                           WHERE c_id = ".$course_id." AND id = " . $lp_order[$order - 1];
3969
                Database::query($sql_u1);
3970
                $sql_u2 = "UPDATE $lp_table SET display_order = " . ($order - 1) . "
3971
                           WHERE c_id = ".$course_id." AND id = " . $lp_id;
3972
                Database::query($sql_u2);
3973
            }
3974
        }
3975
    }
3976
3977
    /**
3978
     * Move a learnpath down (display_order)
3979
     * @param	integer	$lp_id Learnpath ID
3980
     */
3981
    public static function move_down($lp_id)
3982
    {
3983
        $course_id = api_get_course_int_id();
3984
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
3985
        $sql = "SELECT * FROM $lp_table
3986
                WHERE c_id = ".$course_id."
3987
                ORDER BY display_order";
3988
        $res = Database::query($sql);
3989
        if ($res === false) {
3990
            return false;
3991
        }
3992
        $lps = array ();
3993
        $lp_order = array ();
3994
        $num = Database :: num_rows($res);
3995
        $max = 0;
3996
        // First check the order is correct, globally (might be wrong because
3997
        // of versions < 1.8.4).
3998 View Code Duplication
        if ($num > 0) {
3999
            $i = 1;
4000
            while ($row = Database :: fetch_array($res)) {
4001
                $max = $i;
4002
                if ($row['display_order'] != $i) { // If we find a gap in the order, we need to fix it.
4003
                    $need_fix = true;
4004
                    $sql_u = "UPDATE $lp_table SET display_order = $i
4005
                              WHERE c_id = ".$course_id." AND id = " . $row['id'];
4006
                    Database::query($sql_u);
4007
                }
4008
                $row['display_order'] = $i;
4009
                $lps[$row['id']] = $row;
4010
                $lp_order[$i] = $row['id'];
4011
                $i++;
4012
            }
4013
        }
4014
        if ($num > 1) { // If there's only one element, no need to sort.
4015
            $order = $lps[$lp_id]['display_order'];
4016
            if ($order < $max) { // If it's the first element, no need to move up.
4017
                $sql_u1 = "UPDATE $lp_table SET display_order = $order
4018
                           WHERE c_id = ".$course_id." AND id = " . $lp_order[$order + 1];
4019
                Database::query($sql_u1);
4020
                $sql_u2 = "UPDATE $lp_table SET display_order = " . ($order + 1) . "
4021
                           WHERE c_id = ".$course_id." AND id = " . $lp_id;
4022
                Database::query($sql_u2);
4023
            }
4024
        }
4025
    }
4026
4027
    /**
4028
     * Updates learnpath attributes to point to the next element
4029
     * The last part is similar to set_current_item but processing the other way around
4030
     */
4031
    public function next()
4032
    {
4033
        if ($this->debug > 0) {
4034
            error_log('New LP - In learnpath::next()', 0);
4035
        }
4036
        $this->last = $this->get_current_item_id();
4037
        $this->items[$this->last]->save(false, $this->prerequisites_match($this->last));
4038
        $this->autocomplete_parents($this->last);
4039
        $new_index = $this->get_next_index();
4040
        if ($this->debug > 2) {
4041
            error_log('New LP - New index: ' . $new_index, 0);
4042
        }
4043
        $this->index = $new_index;
4044
        if ($this->debug > 2) {
4045
            error_log('New LP - Now having orderedlist[' . $new_index . '] = ' . $this->ordered_items[$new_index], 0);
4046
        }
4047
        $this->current = $this->ordered_items[$new_index];
4048
        if ($this->debug > 2) {
4049
            error_log('New LP - new item id is ' . $this->current . '-' . $this->get_current_item_id(), 0);
4050
        }
4051
    }
4052
4053
    /**
4054
     * Open a resource = initialise all local variables relative to this resource. Depending on the child
4055
     * class, this might be redefined to allow several behaviours depending on the document type.
4056
     * @param integer Resource ID
4057
     * @return boolean True on success, false otherwise
4058
     */
4059
    public function open($id)
4060
    {
4061
        if ($this->debug > 0) {
4062
            error_log('New LP - In learnpath::open()', 0);
4063
        }
4064
        // TODO:
4065
        // set the current resource attribute to this resource
4066
        // switch on element type (redefine in child class?)
4067
        // set status for this item to "opened"
4068
        // start timer
4069
        // initialise score
4070
        $this->index = 0; //or = the last item seen (see $this->last)
4071
    }
4072
4073
    /**
4074
     * Check that all prerequisites are fulfilled. Returns true and an
4075
     * empty string on succes, returns false
4076
     * and the prerequisite string on error.
4077
     * This function is based on the rules for aicc_script language as
4078
     * described in the SCORM 1.2 CAM documentation page 108.
4079
     * @param	integer	$itemId Optional item ID. If none given, uses the current open item.
4080
     * @return	boolean	True if prerequisites are matched, false otherwise -
4081
     * Empty string if true returned, prerequisites string otherwise.
4082
     */
4083
    public function prerequisites_match($itemId = null)
4084
    {
4085
        $debug = $this->debug;
4086
        if ($debug > 0) {
4087
            error_log('In learnpath::prerequisites_match()', 0);
4088
        }
4089
4090
        if (empty($itemId)) {
4091
            $itemId = $this->current;
4092
        }
4093
4094
        $currentItem = $this->getItem($itemId);
4095
4096
        if ($currentItem) {
4097
            if ($this->type == 2) {
4098
                // Getting prereq from scorm
4099
                $prereq_string = $this->get_scorm_prereq_string($itemId);
4100
            } else {
4101
                $prereq_string = $currentItem->get_prereq_string();
4102
            }
4103
4104
            if (empty($prereq_string)) {
4105
                if ($debug > 0) {
4106
                    error_log('Found prereq_string is empty return true');
4107
                }
4108
                return true;
4109
            }
4110
            // Clean spaces.
4111
            $prereq_string = str_replace(' ', '', $prereq_string);
4112
            if ($debug > 0) {
4113
                error_log('Found prereq_string: ' . $prereq_string, 0);
4114
            }
4115
            // Now send to the parse_prereq() function that will check this component's prerequisites.
4116
            $result = $currentItem->parse_prereq(
4117
                $prereq_string,
4118
                $this->items,
4119
                $this->refs_list,
4120
                $this->get_user_id()
4121
            );
4122
4123
            if ($result === false) {
4124
                $this->set_error_msg($currentItem->prereq_alert);
4125
            }
4126
        } else {
4127
            $result = true;
4128
            if ($debug > 1) {
4129
                error_log('$this->items[' . $itemId . '] was not an object', 0);
4130
            }
4131
        }
4132
4133
        if ($debug > 1) {
4134
            error_log('End of prerequisites_match(). Error message is now ' . $this->error, 0);
4135
        }
4136
        return $result;
4137
    }
4138
4139
    /**
4140
     * Updates learnpath attributes to point to the previous element
4141
     * The last part is similar to set_current_item but processing the other way around
4142
     */
4143
    public function previous()
4144
    {
4145
        if ($this->debug > 0) {
4146
            error_log('New LP - In learnpath::previous()', 0);
4147
        }
4148
        $this->last = $this->get_current_item_id();
4149
        $this->items[$this->last]->save(false, $this->prerequisites_match($this->last));
4150
        $this->autocomplete_parents($this->last);
4151
        $new_index = $this->get_previous_index();
4152
        $this->index = $new_index;
4153
        $this->current = $this->ordered_items[$new_index];
4154
    }
4155
4156
    /**
4157
     * Publishes a learnpath. This basically means show or hide the learnpath
4158
     * to normal users.
4159
     * Can be used as abstract
4160
     * @param	integer	Learnpath ID
4161
     * @param	string	New visibility
4162
     */
4163
    public static function toggle_visibility($lp_id, $set_visibility = 1)
4164
    {
4165
        $action = 'visible';
4166
        if ($set_visibility != 1) {
4167
            $action = 'invisible';
4168
            self::toggle_publish($lp_id, 'i');
4169
        }
4170
4171
        return api_item_property_update(
4172
            api_get_course_info(),
4173
            TOOL_LEARNPATH,
4174
            $lp_id,
4175
            $action,
4176
            api_get_user_id()
4177
        );
4178
    }
4179
4180
    /**
4181
     * Publishes a learnpath. This basically means show or hide the learnpath
4182
     * on the course homepage
4183
     * Can be used as abstract
4184
     * @param	integer	$lp_id Learnpath id
4185
     * @param	string	$set_visibility New visibility (v/i - visible/invisible)
4186
     * @return bool
4187
     */
4188
    public static function toggle_publish($lp_id, $set_visibility = 'v')
4189
    {
4190
        $course_id = api_get_course_int_id();
4191
        $tbl_lp = Database :: get_course_table(TABLE_LP_MAIN);
4192
        $lp_id = intval($lp_id);
4193
        $sql = "SELECT * FROM $tbl_lp
4194
                WHERE c_id = ".$course_id." AND id = $lp_id";
4195
        $result = Database::query($sql);
4196
        if (Database::num_rows($result)) {
4197
            $row = Database :: fetch_array($result);
4198
            $name = domesticate($row['name']);
4199
            if ($set_visibility == 'i') {
4200
                $s = $name . " " . get_lang('LearnpathNotPublished');
4201
                $dialogBox = $s;
4202
                $v = 0;
4203
            }
4204
            if ($set_visibility == 'v') {
4205
                $s = $name . " " . get_lang('LearnpathPublished');
4206
                $dialogBox = $s;
4207
                $v = 1;
4208
            }
4209
        } else {
4210
            return false;
4211
        }
4212
4213
        $session_id = api_get_session_id();
4214
        $session_condition = api_get_session_condition($session_id);
4215
4216
        $tbl_tool = Database :: get_course_table(TABLE_TOOL_LIST);
4217
        $link = 'newscorm/lp_controller.php?action=view&lp_id='.$lp_id.'&id_session='.$session_id;
4218
        $sql = "SELECT * FROM $tbl_tool
4219
                WHERE
4220
                    c_id = ".$course_id." AND
4221
                    link='$link' and
4222
                    image='scormbuilder.gif' and
4223
                    link LIKE '$link%'
4224
                    $session_condition
4225
                ";
4226
        $result = Database::query($sql);
4227
        $num = Database :: num_rows($result);
4228
        if ($set_visibility == 'i' && $num > 0) {
4229
            $sql = "DELETE FROM $tbl_tool
4230
                    WHERE c_id = ".$course_id." AND (link='$link' and image='scormbuilder.gif' $session_condition)";
4231
            Database::query($sql);
4232
4233
        } elseif ($set_visibility == 'v' && $num == 0) {
4234
            $sql = "INSERT INTO $tbl_tool (category, c_id, name, link, image, visibility, admin, address, added_tool, session_id) VALUES
4235
            	    ('authoring', $course_id, '$name', '$link', 'scormbuilder.gif', '$v', '0','pastillegris.gif', 0, $session_id)";
4236
            Database::query($sql);
4237
4238
            $insertId = Database::insert_id();
4239
            if ($insertId) {
4240
                $sql = "UPDATE $tbl_tool SET id = iid WHERE iid = $insertId";
4241
                Database::query($sql);
4242
            }
4243
        } elseif ($set_visibility == 'v' && $num > 0) {
4244
            $sql = "UPDATE $tbl_tool SET
4245
                        c_id = $course_id,
4246
                        name = '$name',
4247
                        link = '$link',
4248
                        image = 'scormbuilder.gif',
4249
                        visibility = '$v',
4250
                        admin = '0',
4251
                        address = 'pastillegris.gif',
4252
                        added_tool = 0,
4253
                        session_id = $session_id
4254
            	    WHERE
4255
            	        c_id = ".$course_id." AND
4256
            	        (link='$link' and image='scormbuilder.gif' $session_condition)
4257
                    ";
4258
            Database::query($sql);
4259
        } else {
4260
            // Parameter and database incompatible, do nothing, exit.
4261
            return false;
4262
        }
4263
4264
    }
4265
4266
    /**
4267
     * Restart the whole learnpath. Return the URL of the first element.
4268
     * Make sure the results are saved with anoter method. This method should probably be
4269
     * redefined in children classes.
4270
     * To use a similar method  statically, use the create_new_attempt() method
4271
     * @return string URL to load in the viewer
4272
     */
4273
    public function restart()
4274
    {
4275
        if ($this->debug > 0) {
4276
            error_log('New LP - In learnpath::restart()', 0);
4277
        }
4278
        // TODO
4279
        // Call autosave method to save the current progress.
4280
        //$this->index = 0;
4281
        if (api_is_invitee()) {
4282
            return false;
4283
        }
4284
        $session_id = api_get_session_id();
4285
        $course_id = api_get_course_int_id();
4286
        $lp_view_table = Database :: get_course_table(TABLE_LP_VIEW);
4287
        $sql = "INSERT INTO $lp_view_table (c_id, lp_id, user_id, view_count, session_id)
4288
                VALUES ($course_id, " . $this->lp_id . "," . $this->get_user_id() . "," . ($this->attempt + 1) . ", $session_id)";
4289
        if ($this->debug > 2) {
4290
            error_log('New LP - Inserting new lp_view for restart: ' . $sql, 0);
4291
        }
4292
        $res = Database::query($sql);
4293
        $view_id = Database::insert_id();
4294
4295
        if ($view_id) {
4296
4297
            $sql = "UPDATE $lp_view_table SET id = iid WHERE iid = $view_id";
4298
            Database::query($sql);
4299
4300
            $this->lp_view_id = $view_id;
4301
            $this->attempt = $this->attempt + 1;
4302
        } else {
4303
            $this->error = 'Could not insert into item_view table...';
4304
            return false;
4305
        }
4306
        $this->autocomplete_parents($this->current);
4307
        foreach ($this->items as $index => $dummy) {
4308
            $this->items[$index]->restart();
4309
            $this->items[$index]->set_lp_view($this->lp_view_id);
4310
        }
4311
        $this->first();
4312
4313
        return true;
4314
    }
4315
4316
    /**
4317
     * Saves the current item
4318
     * @return	boolean
4319
     */
4320
    public function save_current()
4321
    {
4322
        if ($this->debug > 0) {
4323
            error_log('learnpath::save_current()', 0);
4324
        }
4325
        // TODO: Do a better check on the index pointing to the right item (it is supposed to be working
4326
        // on $ordered_items[] but not sure it's always safe to use with $items[]).
4327
        if ($this->debug > 2) {
4328
            error_log('New LP - save_current() saving item ' . $this->current, 0);
4329
        }
4330
        if ($this->debug > 2) {
4331
            error_log('' . print_r($this->items, true), 0);
4332
        }
4333
        if (isset($this->items[$this->current]) &&
4334
            is_object($this->items[$this->current])
4335
        ) {
4336
            $res = $this->items[$this->current]->save(false, $this->prerequisites_match($this->current));
4337
            $this->autocomplete_parents($this->current);
4338
            $status = $this->items[$this->current]->get_status();
4339
            $this->update_queue[$this->current] = $status;
4340
            return $res;
4341
        }
4342
        return false;
4343
    }
4344
4345
    /**
4346
     * Saves the given item
4347
     * @param	integer	$item_id. Optional (will take from $_REQUEST if null)
0 ignored issues
show
Documentation introduced by
There is no parameter named $item_id.. Did you maybe mean $item_id?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
4348
     * @param	boolean	$from_outside Save from url params (true) or from current attributes (false). Optional. Defaults to true
4349
     * @return	boolean
4350
     */
4351
    public function save_item($item_id = null, $from_outside = true)
4352
    {
4353
        $debug = $this->debug;
4354
        if ($debug) {
4355
            error_log('In learnpath::save_item(' . $item_id . ',' . intval($from_outside). ')', 0);
4356
        }
4357
        // TODO: Do a better check on the index pointing to the right item (it is supposed to be working
4358
        // on $ordered_items[] but not sure it's always safe to use with $items[]).
4359
        if (empty($item_id)) {
4360
            $item_id = intval($_REQUEST['id']);
4361
        }
4362
        if (empty($item_id)) {
4363
            $item_id = $this->get_current_item_id();
4364
        }
4365
        if (isset($this->items[$item_id]) && is_object($this->items[$item_id])) {
4366
            if ($debug) {
4367
                error_log('Object exists');
4368
            }
4369
4370
            // Saving the item.
4371
            $res = $this->items[$item_id]->save(
4372
                $from_outside,
4373
                $this->prerequisites_match($item_id)
4374
            );
4375
4376
            if ($debug) {
4377
                error_log('update_queue before:');
4378
                error_log(print_r($this->update_queue,1));
4379
            }
4380
            $this->autocomplete_parents($item_id);
4381
4382
            $status = $this->items[$item_id]->get_status();
4383
            $this->update_queue[$item_id] = $status;
4384
4385
            if ($debug) {
4386
                error_log('get_status(): ' . $status);
4387
                error_log('update_queue after:');
4388
                error_log(print_r($this->update_queue,1));
4389
            }
4390
            return $res;
4391
        }
4392
        return false;
4393
    }
4394
4395
    /**
4396
     * Saves the last item seen's ID only in case
4397
     */
4398
    public function save_last()
4399
    {
4400
        $course_id = api_get_course_int_id();
4401
        if ($this->debug > 0) {
4402
            error_log('New LP - In learnpath::save_last()', 0);
4403
        }
4404
        $session_condition = api_get_session_condition(api_get_session_id(), true, false);
4405
        $table = Database :: get_course_table(TABLE_LP_VIEW);
4406
4407
        if (isset($this->current) && !api_is_invitee()) {
4408
            if ($this->debug > 2) {
4409
                error_log('New LP - Saving current item (' . $this->current . ') for later review', 0);
4410
            }
4411
            $sql = "UPDATE $table SET
4412
                        last_item = " . intval($this->get_current_item_id()). "
4413
                    WHERE
4414
                        c_id = $course_id AND
4415
                        lp_id = " . $this->get_id() . " AND
4416
                        user_id = " . $this->get_user_id()." ".$session_condition;
4417
4418
            if ($this->debug > 2) {
4419
                error_log('New LP - Saving last item seen : ' . $sql, 0);
4420
            }
4421
            Database::query($sql);
4422
        }
4423
4424
        if (!api_is_invitee()) {
4425
            // Save progress.
4426
            list($progress, $text) = $this->get_progress_bar_text('%');
0 ignored issues
show
Unused Code introduced by
The assignment to $text is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
4427
            if ($progress >= 0 && $progress <= 100) {
4428
                $progress = (int) $progress;
4429
                $sql = "UPDATE $table SET
4430
                            progress = $progress
4431
                        WHERE
4432
                            c_id = ".$course_id." AND
4433
                            lp_id = " . $this->get_id() . " AND
4434
                            user_id = " . $this->get_user_id()." ".$session_condition;
4435
                // Ignore errors as some tables might not have the progress field just yet.
4436
                Database::query($sql);
4437
                $this->progress_db = $progress;
0 ignored issues
show
Documentation Bug introduced by
The property $progress_db was declared of type string, but $progress is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
4438
            }
4439
        }
4440
    }
4441
4442
    /**
4443
     * Sets the current item ID (checks if valid and authorized first)
4444
     * @param	integer	$item_id New item ID. If not given or not authorized, defaults to current
4445
     */
4446
    public function set_current_item($item_id = null)
4447
    {
4448
        if ($this->debug > 0) {
4449
            error_log('New LP - In learnpath::set_current_item(' . $item_id . ')', 0);
4450
        }
4451
        if (empty ($item_id)) {
4452
            if ($this->debug > 2) {
4453
                error_log('New LP - No new current item given, ignore...', 0);
4454
            }
4455
            // Do nothing.
4456
        } else {
4457
            if ($this->debug > 2) {
4458
                error_log('New LP - New current item given is ' . $item_id . '...', 0);
4459
            }
4460
            if (is_numeric($item_id)) {
4461
                $item_id = intval($item_id);
4462
                // TODO: Check in database here.
4463
                $this->last = $this->current;
4464
                $this->current = $item_id;
4465
                // TODO: Update $this->index as well.
4466
                foreach ($this->ordered_items as $index => $item) {
4467
                    if ($item == $this->current) {
4468
                        $this->index = $index;
4469
                        break;
4470
                    }
4471
                }
4472 View Code Duplication
                if ($this->debug > 2) {
4473
                    error_log('New LP - set_current_item(' . $item_id . ') done. Index is now : ' . $this->index, 0);
4474
                }
4475
            } else {
4476
                error_log('New LP - set_current_item(' . $item_id . ') failed. Not a numeric value: ', 0);
4477
            }
4478
        }
4479
    }
4480
4481
    /**
4482
     * Sets the encoding
4483
     * @param	string	New encoding
4484
     * TODO (as of Chamilo 1.8.8): Check in the future whether this method is needed.
4485
     */
4486
    public function set_encoding($enc = 'UTF-8')
4487
    {
4488
        if ($this->debug > 0) {
4489
            error_log('New LP - In learnpath::set_encoding()', 0);
4490
        }
4491
4492
        $course_id = api_get_course_int_id();
4493
        $enc = api_refine_encoding_id($enc);
4494
        if (empty($enc)) {
4495
            $enc = api_get_system_encoding();
4496
        }
4497
        if (api_is_encoding_supported($enc)) {
0 ignored issues
show
Bug introduced by
It seems like $enc defined by api_refine_encoding_id($enc) on line 4493 can also be of type array; however, api_is_encoding_supported() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
4498
            $lp = $this->get_id();
4499
            if ($lp != 0) {
4500
                $tbl_lp = Database :: get_course_table(TABLE_LP_MAIN);
4501
                $sql = "UPDATE $tbl_lp SET default_encoding = '$enc' WHERE c_id = ".$course_id." AND id = " . $lp;
4502
                $res = Database::query($sql);
4503
                return $res;
4504
            }
4505
        }
4506
        return false;
4507
    }
4508
4509
    /**
4510
     * Sets the JS lib setting in the database directly.
4511
     * This is the JavaScript library file this lp needs to load on startup
4512
     * @param	string	Proximity setting
4513
     * @return  boolean True on update success. False otherwise.
4514
     */
4515 View Code Duplication
    public function set_jslib($lib = '')
4516
    {
4517
        if ($this->debug > 0) {
4518
            error_log('New LP - In learnpath::set_jslib()', 0);
4519
        }
4520
        $lp = $this->get_id();
4521
        $course_id = api_get_course_int_id();
4522
4523
        if ($lp != 0) {
4524
            $tbl_lp = Database :: get_course_table(TABLE_LP_MAIN);
4525
            $sql = "UPDATE $tbl_lp SET js_lib = '$lib' WHERE c_id = ".$course_id." AND id = " . $lp;
4526
            $res = Database::query($sql);
4527
            return $res;
4528
        } else {
4529
            return false;
4530
        }
4531
    }
4532
4533
    /**
4534
     * Sets the name of the LP maker (publisher) (and save)
4535
     * @param	string	Optional string giving the new content_maker of this learnpath
4536
     * @return  boolean True
4537
     */
4538 View Code Duplication
    public function set_maker($name = '')
4539
    {
4540
        if ($this->debug > 0) {
4541
            error_log('New LP - In learnpath::set_maker()', 0);
4542
        }
4543
        if (empty ($name))
4544
            return false;
4545
        $this->maker = $name;
4546
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
4547
        $course_id = api_get_course_int_id();
4548
        $lp_id = $this->get_id();
4549
        $sql = "UPDATE $lp_table SET
4550
                content_maker = '" . Database::escape_string($this->maker) . "'
4551
                WHERE c_id = ".$course_id." AND id = '$lp_id'";
4552
        if ($this->debug > 2) {
4553
            error_log('New LP - lp updated with new content_maker : ' . $this->maker, 0);
4554
        }
4555
        Database::query($sql);
4556
        return true;
4557
    }
4558
4559
    /**
4560
     * Sets the name of the current learnpath (and save)
4561
     * @param	string	$name Optional string giving the new name of this learnpath
4562
     * @return  boolean True/False
4563
     */
4564
    public function set_name($name = null)
4565
    {
4566
        if ($this->debug > 0) {
4567
            error_log('New LP - In learnpath::set_name()', 0);
4568
        }
4569
        if (empty($name)) {
4570
            return false;
4571
        }
4572
        $this->name = Database::escape_string($name);
4573
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
4574
        $lp_id = $this->get_id();
4575
        $course_id = $this->course_info['real_id'];
4576
        $sql = "UPDATE $lp_table SET
4577
                name = '" . Database::escape_string($this->name). "'
4578
                WHERE c_id = ".$course_id." AND id = '$lp_id'";
4579
        if ($this->debug > 2) {
4580
            error_log('New LP - lp updated with new name : ' . $this->name, 0);
4581
        }
4582
        $result = Database::query($sql);
4583
        // If the lp is visible on the homepage, change his name there.
4584
        if (Database::affected_rows($result)) {
4585
            $session_id = api_get_session_id();
4586
            $session_condition = api_get_session_condition($session_id);
4587
            $tbl_tool = Database :: get_course_table(TABLE_TOOL_LIST);
4588
            $link = 'newscorm/lp_controller.php?action=view&lp_id=' . $lp_id.'&id_session='.$session_id;
4589
            $sql = "UPDATE $tbl_tool SET name = '$this->name'
4590
            	    WHERE
4591
            	        c_id = $course_id AND
4592
            	        (link='$link' AND image='scormbuilder.gif' $session_condition)";
4593
            Database::query($sql);
4594
            return true;
4595
        } else {
4596
            return false;
4597
        }
4598
    }
4599
4600
    /**
4601
     * Set index specified prefix terms for all items in this path
4602
     * @param   string  Comma-separated list of terms
4603
     * @param   char Xapian term prefix
4604
     * @return  boolean False on error, true otherwise
4605
     */
4606
    public function set_terms_by_prefix($terms_string, $prefix)
4607
    {
4608
        $course_id = api_get_course_int_id();
4609
        if (api_get_setting('search_enabled') !== 'true')
4610
            return false;
4611
4612
        if (!extension_loaded('xapian')) {
4613
            return false;
4614
        }
4615
4616
        $terms_string = trim($terms_string);
4617
        $terms = explode(',', $terms_string);
4618
        array_walk($terms, 'trim_value');
4619
4620
        $stored_terms = $this->get_common_index_terms_by_prefix($prefix);
4621
4622
        // Don't do anything if no change, verify only at DB, not the search engine.
4623 View Code Duplication
        if ((count(array_diff($terms, $stored_terms)) == 0) && (count(array_diff($stored_terms, $terms)) == 0))
4624
            return false;
4625
4626
        require_once 'xapian.php'; // TODO: Try catch every xapian use or make wrappers on API.
4627
        require_once api_get_path(LIBRARY_PATH).'search/ChamiloIndexer.class.php';
4628
        require_once api_get_path(LIBRARY_PATH).'search/xapian/XapianQuery.php';
4629
        require_once api_get_path(LIBRARY_PATH).'search/IndexableChunk.class.php';
4630
4631
        $items_table = Database :: get_course_table(TABLE_LP_ITEM);
4632
        // TODO: Make query secure agains XSS : use member attr instead of post var.
4633
        $lp_id = intval($_POST['lp_id']);
4634
        $sql = "SELECT * FROM $items_table WHERE c_id = $course_id AND lp_id = $lp_id";
4635
        $result = Database::query($sql);
4636
        $di = new ChamiloIndexer();
4637
4638
        while ($lp_item = Database :: fetch_array($result)) {
4639
            // Get search_did.
4640
            $tbl_se_ref = Database :: get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
4641
            $sql = 'SELECT * FROM %s
4642
                    WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s AND ref_id_second_level=%d
4643
                    LIMIT 1';
4644
            $sql = sprintf($sql, $tbl_se_ref, $this->cc, TOOL_LEARNPATH, $lp_id, $lp_item['id']);
4645
4646
            //echo $sql; echo '<br>';
4647
            $res = Database::query($sql);
4648
            if (Database::num_rows($res) > 0) {
4649
                $se_ref = Database :: fetch_array($res);
4650
4651
                // Compare terms.
4652
                $doc = $di->get_document($se_ref['search_did']);
4653
                $xapian_terms = xapian_get_doc_terms($doc, $prefix);
4654
                $xterms = array();
4655
                foreach ($xapian_terms as $xapian_term) {
0 ignored issues
show
Bug introduced by
The expression $xapian_terms of type null|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
4656
                    $xterms[] = substr($xapian_term['name'], 1);
4657
                }
4658
4659
                $dterms = $terms;
4660
4661
                $missing_terms = array_diff($dterms, $xterms);
4662
                $deprecated_terms = array_diff($xterms, $dterms);
4663
4664
                // Save it to search engine.
4665
                foreach ($missing_terms as $term) {
4666
                    $doc->add_term($prefix . $term, 1);
4667
                }
4668
                foreach ($deprecated_terms as $term) {
4669
                    $doc->remove_term($prefix . $term);
4670
                }
4671
                $di->getDb()->replace_document((int) $se_ref['search_did'], $doc);
4672
                $di->getDb()->flush();
4673
            } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
4674
                //@todo What we should do here?
4675
            }
4676
        }
4677
        return true;
4678
    }
4679
4680
    /**
4681
     * Sets the theme of the LP (local/remote) (and save)
4682
     * @param	string	Optional string giving the new theme of this learnpath
4683
     * @return   bool    Returns true if theme name is not empty
4684
     */
4685 View Code Duplication
    public function set_theme($name = '')
4686
    {
4687
        $course_id = api_get_course_int_id();
4688
        if ($this->debug > 0) {
4689
            error_log('New LP - In learnpath::set_theme()', 0);
4690
        }
4691
        $this->theme = $name;
4692
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
4693
        $lp_id = $this->get_id();
4694
        $sql = "UPDATE $lp_table SET theme = '" . Database::escape_string($this->theme). "'
4695
                WHERE c_id = ".$course_id." AND id = '$lp_id'";
4696
        if ($this->debug > 2) {
4697
            error_log('New LP - lp updated with new theme : ' . $this->theme, 0);
4698
        }
4699
        Database::query($sql);
4700
4701
        return true;
4702
    }
4703
4704
    /**
4705
     * Sets the image of an LP (and save)
4706
     * @param	 string	Optional string giving the new image of this learnpath
4707
     * @return bool   Returns true if theme name is not empty
4708
     */
4709 View Code Duplication
    public function set_preview_image($name = '')
4710
    {
4711
        $course_id = api_get_course_int_id();
4712
        if ($this->debug > 0) {
4713
            error_log('New LP - In learnpath::set_preview_image()', 0);
4714
        }
4715
4716
        $this->preview_image = $name;
4717
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
4718
        $lp_id = $this->get_id();
4719
        $sql = "UPDATE $lp_table SET
4720
                preview_image = '" . Database::escape_string($this->preview_image). "'
4721
                WHERE c_id = ".$course_id." AND id = '$lp_id'";
4722
        if ($this->debug > 2) {
4723
            error_log('New LP - lp updated with new preview image : ' . $this->preview_image, 0);
4724
        }
4725
        Database::query($sql);
4726
        return true;
4727
    }
4728
4729
    /**
4730
     * Sets the author of a LP (and save)
4731
     * @param	string	Optional string giving the new author of this learnpath
4732
     * @return   bool    Returns true if author's name is not empty
4733
     */
4734 View Code Duplication
    public function set_author($name = '')
4735
    {
4736
        $course_id = api_get_course_int_id();
4737
        if ($this->debug > 0) {
4738
            error_log('New LP - In learnpath::set_author()', 0);
4739
        }
4740
        $this->author = $name;
4741
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
4742
        $lp_id = $this->get_id();
4743
        $sql = "UPDATE $lp_table SET author = '" . Database::escape_string($name). "'
4744
                WHERE c_id = ".$course_id." AND id = '$lp_id'";
4745
        if ($this->debug > 2) {
4746
            error_log('New LP - lp updated with new preview author : ' . $this->author, 0);
4747
        }
4748
        Database::query($sql);
4749
4750
        return true;
4751
    }
4752
4753
    /**
4754
     * Sets the hide_toc_frame parameter of a LP (and save)
4755
     * @param	int	1 if frame is hidden 0 then else
4756
     * @return   bool    Returns true if author's name is not empty
4757
     */
4758 View Code Duplication
    public function set_hide_toc_frame($hide)
4759
    {
4760
        $course_id = api_get_course_int_id();
4761
        if ($this->debug > 0) {
4762
            error_log('New LP - In learnpath::set_hide_toc_frame()', 0);
4763
        }
4764
        if (intval($hide) == $hide){
4765
            $this->hide_toc_frame = $hide;
4766
            $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
4767
            $lp_id = $this->get_id();
4768
            $sql = "UPDATE $lp_table SET
4769
                    hide_toc_frame = '" . $this->hide_toc_frame . "'
4770
                    WHERE c_id = ".$course_id." AND id = '$lp_id'";
4771
            if ($this->debug > 2) {
4772
                error_log('New LP - lp updated with new preview hide_toc_frame : ' . $this->author, 0);
4773
            }
4774
            Database::query($sql);
4775
4776
            return true;
4777
        } else {
4778
            return false;
4779
        }
4780
    }
4781
4782
    /**
4783
     * Sets the prerequisite of a LP (and save)
4784
     * @param	int		integer giving the new prerequisite of this learnpath
4785
     * @return 	bool 	returns true if prerequisite is not empty
4786
     */
4787 View Code Duplication
    public function set_prerequisite($prerequisite)
4788
    {
4789
        $course_id = api_get_course_int_id();
4790
        if ($this->debug > 0) {
4791
            error_log('New LP - In learnpath::set_prerequisite()', 0);
4792
        }
4793
        $this->prerequisite = intval($prerequisite);
4794
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
4795
        $lp_id = $this->get_id();
4796
        $sql = "UPDATE $lp_table SET prerequisite = '".$this->prerequisite."'
4797
                WHERE c_id = ".$course_id." AND id = '$lp_id'";
4798
        if ($this->debug > 2) {
4799
            error_log('New LP - lp updated with new preview requisite : ' . $this->requisite, 0);
4800
        }
4801
        Database::query($sql);
4802
        return true;
4803
    }
4804
4805
    /**
4806
     * Sets the location/proximity of the LP (local/remote) (and save)
4807
     * @param	string	Optional string giving the new location of this learnpath
4808
     * @return  boolean True on success / False on error
4809
     */
4810
    public function set_proximity($name = '')
4811
    {
4812
        $course_id = api_get_course_int_id();
4813
        if ($this->debug > 0) {
4814
            error_log('New LP - In learnpath::set_proximity()', 0);
4815
        }
4816
        if (empty ($name))
4817
            return false;
4818
4819
        $this->proximity = $name;
4820
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
4821
        $lp_id = $this->get_id();
4822
        $sql = "UPDATE $lp_table SET
4823
                    content_local = '" . Database::escape_string($name) . "'
4824
                WHERE c_id = ".$course_id." AND id = '$lp_id'";
4825
        if ($this->debug > 2) {
4826
            error_log('New LP - lp updated with new proximity : ' . $this->proximity, 0);
4827
        }
4828
        Database::query($sql);
4829
        return true;
4830
    }
4831
4832
    /**
4833
     * Sets the previous item ID to a given ID. Generally, this should be set to the previous 'current' item
4834
     * @param	integer	DB ID of the item
4835
     */
4836
    public function set_previous_item($id)
4837
    {
4838
        if ($this->debug > 0) {
4839
            error_log('New LP - In learnpath::set_previous_item()', 0);
4840
        }
4841
        $this->last = $id;
4842
    }
4843
4844
    /**
4845
     * Sets use_max_score
4846
     * @param   string  $use_max_score Optional string giving the new location of this learnpath
4847
     * @return  boolean True on success / False on error
4848
     */
4849
    public function set_use_max_score($use_max_score = 1)
4850
    {
4851
        $course_id = api_get_course_int_id();
4852
        if ($this->debug > 0) {
4853
            error_log('New LP - In learnpath::set_use_max_score()', 0);
4854
        }
4855
        $use_max_score = intval($use_max_score);
4856
        $this->use_max_score = $use_max_score;
4857
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
4858
        $lp_id = $this->get_id();
4859
        $sql = "UPDATE $lp_table SET
4860
                    use_max_score = '" . $this->use_max_score . "'
4861
                WHERE c_id = ".$course_id." AND id = '$lp_id'";
4862
4863
        if ($this->debug > 2) {
4864
            error_log('New LP - lp updated with new use_max_score : ' . $this->use_max_score, 0);
4865
        }
4866
        Database::query($sql);
4867
4868
        return true;
4869
    }
4870
4871
    /**
4872
     * Sets and saves the expired_on date
4873
     * @param   string  $expired_on Optional string giving the new author of this learnpath
4874
     * @return   bool    Returns true if author's name is not empty
4875
     */
4876 View Code Duplication
    public function set_expired_on($expired_on)
4877
    {
4878
        $course_id = api_get_course_int_id();
4879
        if ($this->debug > 0) {
4880
            error_log('New LP - In learnpath::set_expired_on()', 0);
4881
        }
4882
4883
        if (!empty($expired_on)) {
4884
            $this->expired_on = api_get_utc_datetime($expired_on);
4885
        } else {
4886
            $this->expired_on = '';
4887
        }
4888
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
4889
        $lp_id = $this->get_id();
4890
        $sql = "UPDATE $lp_table SET
4891
                expired_on = '" . Database::escape_string($this->expired_on) . "'
4892
                WHERE c_id = ".$course_id." AND id = '$lp_id'";
4893
        if ($this->debug > 2) {
4894
            error_log('New LP - lp updated with new expired_on : ' . $this->expired_on, 0);
4895
        }
4896
        Database::query($sql);
4897
4898
        return true;
4899
    }
4900
4901
    /**
4902
     * Sets and saves the publicated_on date
4903
     * @param   string  $publicated_on Optional string giving the new author of this learnpath
4904
     * @return   bool    Returns true if author's name is not empty
4905
     */
4906 View Code Duplication
    public function set_publicated_on($publicated_on)
4907
    {
4908
        $course_id = api_get_course_int_id();
4909
        if ($this->debug > 0) {
4910
            error_log('New LP - In learnpath::set_expired_on()', 0);
4911
        }
4912
        if (!empty($publicated_on)) {
4913
            $this->publicated_on = api_get_utc_datetime($publicated_on);
4914
        } else {
4915
            $this->publicated_on = '';
4916
        }
4917
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
4918
        $lp_id = $this->get_id();
4919
        $sql = "UPDATE $lp_table SET
4920
                publicated_on = '" . Database::escape_string($this->publicated_on) . "'
4921
                WHERE c_id = ".$course_id." AND id = '$lp_id'";
4922
        if ($this->debug > 2) {
4923
            error_log('New LP - lp updated with new publicated_on : ' . $this->publicated_on, 0);
4924
        }
4925
        Database::query($sql);
4926
4927
        return true;
4928
    }
4929
4930
    /**
4931
     * Sets and saves the expired_on date
4932
     * @return   bool    Returns true if author's name is not empty
4933
     */
4934 View Code Duplication
    public function set_modified_on()
4935
    {
4936
        $course_id = api_get_course_int_id();
4937
        if ($this->debug > 0) {
4938
            error_log('New LP - In learnpath::set_expired_on()', 0);
4939
        }
4940
        $this->modified_on = api_get_utc_datetime();
4941
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
4942
        $lp_id = $this->get_id();
4943
        $sql = "UPDATE $lp_table SET modified_on = '" . $this->modified_on . "'
4944
                WHERE c_id = ".$course_id." AND id = '$lp_id'";
4945
        if ($this->debug > 2) {
4946
            error_log('New LP - lp updated with new expired_on : ' . $this->modified_on, 0);
4947
        }
4948
        Database::query($sql);
4949
        return true;
4950
    }
4951
4952
    /**
4953
     * Sets the object's error message
4954
     * @param	string	Error message. If empty, reinits the error string
4955
     * @return 	void
4956
     */
4957
    public function set_error_msg($error = '')
4958
    {
4959
        if ($this->debug > 0) {
4960
            error_log('New LP - In learnpath::set_error_msg()', 0);
4961
        }
4962
        if (empty ($error)) {
4963
            $this->error = '';
4964
        } else {
4965
            $this->error .= $error;
4966
        }
4967
    }
4968
4969
    /**
4970
     * Launches the current item if not 'sco'
4971
     * (starts timer and make sure there is a record ready in the DB)
4972
     * @param  boolean  $allow_new_attempt Whether to allow a new attempt or not
4973
     * @return boolean
4974
     */
4975
    public function start_current_item($allow_new_attempt = false)
4976
    {
4977
        if ($this->debug > 0) {
4978
            error_log('New LP - In learnpath::start_current_item()', 0);
4979
        }
4980
        if ($this->current != 0 && is_object($this->items[$this->current])) {
4981
            $type = $this->get_type();
4982
            $item_type = $this->items[$this->current]->get_type();
4983
            if (($type == 2 && $item_type != 'sco') ||
4984
                ($type == 3 && $item_type != 'au') ||
4985
                ($type == 1 && $item_type != TOOL_QUIZ && $item_type != TOOL_HOTPOTATOES)
4986
            ) {
4987
                $this->items[$this->current]->open($allow_new_attempt);
4988
                $this->autocomplete_parents($this->current);
4989
                $prereq_check = $this->prerequisites_match($this->current);
4990
                $this->items[$this->current]->save(false, $prereq_check);
4991
                //$this->update_queue[$this->last] = $this->items[$this->last]->get_status();
4992
            } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
4993
                // If sco, then it is supposed to have been updated by some other call.
4994
            }
4995
            if ($item_type == 'sco') {
4996
                $this->items[$this->current]->restart();
4997
            }
4998
        }
4999
        if ($this->debug > 0) {
5000
            error_log('New LP - End of learnpath::start_current_item()', 0);
5001
        }
5002
        return true;
5003
    }
5004
5005
    /**
5006
     * Stops the processing and counters for the old item (as held in $this->last)
5007
     * @return boolean  True/False
5008
     */
5009
    public function stop_previous_item()
5010
    {
5011
        if ($this->debug > 0) {
5012
            error_log('New LP - In learnpath::stop_previous_item()', 0);
5013
        }
5014
5015
        if ($this->last != 0 && $this->last != $this->current && is_object($this->items[$this->last])) {
5016
            if ($this->debug > 2) {
5017
                error_log('New LP - In learnpath::stop_previous_item() - ' . $this->last . ' is object', 0);
5018
            }
5019
            switch ($this->get_type()) {
5020 View Code Duplication
                case '3' :
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
5021
                    if ($this->items[$this->last]->get_type() != 'au') {
5022
                        if ($this->debug > 2) {
5023
                            error_log('New LP - In learnpath::stop_previous_item() - ' . $this->last . ' in lp_type 3 is <> au', 0);
5024
                        }
5025
                        $this->items[$this->last]->close();
5026
                        //$this->autocomplete_parents($this->last);
5027
                        //$this->update_queue[$this->last] = $this->items[$this->last]->get_status();
5028
                    } else {
5029
                        if ($this->debug > 2) {
5030
                            error_log('New LP - In learnpath::stop_previous_item() - Item is an AU, saving is managed by AICC signals', 0);
5031
                        }
5032
                    }
5033 View Code Duplication
                case '2' :
5034
                    if ($this->items[$this->last]->get_type() != 'sco') {
5035
                        if ($this->debug > 2) {
5036
                            error_log('New LP - In learnpath::stop_previous_item() - ' . $this->last . ' in lp_type 2 is <> sco', 0);
5037
                        }
5038
                        $this->items[$this->last]->close();
5039
                        //$this->autocomplete_parents($this->last);
5040
                        //$this->update_queue[$this->last] = $this->items[$this->last]->get_status();
5041
                    } else {
5042
                        if ($this->debug > 2) {
5043
                            error_log('New LP - In learnpath::stop_previous_item() - Item is a SCO, saving is managed by SCO signals', 0);
5044
                        }
5045
                    }
5046
                    break;
5047
                case '1' :
5048
                default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5049
                    if ($this->debug > 2) {
5050
                        error_log('New LP - In learnpath::stop_previous_item() - ' . $this->last . ' in lp_type 1 is asset', 0);
5051
                    }
5052
                    $this->items[$this->last]->close();
5053
                    break;
5054
            }
5055
        } else {
5056
            if ($this->debug > 2) {
5057
                error_log('New LP - In learnpath::stop_previous_item() - No previous element found, ignoring...', 0);
5058
            }
5059
            return false;
5060
        }
5061
        return true;
5062
    }
5063
5064
    /**
5065
     * Updates the default view mode from fullscreen to embedded and inversely
5066
     * @return	string The current default view mode ('fullscreen' or 'embedded')
5067
     */
5068
    public function update_default_view_mode()
5069
    {
5070
        $course_id = api_get_course_int_id();
5071
        if ($this->debug > 0) {
5072
            error_log('New LP - In learnpath::update_default_view_mode()', 0);
5073
        }
5074
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
5075
        $sql = "SELECT * FROM $lp_table
5076
                WHERE c_id = ".$course_id." AND id = " . $this->get_id();
5077
        $res = Database::query($sql);
5078
        if (Database :: num_rows($res) > 0) {
5079
            $row = Database :: fetch_array($res);
5080
            $default_view_mode = $row['default_view_mod'];
5081
            $view_mode = $default_view_mode;
5082
            switch ($default_view_mode) {
5083
                case 'fullscreen': // default with popup
5084
                    $view_mode = 'embedded';
5085
                    break;
5086
                case 'embedded': // default view with left menu
5087
                    $view_mode = 'embedframe';
5088
                    break;
5089
                case 'embedframe': //folded menu
5090
                    $view_mode = 'impress';
5091
                    break;
5092
                case 'impress':
5093
                    $view_mode = 'fullscreen';
5094
                    break;
5095
            }
5096
            $sql = "UPDATE $lp_table SET default_view_mod = '$view_mode'
5097
                    WHERE c_id = ".$course_id." AND id = " . $this->get_id();
5098
            Database::query($sql);
5099
            $this->mode = $view_mode;
5100
5101
            return $view_mode;
5102
        } else {
5103
            if ($this->debug > 2) {
5104
                error_log('New LP - Problem in update_default_view() - could not find LP ' . $this->get_id() . ' in DB', 0);
5105
            }
5106
        }
5107
        return -1;
5108
    }
5109
5110
    /**
5111
     * Updates the default behaviour about auto-commiting SCORM updates
5112
     * @return	boolean	True if auto-commit has been set to 'on', false otherwise
5113
     */
5114
    public function update_default_scorm_commit()
5115
    {
5116
        $course_id = api_get_course_int_id();
5117
        if ($this->debug > 0) {
5118
            error_log('New LP - In learnpath::update_default_scorm_commit()', 0);
5119
        }
5120
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
5121
        $sql = "SELECT * FROM $lp_table
5122
                WHERE c_id = ".$course_id." AND id = " . $this->get_id();
5123
        $res = Database::query($sql);
5124
        if (Database :: num_rows($res) > 0) {
5125
            $row = Database :: fetch_array($res);
5126
            $force = $row['force_commit'];
5127
            if ($force == 1) {
5128
                $force = 0;
5129
                $force_return = false;
5130
            } elseif ($force == 0) {
5131
                $force = 1;
5132
                $force_return = true;
5133
            }
5134
            $sql = "UPDATE $lp_table SET force_commit = $force
5135
                    WHERE c_id = ".$course_id." AND id = " . $this->get_id();
5136
            Database::query($sql);
5137
            $this->force_commit = $force_return;
5138
5139
            return $force_return;
5140
        } else {
5141
            if ($this->debug > 2) {
5142
                error_log('New LP - Problem in update_default_scorm_commit() - could not find LP ' . $this->get_id() . ' in DB', 0);
5143
            }
5144
        }
5145
        return -1;
5146
    }
5147
5148
    /**
5149
     * Updates the order of learning paths (goes through all of them by order and fills the gaps)
5150
     * @return	bool	True on success, false on failure
5151
     */
5152
    public function update_display_order()
5153
    {
5154
        $course_id = api_get_course_int_id();
5155
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
5156
5157
        $sql = "SELECT * FROM $lp_table WHERE c_id = ".$course_id." ORDER BY display_order";
5158
        $res = Database::query($sql);
5159
        if ($res === false)
5160
            return false;
5161
5162
        $num = Database :: num_rows($res);
5163
        // First check the order is correct, globally (might be wrong because
5164
        // of versions < 1.8.4).
5165
        if ($num > 0) {
5166
            $i = 1;
5167
            while ($row = Database :: fetch_array($res)) {
5168
                if ($row['display_order'] != $i) { // If we find a gap in the order, we need to fix it.
5169
                    $need_fix = true;
5170
                    $sql = "UPDATE $lp_table SET display_order = $i
5171
                            WHERE c_id = ".$course_id." AND id = " . $row['id'];
5172
                    Database::query($sql);
5173
                }
5174
                $i++;
5175
            }
5176
        }
5177
        return true;
5178
    }
5179
5180
    /**
5181
     * Updates the "prevent_reinit" value that enables control on reinitialising items on second view
5182
     * @return	boolean	True if prevent_reinit has been set to 'on', false otherwise (or 1 or 0 in this case)
5183
     */
5184 View Code Duplication
    public function update_reinit()
5185
    {
5186
        $course_id = api_get_course_int_id();
5187
        if ($this->debug > 0) {
5188
            error_log('New LP - In learnpath::update_reinit()', 0);
5189
        }
5190
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
5191
        $sql = "SELECT * FROM $lp_table
5192
                WHERE c_id = ".$course_id." AND id = " . $this->get_id();
5193
        $res = Database::query($sql);
5194
        if (Database :: num_rows($res) > 0) {
5195
            $row = Database :: fetch_array($res);
5196
            $force = $row['prevent_reinit'];
5197
            if ($force == 1) {
5198
                $force = 0;
5199
            } elseif ($force == 0) {
5200
                $force = 1;
5201
            }
5202
            $sql = "UPDATE $lp_table SET prevent_reinit = $force
5203
                    WHERE c_id = ".$course_id." AND id = " . $this->get_id();
5204
            Database::query($sql);
5205
            $this->prevent_reinit = $force;
5206
            return $force;
5207
        } else {
5208
            if ($this->debug > 2) {
5209
                error_log('New LP - Problem in update_reinit() - could not find LP ' . $this->get_id() . ' in DB', 0);
5210
            }
5211
        }
5212
        return -1;
5213
    }
5214
5215
    /**
5216
     * Determine the attempt_mode thanks to prevent_reinit and seriousgame_mode db flag
5217
     *
5218
     * @return string 'single', 'multi' or 'seriousgame'
5219
     * @author ndiechburg <[email protected]>
5220
     **/
5221
    public function get_attempt_mode()
5222
    {
5223
        //Set default value for seriousgame_mode
5224
        if (!isset($this->seriousgame_mode)) {
5225
            $this->seriousgame_mode=0;
5226
        }
5227
        // Set default value for prevent_reinit
5228
        if (!isset($this->prevent_reinit)) {
5229
            $this->prevent_reinit =1;
5230
        }
5231
        if ($this->seriousgame_mode == 1 && $this->prevent_reinit == 1) {
5232
            return 'seriousgame';
5233
        }
5234
        if ($this->seriousgame_mode == 0 && $this->prevent_reinit == 1) {
5235
            return 'single';
5236
        }
5237
        if ($this->seriousgame_mode == 0 && $this->prevent_reinit == 0) {
5238
            return 'multiple';
5239
        }
5240
        return 'single';
5241
    }
5242
5243
    /**
5244
     * Register the attempt mode into db thanks to flags prevent_reinit and seriousgame_mode flags
5245
     *
5246
     * @param string 'seriousgame', 'single' or 'multiple'
5247
     * @return boolean
5248
     * @author ndiechburg <[email protected]>
5249
     **/
5250
    public function set_attempt_mode($mode)
5251
    {
5252
        $course_id = api_get_course_int_id();
5253
        switch ($mode) {
5254
            case 'seriousgame' :
5255
                $sg_mode = 1;
5256
                $prevent_reinit = 1;
5257
                break;
5258
            case 'single' :
5259
                $sg_mode = 0;
5260
                $prevent_reinit = 1;
5261
                break;
5262
            case 'multiple' :
5263
                $sg_mode = 0;
5264
                $prevent_reinit = 0;
5265
                break;
5266
            default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5267
                $sg_mode = 0;
5268
                $prevent_reinit = 0;
5269
                break;
5270
        }
5271
        $this->prevent_reinit = $prevent_reinit;
5272
        $this->seriousgame_mode = $sg_mode;
5273
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
5274
        $sql = "UPDATE $lp_table SET
5275
                prevent_reinit = $prevent_reinit ,
5276
                seriousgame_mode = $sg_mode
5277
                WHERE c_id = ".$course_id." AND id = " . $this->get_id();
5278
        $res = Database::query($sql);
5279
        if ($res) {
5280
            return true;
5281
        } else {
5282
            return false;
5283
        }
5284
    }
5285
5286
    /**
5287
     * Switch between multiple attempt, single attempt or serious_game mode (only for scorm)
5288
     *
5289
     * @return boolean
5290
     * @author ndiechburg <[email protected]>
5291
     **/
5292
    public function switch_attempt_mode()
5293
    {
5294
        if ($this->debug > 0) {
5295
            error_log('New LP - In learnpath::switch_attempt_mode()', 0);
5296
        }
5297
        $mode = $this->get_attempt_mode();
5298
        switch ($mode) {
5299
            case 'single' :
5300
                $next_mode = 'multiple';
5301
                break;
5302
            case 'multiple' :
5303
                $next_mode = 'seriousgame';
5304
                break;
5305
            case 'seriousgame' :
5306
                $next_mode = 'single';
5307
                break;
5308
            default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
5309
                $next_mode = 'single';
5310
                break;
5311
        }
5312
        $this->set_attempt_mode($next_mode);
5313
    }
5314
5315
    /**
5316
     * Switch the lp in ktm mode. This is a special scorm mode with unique attempt
5317
     * but possibility to do again a completed item.
5318
     *
5319
     * @return boolean true if seriousgame_mode has been set to 1, false otherwise
5320
     * @author ndiechburg <[email protected]>
5321
     **/
5322 View Code Duplication
    public function set_seriousgame_mode()
5323
    {
5324
        $course_id = api_get_course_int_id();
5325
        if ($this->debug > 0) {
5326
            error_log('New LP - In learnpath::set_seriousgame_mode()', 0);
5327
        }
5328
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
5329
        $sql = "SELECT * FROM $lp_table WHERE c_id = ".$course_id." AND id = " . $this->get_id();
5330
        $res = Database::query($sql);
5331
        if (Database :: num_rows($res) > 0) {
5332
            $row = Database :: fetch_array($res);
5333
            $force = $row['seriousgame_mode'];
5334
            if ($force == 1) {
5335
                $force = 0;
5336
            } elseif ($force == 0) {
5337
                $force = 1;
5338
            }
5339
            $sql = "UPDATE $lp_table SET seriousgame_mode = $force
5340
			        WHERE c_id = ".$course_id." AND id = " . $this->get_id();
5341
            Database::query($sql);
5342
            $this->seriousgame_mode = $force;
5343
            return $force;
5344
        } else {
5345
            if ($this->debug > 2) {
5346
                error_log('New LP - Problem in set_seriousgame_mode() - could not find LP ' . $this->get_id() . ' in DB', 0);
5347
            }
5348
        }
5349
        return -1;
5350
    }
5351
5352
    /**
5353
     * Updates the "scorm_debug" value that shows or hide the debug window
5354
     * @return	boolean	True if scorm_debug has been set to 'on', false otherwise (or 1 or 0 in this case)
5355
     */
5356 View Code Duplication
    public function update_scorm_debug()
5357
    {
5358
        $course_id = api_get_course_int_id();
5359
        if ($this->debug > 0) {
5360
            error_log('New LP - In learnpath::update_scorm_debug()', 0);
5361
        }
5362
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
5363
        $sql = "SELECT * FROM $lp_table
5364
                WHERE c_id = ".$course_id." AND id = " . $this->get_id();
5365
        $res = Database::query($sql);
5366
        if (Database :: num_rows($res) > 0) {
5367
            $row = Database :: fetch_array($res);
5368
            $force = $row['debug'];
5369
            if ($force == 1) {
5370
                $force = 0;
5371
            } elseif ($force == 0) {
5372
                $force = 1;
5373
            }
5374
            $sql = "UPDATE $lp_table SET debug = $force
5375
                    WHERE c_id = ".$course_id." AND id = " . $this->get_id();
5376
            $res = Database::query($sql);
5377
            $this->scorm_debug = $force;
5378
            return $force;
5379
        } else {
5380
            if ($this->debug > 2) {
5381
                error_log('New LP - Problem in update_scorm_debug() - could not find LP ' . $this->get_id() . ' in DB', 0);
5382
            }
5383
        }
5384
        return -1;
5385
    }
5386
5387
    /**
5388
     * Function that makes a call to the function sort_tree_array and create_tree_array
5389
     * @author Kevin Van Den Haute
5390
     * @param  array
5391
     */
5392
    public function tree_array($array)
5393
    {
5394
        if ($this->debug > 1) {
5395
            error_log('New LP - In learnpath::tree_array()', 0);
5396
        }
5397
        $array = $this->sort_tree_array($array);
5398
        $this->create_tree_array($array);
5399
    }
5400
5401
    /**
5402
     * Creates an array with the elements of the learning path tree in it
5403
     *
5404
     * @author Kevin Van Den Haute
5405
     * @param array $array
5406
     * @param int $parent
5407
     * @param int $depth
5408
     * @param array $tmp
5409
     */
5410
    public function create_tree_array($array, $parent = 0, $depth = -1, $tmp = array ())
5411
    {
5412
        if ($this->debug > 1) {
5413
            error_log('New LP - In learnpath::create_tree_array())', 0);
5414
        }
5415
5416
        if (is_array($array)) {
5417
            for ($i = 0; $i < count($array); $i++) {
5418
                if ($array[$i]['parent_item_id'] == $parent) {
5419
                    if (!in_array($array[$i]['parent_item_id'], $tmp)) {
5420
                        $tmp[] = $array[$i]['parent_item_id'];
5421
                        $depth++;
5422
                    }
5423
                    $preq = (empty($array[$i]['prerequisite']) ? '' : $array[$i]['prerequisite']);
5424
                    $audio = isset($array[$i]['audio']) ? $array[$i]['audio'] : null;
5425
                    $path = isset($array[$i]['path']) ? $array[$i]['path'] : null;
5426
5427
                    $prerequisiteMinScore = isset($array[$i]['prerequisite_min_score']) ? $array[$i]['prerequisite_min_score'] : null;
5428
                    $prerequisiteMaxScore = isset($array[$i]['prerequisite_max_score']) ? $array[$i]['prerequisite_max_score'] : null;
5429
                    $ref = isset($array[$i]['ref']) ? $array[$i]['ref'] : '';
5430
                    $this->arrMenu[] = array(
5431
                        'id' => $array[$i]['id'],
5432
                        'ref' => $ref,
5433
                        'item_type' => $array[$i]['item_type'],
5434
                        'title' => $array[$i]['title'],
5435
                        'path' => $path,
5436
                        'description' => $array[$i]['description'],
5437
                        'parent_item_id' => $array[$i]['parent_item_id'],
5438
                        'previous_item_id' => $array[$i]['previous_item_id'],
5439
                        'next_item_id' => $array[$i]['next_item_id'],
5440
                        'min_score' => $array[$i]['min_score'],
5441
                        'max_score' => $array[$i]['max_score'],
5442
                        'mastery_score' => $array[$i]['mastery_score'],
5443
                        'display_order' => $array[$i]['display_order'],
5444
                        'prerequisite' => $preq,
5445
                        'depth' => $depth,
5446
                        'audio' => $audio,
5447
                        'prerequisite_min_score' => $prerequisiteMinScore,
5448
                        'prerequisite_max_score' => $prerequisiteMaxScore
5449
                    );
5450
5451
                    $this->create_tree_array($array, $array[$i]['id'], $depth, $tmp);
5452
                }
5453
            }
5454
        }
5455
    }
5456
5457
    /**
5458
     * Sorts a multi dimensional array by parent id and display order
5459
     * @author Kevin Van Den Haute
5460
     *
5461
     * @param array $array (array with al the learning path items in it)
5462
     *
5463
     * @return array
5464
     */
5465
    public function sort_tree_array($array) {
5466
        foreach ($array as $key => $row) {
5467
            $parent[$key] = $row['parent_item_id'];
5468
            $position[$key] = $row['display_order'];
5469
        }
5470
5471
        if (count($array) > 0)
5472
            array_multisort($parent, SORT_ASC, $position, SORT_ASC, $array);
5473
5474
        return $array;
5475
    }
5476
5477
    /**
5478
     * Function that creates a html list of learning path items so that we can add audio files to them
5479
     * @author Kevin Van Den Haute
5480
     * @param int $lp_id
0 ignored issues
show
Bug introduced by
There is no parameter named $lp_id. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
5481
     * @return string
5482
     */
5483
    public function overview()
5484
    {
5485
        if ($this->debug > 0) {
5486
            error_log('New LP - In learnpath::overview()', 0);
5487
        }
5488
5489
        $_SESSION['gradebook'] = isset($_GET['gradebook']) ? Security :: remove_XSS($_GET['gradebook']) : null;
5490
        $return = '';
5491
5492
        $update_audio = isset($_GET['updateaudio']) ? $_GET['updateaudio'] : null;
5493
5494
        // we need to start a form when we want to update all the mp3 files
5495
        if ($update_audio == 'true') {
5496
            $return .= '<form action="' . api_get_self() . '?cidReq=' . Security :: remove_XSS($_GET['cidReq']) . '&updateaudio=' . Security :: remove_XSS($_GET['updateaudio']) .'&action=' . Security :: remove_XSS($_GET['action']) . '&lp_id=' . $_SESSION['oLP']->lp_id . '" method="post" enctype="multipart/form-data" name="updatemp3" id="updatemp3">';
5497
        }
5498
        $return .= '<div id="message"></div>';
5499
        if (count($this->items) == 0) {
5500
            $return .= Display::display_normal_message(get_lang('YouShouldAddItemsBeforeAttachAudio'));
5501
        } else {
5502
            $return_audio = '<table class="data_table">';
5503
            $return_audio .= '<tr>';
5504
            $return_audio .= '<th width="40%">' . get_lang('Title') . '</th>';
5505
            $return_audio .= '<th>' . get_lang('Audio') . '</th>';
5506
            $return_audio .= '</tr>';
5507
5508
            if ($update_audio != 'true') {
5509
                $return .= '<div class="col-md-12">';
5510
                $return .= self::return_new_tree($update_audio);
5511
                $return .='</div>';
5512
                $return .= Display::div(Display::url(get_lang('Save'), '#', array('id'=>'listSubmit', 'class'=>'btn btn-primary')), array('style'=>'float:left; margin-top:15px;width:100%'));
5513
            } else {
5514
                $return_audio .= self::return_new_tree($update_audio);
5515
                $return .= $return_audio.'</table>';
5516
            }
5517
5518
            // We need to close the form when we are updating the mp3 files.
5519
            if ($update_audio == 'true') {
5520
                $return .= '<div class="footer-audio">';
5521
                $return .= Display::button('save_audio','<em class="fa fa-file-audio-o"></em> '. get_lang('SaveAudioAndOrganization'),array('class'=>'btn btn-primary','type'=>'submit'));
5522
                $return .= '</div>';
5523
                //$return .= '<div><button class="btn btn-primary" type="submit" name="save_audio" id="save_audio">' . get_lang('SaveAudioAndOrganization') . '</button></div>'; // TODO: What kind of language variable is this?
5524
            }
5525
        }
5526
5527
        // We need to close the form when we are updating the mp3 files.
5528
        if ($update_audio == 'true' && count($this->arrMenu) != 0) {
5529
            $return .= '</form>';
5530
        }
5531
        return $return;
5532
    }
5533
5534
    /**
5535
     * @param string string $update_audio
5536
     * @param bool $drop_element_here
5537
     * @return string
5538
     */
5539
    public function return_new_tree($update_audio = 'false', $drop_element_here = false)
5540
    {
5541
        $return = '';
5542
        $is_allowed_to_edit = api_is_allowed_to_edit(null,true);
5543
5544
        $course_id = api_get_course_int_id();
5545
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
5546
5547
        $sql = "SELECT * FROM $tbl_lp_item
5548
                WHERE c_id = $course_id AND lp_id = ".$this->lp_id;
5549
5550
        $result = Database::query($sql);
5551
        $arrLP = array();
5552
        while ($row = Database :: fetch_array($result)) {
5553
5554
            $arrLP[] = array(
5555
                'id' => $row['id'],
5556
                'item_type' => $row['item_type'],
5557
                'title' => Security :: remove_XSS($row['title']),
5558
                'path' => $row['path'],
5559
                'description' => Security::remove_XSS($row['description']),
5560
                'parent_item_id' => $row['parent_item_id'],
5561
                'previous_item_id' => $row['previous_item_id'],
5562
                'next_item_id' => $row['next_item_id'],
5563
                'max_score' => $row['max_score'],
5564
                'min_score' => $row['min_score'],
5565
                'mastery_score' => $row['mastery_score'],
5566
                'prerequisite' => $row['prerequisite'],
5567
                'display_order' => $row['display_order'],
5568
                'audio' => $row['audio'],
5569
                'prerequisite_max_score' => $row['prerequisite_max_score'],
5570
                'prerequisite_min_score' => $row['prerequisite_min_score']
5571
            );
5572
        }
5573
5574
        $this->tree_array($arrLP);
5575
        $arrLP = isset($this->arrMenu) ? $this->arrMenu : null;
5576
        unset ($this->arrMenu);
5577
        $default_data = null;
5578
        $default_content = null;
5579
5580
        $elements = array();
5581
        $return_audio = null;
5582
5583
        for ($i = 0; $i < count($arrLP); $i++) {
5584
            $title = $arrLP[$i]['title'];
5585
5586
            $title_cut = cut($arrLP[$i]['title'], 25);
5587
5588
            // Link for the documents
5589
            if ($arrLP[$i]['item_type'] == 'document') {
5590
                $url = api_get_self() . '?'.api_get_cidreq().'&action=view_item&mode=preview_document&id=' . $arrLP[$i]['id'] . '&lp_id=' . $this->lp_id;
5591
                $title_cut = Display::url(
5592
                    $title_cut,
5593
                    $url,
5594
                    array(
5595
                        'class' => 'ajax moved',
5596
                        'data-title' => $title_cut
5597
                    )
5598
                );
5599
            }
5600
5601
            // Detect if type is FINAL_ITEM to set path_id to SESSION
5602
            if ($arrLP[$i]['item_type'] == TOOL_FINAL_ITEM) {
5603
                $_SESSION['pathItem'] = $arrLP[$i]['path'];
5604
            }
5605
5606
5607
5608
5609
            if (($i % 2) == 0) {
5610
                $oddClass = 'row_odd';
5611
            } else {
5612
                $oddClass = 'row_even';
5613
            }
5614
            $return_audio .= '<tr id ="lp_item_'.$arrLP[$i]['id'] .'" class="' . $oddClass . '">';
5615
5616
            $icon_name = str_replace(' ', '', $arrLP[$i]['item_type']);
5617
5618
            if (file_exists('../img/lp_' . $icon_name . '.png')) {
5619
                $icon = Display::return_icon('lp_'.$icon_name.'.png');
5620
            } else {
5621
                if (file_exists('../img/lp_' . $icon_name . '.gif')) {
5622
                    $icon = Display::return_icon('lp_'.$icon_name.'.gif');
5623
                } else {
5624
                    if ($arrLP[$i]['item_type'] === TOOL_FINAL_ITEM) {
5625
                        $icon = Display::return_icon('certificate.png');
5626
                    } else {
5627
                        $icon = Display::return_icon('folder_document.gif');
5628
                    }
5629
                }
5630
            }
5631
5632
            // The audio column.
5633
            $return_audio  .= '<td align="left" style="padding-left:10px;">';
5634
            $audio = '';
5635
5636
            if (!$update_audio || $update_audio <> 'true') {
5637
                if (!empty($arrLP[$i]['audio'])) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
5638
                } else {
5639
                    $audio .= '';
5640
                }
5641
            } else {
5642
                $types = self::getChapterTypes();
5643
                if (!in_array($arrLP[$i]['item_type'], $types)) {
5644
                    $audio .= '<input type="file" name="mp3file' . $arrLP[$i]['id'] . '" id="mp3file" />';
5645
                    if (!empty ($arrLP[$i]['audio'])) {
5646
                        $audio .= '<br />'.Security::remove_XSS($arrLP[$i]['audio']).'<br />
5647
                        <input type="checkbox" name="removemp3' . $arrLP[$i]['id'] . '" id="checkbox' . $arrLP[$i]['id'] . '" />' . get_lang('RemoveAudio');
5648
                    }
5649
                }
5650
            }
5651
            $return_audio .= Display::span($icon.' '.$title).Display::tag('td', $audio, array('style'=>''));
5652
            $return_audio .= '</td>';
5653
            $move_icon = '';
5654
            $move_item_icon = '';
5655
            $edit_icon = '';
5656
            $delete_icon = '';
5657
            $audio_icon = '';
5658
            $prerequisities_icon = '';
5659
            $forumIcon = '';
5660
5661
            if ($is_allowed_to_edit) {
5662
                if (!$update_audio || $update_audio <> 'true') {
5663 View Code Duplication
                    if ($arrLP[$i]['item_type'] !== TOOL_FINAL_ITEM) {
5664
                        $move_icon .= '<a class="moved" href="#">';
5665
                        $move_icon .= Display::return_icon('move_everywhere.png', get_lang('Move'), array(), ICON_SIZE_TINY);
5666
                        $move_icon .= '</a>';
5667
                    }
5668
                }
5669
5670
                // No edit for this item types
5671
                if (!in_array($arrLP[$i]['item_type'], array('sco', 'asset', 'final_item'))) {
5672
                    if (!in_array($arrLP[$i]['item_type'], array('dokeos_chapter', 'dokeos_module'))) {
5673
                        $edit_icon .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=edit_item&view=build&id=' . $arrLP[$i]['id'] . '&lp_id=' . $this->lp_id . '&path_item=' . $arrLP[$i]['path'] . '" class="btn btn-default">';
5674
                        $edit_icon .= Display::return_icon('edit.png', get_lang('LearnpathEditModule'), array(), ICON_SIZE_TINY);
5675
                        $edit_icon .= '</a>';
5676
5677
                        if (
5678
                        !in_array($arrLP[$i]['item_type'], ['forum', 'thread'])
5679
                        ) {
5680
                            if (
5681
                            $this->items[$arrLP[$i]['id']]->getForumThread(
5682
                                $this->course_int_id,
5683
                                $this->lp_session_id
5684
                            )
5685
                            ) {
5686
                                $forumIconUrl = api_get_self() . '?' . api_get_cidreq() . '&' . http_build_query([
5687
                                    'action' => 'dissociate_forum',
5688
                                    'id' => $arrLP[$i]['id'],
5689
                                    'lp_id' => $this->lp_id
5690
                                ]);
5691
                                $forumIcon = Display::url(
5692
                                    Display::return_icon('forum.png', get_lang('DissociateForumToLPItem'), [], ICON_SIZE_TINY),
5693
                                    $forumIconUrl,
5694
                                    ['class' => 'btn btn-default lp-btn-dissociate-forum']
5695
                                );
5696
                            } else {
5697
                                $forumIconUrl = api_get_self() . '?' . api_get_cidreq() . '&' . http_build_query([
5698
                                    'action' => 'create_forum',
5699
                                    'id' => $arrLP[$i]['id'],
5700
                                    'lp_id' => $this->lp_id
5701
                                ]);
5702
                                $forumIcon = Display::url(
5703
                                    Display::return_icon('forum.png', get_lang('AssociateForumToLPItem'), [], ICON_SIZE_TINY),
5704
                                    $forumIconUrl,
5705
                                    ['class' => "btn btn-default lp-btn-associate-forum"]
5706
                                );
5707
                            }
5708
                        }
5709
                    } else {
5710
                        $edit_icon .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=edit_item&id=' . $arrLP[$i]['id'] . '&lp_id=' . $this->lp_id . '&path_item=' . $arrLP[$i]['path'] . '" class="btn btn-default">';
5711
                        $edit_icon .= Display::return_icon('edit.png', get_lang('LearnpathEditModule'), array(), ICON_SIZE_TINY);
5712
                        $edit_icon .= '</a>';
5713
                    }
5714
                }
5715
5716
                $delete_icon .= ' <a href="'.api_get_self().'?'.api_get_cidreq().'&action=delete_item&id=' . $arrLP[$i]['id'] . '&lp_id=' . $this->lp_id . '" onclick="return confirmation(\'' . addslashes($title) . '\');" class="btn btn-default">';
5717
                $delete_icon .= Display::return_icon('delete.png', get_lang('LearnpathDeleteModule'), array(), ICON_SIZE_TINY);
5718
                $delete_icon .= '</a>';
5719
5720
                $url = api_get_self() . '?'.api_get_cidreq().'&view=build&id='.$arrLP[$i]['id'] .'&lp_id='.$this->lp_id;
5721
5722
                if (!in_array($arrLP[$i]['item_type'], array('dokeos_chapter', 'dokeos_module', 'dir'))) {
5723
                    $prerequisities_icon = Display::url(Display::return_icon('accept.png', get_lang('LearnpathPrerequisites'), array(), ICON_SIZE_TINY), $url.'&action=edit_item_prereq', ['class' => 'btn btn-default']);
5724
                    $move_item_icon = Display::url(Display::return_icon('move.png', get_lang('Move'), array(), ICON_SIZE_TINY), $url.'&action=move_item', ['class' => 'btn btn-default']);
5725
                    $audio_icon = Display::url(Display::return_icon('audio.png', get_lang('UplUpload'), array(), ICON_SIZE_TINY), $url.'&action=add_audio', ['class' => 'btn btn-default']);
5726
                }
5727
            }
5728
            if ($update_audio != 'true') {
5729
                $row = $move_icon . ' ' . $icon .
5730
                    Display::span($title_cut) .
5731
                    Display::tag(
5732
                        'div',
5733
                        "<div class=\"btn-group btn-group-xs\">$audio $edit_icon $forumIcon $prerequisities_icon $move_item_icon $audio_icon $delete_icon</div>",
5734
                        array('class'=>'btn-toolbar button_actions')
5735
                    );
5736
            } else {
5737
                $row = Display::span($title.$icon).Display::span($audio, array('class'=>'button_actions'));
5738
            }
5739
            $parent_id = $arrLP[$i]['parent_item_id'];
5740
5741
            $default_data[$arrLP[$i]['id']] = $row;
5742
            $default_content[$arrLP[$i]['id']] = $arrLP[$i];
5743
5744
            if (empty($parent_id)) {
5745
                $elements[$arrLP[$i]['id']]['data'] = $row;
5746
                $elements[$arrLP[$i]['id']]['type'] = $arrLP[$i]['item_type'];
5747
            } else {
5748
                $parent_arrays = array();
5749
                if ($arrLP[$i]['depth'] > 1) {
5750
                    //Getting list of parents
5751
                    for($j = 0; $j < $arrLP[$i]['depth']; $j++) {
5752
                        foreach($arrLP as $item) {
5753
                            if ($item['id'] == $parent_id) {
5754
                                if ($item['parent_item_id'] == 0) {
5755
                                    $parent_id = $item['id'];
5756
                                    break;
5757
                                } else {
5758
                                    $parent_id = $item['parent_item_id'];
5759
                                    if (empty($parent_arrays)) {
5760
                                        $parent_arrays[] = intval($item['id']);
5761
                                    }
5762
                                    $parent_arrays[] = $parent_id;
5763
                                    break;
5764
                                }
5765
                            }
5766
                        }
5767
                    }
5768
                }
5769
5770
                if (!empty($parent_arrays)) {
5771
                    $parent_arrays = array_reverse($parent_arrays);
5772
                    $val = '$elements';
5773
                    $x = 0;
5774
                    foreach($parent_arrays as $item) {
5775
                        if ($x != count($parent_arrays) -1) {
5776
                            $val .= '["'.$item.'"]["children"]';
5777
                        } else {
5778
                            $val .= '["'.$item.'"]["children"]';
5779
                        }
5780
                        $x++;
5781
                    }
5782
                    $val .= "";
5783
                    $code_str = $val."[".$arrLP[$i]['id']."][\"load_data\"] = '".$arrLP[$i]['id']."' ; ";
5784
                    eval($code_str);
0 ignored issues
show
Coding Style introduced by
It is generally not recommended to use eval unless absolutely required.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
5785
                } else {
5786
                    $elements[$parent_id]['children'][$arrLP[$i]['id']]['data'] = $row;
5787
                    $elements[$parent_id]['children'][$arrLP[$i]['id']]['type'] = $arrLP[$i]['item_type'];
5788
                }
5789
            }
5790
        }
5791
5792
        $list = '<ul id="lp_item_list">';
5793
        $tree = self::print_recursive($elements, $default_data, $default_content);
5794
5795
        if (!empty($tree)) {
5796
            $list .= $tree;
5797
        } else {
5798
            if ($drop_element_here) {
5799
                $list .= Display::return_message(get_lang("DragAndDropAnElementHere"));
5800
            }
5801
        }
5802
        $list .= '</ul>';
5803
5804
        //$return .= Display::panel($list, $this->name);
5805
        $return .= Display::panelCollapse($this->name, $list, 'scorm-list', null, 'scorm-list-accordion', 'scorm-list-collapse');
5806
5807
        if ($update_audio == 'true') {
5808
            $return = $return_audio;
5809
        }
5810
5811
        return $return;
5812
    }
5813
5814
    /**
5815
     * @param array $elements
5816
     * @param array $default_data
5817
     * @param array $default_content
5818
     * @return string
5819
     */
5820
    public function print_recursive($elements, $default_data, $default_content)
5821
    {
5822
        $return = '';
5823
        foreach ($elements as $key => $item) {
5824
            if (isset($item['load_data']) || empty($item['data'])) {
5825
                $item['data'] = $default_data[$item['load_data']];
5826
                $item['type'] = $default_content[$item['load_data']]['item_type'];
5827
            }
5828
            $sub_list = '';
5829
            if (isset($item['type']) && $item['type'] == 'dokeos_chapter') {
5830
                $sub_list = Display::tag('li', '', array('class'=>'sub_item empty')); // empty value
5831
            }
5832
            if (empty($item['children'])) {
5833
                $sub_list = Display::tag('ul', $sub_list, array('id'=>'UL_'.$key, 'class'=>'record li_container'));
5834
                $active = null;
5835
                if (isset($_REQUEST['id']) && $key == $_REQUEST['id']) {
5836
                    $active = 'active';
5837
                }
5838
                $return  .= Display::tag('li', Display::div($item['data'], array('class'=>"item_data $active")).$sub_list, array('id'=>$key, 'class'=>'record li_container'));
5839
            } else {
5840
                //sections
5841
                if (isset($item['children'])) {
5842
                    $data = self::print_recursive($item['children'], $default_data, $default_content);
5843
                }
5844
                $sub_list = Display::tag('ul', $sub_list.$data, array('id'=>'UL_'.$key, 'class'=>'record li_container'));
5845
                $return .= Display::tag('li', Display::div($item['data'], array('class'=>'item_data')).$sub_list, array('id'=>$key, 'class'=>'record li_container'));
5846
            }
5847
        }
5848
5849
        return $return;
5850
    }
5851
5852
    /**
5853
     * This function builds the action menu
5854
     * @param bool $returnContent
5855
     * @return void
5856
     */
5857
    public function build_action_menu($returnContent = false)
5858
    {
5859
        $gradebook = isset($_GET['gradebook']) ? Security :: remove_XSS($_GET['gradebook']) : null;
5860
        $return = '<div class="actions">';
5861
        $return .=  '<a href="lp_controller.php?'.api_get_cidreq().'&gradebook=' . $gradebook . '&action=view&lp_id=' . $_SESSION['oLP']->lp_id . '&isStudentView=true">' . Display :: return_icon('preview_view.png', get_lang('Display'),'',ICON_SIZE_MEDIUM).'</a> ';
5862
        $return .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=admin_view&lp_id=' . $_SESSION['oLP']->lp_id . '&updateaudio=true">' . Display :: return_icon('upload_audio.png', get_lang('UpdateAllAudioFragments'),'',ICON_SIZE_MEDIUM).'</a>';
5863
        $return .= '<a href="lp_controller.php?'.api_get_cidreq().'&action=edit&lp_id=' . $_SESSION['oLP']->lp_id . '">' . Display :: return_icon('settings.png', get_lang('CourseSettings'),'',ICON_SIZE_MEDIUM).'</a>';
5864
        $buttons = array(
5865
            array(
5866
                'title' => get_lang('SetPrerequisiteForEachItem'),
5867
                'href' => 'lp_controller.php?'.api_get_cidreq().'&action=set_previous_step_as_prerequisite&lp_id=' . $_SESSION['oLP']->lp_id,
5868
            ),
5869
            array(
5870
                'title' => get_lang('ClearAllPrerequisites'),
5871
                'href' => 'lp_controller.php?'.api_get_cidreq().'&action=clear_prerequisites&lp_id=' . $_SESSION['oLP']->lp_id,
5872
            ),
5873
        );
5874
        $return .= Display::group_button(get_lang('PrerequisitesOptions'), $buttons);
5875
        $return .= '</div>';
5876
5877
        if ($returnContent) {
5878
            return $return;
5879
        }
5880
        echo $return;
5881
    }
5882
5883
    /**
5884
     * Creates the default learning path folder
5885
     * @param array $course
5886
     * @param int $creatorId
5887
     *
5888
     * @return bool
5889
     */
5890
    public static function generate_learning_path_folder($course, $creatorId = 0)
5891
    {
5892
        // Creating learning_path folder
5893
        $dir = '/learning_path';
5894
        $filepath = api_get_path(SYS_COURSE_PATH).$course['path'] . '/document';
5895
        $creatorId = empty($creatorId) ? api_get_user_id() : $creatorId;
5896
5897
        $folder = false;
5898
        if (!is_dir($filepath.'/'.$dir)) {
5899
            $folderData = create_unexisting_directory(
5900
                $course,
5901
                $creatorId,
5902
                api_get_session_id(),
5903
                0,
5904
                0,
5905
                $filepath,
5906
                $dir,
5907
                get_lang('LearningPaths'),
5908
                0
5909
            );
5910
            if (!empty($folderData)) {
5911
                $folder = true;
5912
            }
5913
        } else {
5914
            $folder = true;
5915
        }
5916
5917
        return $folder;
5918
    }
5919
5920
    /**
5921
     * @param array $course
5922
     * @param string $lp_name
5923
     * @param int $creatorId
5924
     *
5925
     * @return array
5926
     */
5927
    public function generate_lp_folder($course, $lp_name = '', $creatorId = 0)
5928
    {
5929
        $filepath = '';
5930
        $dir = '/learning_path/';
5931
5932
        if (empty($lp_name)) {
5933
            $lp_name = $this->name;
5934
        }
5935
        $creatorId = empty($creatorId) ? api_get_user_id() : $creatorId;
5936
5937
        $folder = self::generate_learning_path_folder($course, $creatorId);
5938
        // Creating LP folder
5939
        if ($folder) {
5940
            //Limits title size
5941
            $title = api_substr(api_replace_dangerous_char($lp_name), 0 , 80);
5942
            $dir   = $dir.$title;
5943
            $filepath = api_get_path(SYS_COURSE_PATH) . $course['path'] . '/document';
5944
            if (!is_dir($filepath.'/'.$dir)) {
5945
                $folderData = create_unexisting_directory(
5946
                    $course,
5947
                    $creatorId,
5948
                    0,
5949
                    0,
5950
                    0,
5951
                    $filepath,
5952
                    $dir,
5953
                    $lp_name
5954
                );
5955
                if (!empty($folderData)) {
5956
                    $folder = true;
5957
                }
5958
            } else {
5959
                $folder = true;
5960
            }
5961
            $dir = $dir.'/';
5962
            if ($folder) {
5963
                $filepath = api_get_path(SYS_COURSE_PATH) . $course['path'] . '/document'.$dir;
5964
            }
5965
        }
5966
        $array = array(
5967
            'dir' => $dir,
5968
            'filepath' => $filepath,
5969
            'folder' => $folder
5970
        );
5971
        return $array;
5972
    }
5973
5974
    /**
5975
     * Create a new document //still needs some finetuning
5976
     * @param array $courseInfo
5977
     * @param string $content
5978
     * @param string $title
5979
     * @param string $extension
5980
     * @param int $creatorId creator id
5981
     *
5982
     * @return string
5983
     */
5984
    public function create_document($courseInfo, $content = '', $title = '', $extension = 'html', $creatorId = 0)
5985
    {
5986
        if (!empty($courseInfo)) {
5987
            $course_id = $courseInfo['real_id'];
5988
        } else {
5989
            $course_id = api_get_course_int_id();
5990
        }
5991
        $creatorId = empty($creatorId) ? api_get_user_id() : $creatorId;
5992
        $sessionId = api_get_session_id();
5993
5994
        global $charset;
5995
        $postDir = isset($_POST['dir']) ? $_POST['dir'] : '';
5996
        $dir = isset ($_GET['dir']) ? $_GET['dir'] : $postDir; // Please, do not modify this dirname formatting.
5997
        // Please, do not modify this dirname formatting.
5998
        if (strstr($dir, '..')) {
5999
            $dir = '/';
6000
        }
6001
        if (!empty($dir[0]) && $dir[0] == '.') {
6002
            $dir = substr($dir, 1);
6003
        }
6004
        if (!empty($dir[0]) && $dir[0] != '/') {
6005
            $dir = '/' . $dir;
6006
        }
6007
        if (isset($dir[strlen($dir) - 1]) && $dir[strlen($dir) - 1] != '/') {
6008
            $dir .= '/';
6009
        }
6010
        $filepath = api_get_path(SYS_COURSE_PATH) . $courseInfo['path'] . '/document' . $dir;
6011
6012
        if (empty($_POST['dir']) && empty($_GET['dir'])) {
6013
            //Generates folder
6014
            $result = $this->generate_lp_folder($courseInfo, '', $creatorId);
6015
            $dir = $result['dir'];
6016
            $filepath = $result['filepath'];
6017
        }
6018
6019 View Code Duplication
        if (!is_dir($filepath)) {
6020
            $filepath = api_get_path(SYS_COURSE_PATH) . $courseInfo['path'] . '/document/';
6021
            $dir = '/';
6022
        }
6023
6024
        // stripslashes() before calling api_replace_dangerous_char() because $_POST['title']
6025
        // is already escaped twice when it gets here.
6026
6027
        $originalTitle = !empty($title) ? $title : $_POST['title'];
6028
        if (!empty($title)) {
6029
            $title = api_replace_dangerous_char(stripslashes($title));
6030
        } else {
6031
            $title = api_replace_dangerous_char(stripslashes($_POST['title']));
6032
        }
6033
6034
        $title = disable_dangerous_file($title);
6035
        $filename = $title;
6036
        $content = !empty($content) ? $content : $_POST['content_lp'];
6037
        $tmp_filename = $filename;
6038
6039
        $i = 0;
6040 View Code Duplication
        while (file_exists($filepath . $tmp_filename . '.'.$extension))
6041
            $tmp_filename = $filename . '_' . ++ $i;
6042
6043
        $filename = $tmp_filename . '.'.$extension;
6044
        if ($extension == 'html') {
6045
            $content = stripslashes($content);
6046
            $content = str_replace(
6047
                api_get_path(WEB_COURSE_PATH),
6048
                api_get_path(REL_PATH).'courses/',
6049
                $content
6050
            );
6051
6052
            // Change the path of mp3 to absolute.
6053
6054
            // The first regexp deals with :// urls.
6055
            $content = preg_replace(
6056
                "|(flashvars=\"file=)([^:/]+)/|",
6057
                "$1".api_get_path(
6058
                    REL_COURSE_PATH
6059
                ).$courseInfo['path'].'/document/',
6060
                $content
6061
            );
6062
            // The second regexp deals with audio/ urls.
6063
            $content = preg_replace(
6064
                "|(flashvars=\"file=)([^/]+)/|",
6065
                "$1".api_get_path(
6066
                    REL_COURSE_PATH
6067
                ).$courseInfo['path'].'/document/$2/',
6068
                $content
6069
            );
6070
            // For flv player: To prevent edition problem with firefox, we have to use a strange tip (don't blame me please).
6071
            $content = str_replace(
6072
                '</body>',
6073
                '<style type="text/css">body{}</style></body>',
6074
                $content
6075
            );
6076
        }
6077
6078
        if (!file_exists($filepath . $filename)) {
6079
            if ($fp = @ fopen($filepath . $filename, 'w')) {
6080
                fputs($fp, $content);
6081
                fclose($fp);
6082
6083
                $file_size = filesize($filepath . $filename);
6084
                $save_file_path = $dir.$filename;
6085
6086
                $document_id = add_document(
6087
                    $courseInfo,
6088
                    $save_file_path,
6089
                    'file',
6090
                    $file_size,
6091
                    $tmp_filename,
6092
                    '',
6093
                    0, //readonly
6094
                    true,
6095
                    null,
6096
                    $sessionId,
6097
                    $creatorId
6098
                );
6099
6100
                if ($document_id) {
6101
                    api_item_property_update(
6102
                        $courseInfo,
6103
                        TOOL_DOCUMENT,
6104
                        $document_id,
6105
                        'DocumentAdded',
6106
                        $creatorId,
6107
                        null,
6108
                        null,
6109
                        null,
6110
                        null,
6111
                        $sessionId
6112
                    );
6113
6114
                    $new_comment = isset($_POST['comment']) ? trim($_POST['comment']) : '';
6115
                    $new_title = $originalTitle;
6116
6117
                    if ($new_comment || $new_title) {
6118
                        $tbl_doc = Database :: get_course_table(TABLE_DOCUMENT);
6119
                        $ct = '';
6120
                        if ($new_comment)
6121
                            $ct .= ", comment='" . Database::escape_string($new_comment). "'";
6122
                        if ($new_title)
6123
                            $ct .= ", title='" . Database::escape_string(htmlspecialchars($new_title, ENT_QUOTES, $charset))."' ";
6124
6125
                        $sql = "UPDATE " . $tbl_doc ." SET " . substr($ct, 1)."
6126
                               WHERE c_id = ".$course_id." AND id = " . $document_id;
6127
                        Database::query($sql);
6128
                    }
6129
                }
6130
                return $document_id;
6131
            }
6132
        }
6133
    }
6134
6135
    /**
6136
     * Edit a document based on $_POST and $_GET parameters 'dir' and 'path'
6137
     * @param 	array $_course array
6138
     * @return 	void
6139
     */
6140
    public function edit_document($_course)
6141
    {
6142
        $course_id = api_get_course_int_id();
6143
        global $_configuration;
6144
        // Please, do not modify this dirname formatting.
6145
        $dir = isset($_GET['dir']) ? $_GET['dir'] : $_POST['dir'];
6146
6147
        if (strstr($dir, '..'))
6148
            $dir = '/';
6149
6150
        if ($dir[0] == '.')
6151
            $dir = substr($dir, 1);
6152
6153
        if ($dir[0] != '/')
6154
            $dir = '/' . $dir;
6155
6156
        if ($dir[strlen($dir) - 1] != '/')
6157
            $dir .= '/';
6158
6159
        $filepath = api_get_path(SYS_COURSE_PATH) . $_course['path'] . '/document' . $dir;
6160
6161 View Code Duplication
        if (!is_dir($filepath)) {
6162
            $filepath = api_get_path(SYS_COURSE_PATH) . $_course['path'] . '/document/';
6163
        }
6164
6165
        $table_doc = Database :: get_course_table(TABLE_DOCUMENT);
6166
        if (isset($_POST['path']) && !empty($_POST['path'])) {
6167
            $document_id = intval($_POST['path']);
6168
            $sql = "SELECT path FROM " . $table_doc . "
6169
                    WHERE c_id = $course_id AND id = " . $document_id;
6170
            $res = Database::query($sql);
6171
            $row = Database :: fetch_array($res);
6172
            $content = stripslashes($_POST['content_lp']);
6173
            $file = $filepath . $row['path'];
6174
6175
            if ($fp = @ fopen($file, 'w')) {
6176
                $content = str_replace(api_get_path(WEB_COURSE_PATH), $_configuration['url_append'] . '/courses/', $content);
6177
6178
                // Change the path of mp3 to absolute.
6179
                // The first regexp deals with :// urls.
6180
                $content = preg_replace("|(flashvars=\"file=)([^:/]+)/|", "$1" . api_get_path(REL_COURSE_PATH) . $_course['path'] . '/document/', $content);
6181
                // The second regexp deals with audio/ urls.
6182
                $content = preg_replace("|(flashvars=\"file=)([^:/]+)/|", "$1" . api_get_path(REL_COURSE_PATH) . $_course['path'] . '/document/$2/', $content);
6183
                fputs($fp, $content);
6184
                fclose($fp);
6185
6186
                $sql = "UPDATE " . $table_doc ." SET
6187
                            title='".Database::escape_string($_POST['title'])."'
6188
                        WHERE c_id = ".$course_id." AND id = " . $document_id;
6189
                Database::query($sql);
6190
            }
6191
        }
6192
    }
6193
6194
    /**
6195
     * Displays the selected item, with a panel for manipulating the item
6196
     * @param int $item_id
6197
     * @param string $msg
6198
     * @return string
6199
     */
6200
    public function display_item($item_id, $msg = null, $show_actions = true)
6201
    {
6202
        $course_id = api_get_course_int_id();
6203
        $return = '';
6204
        if (is_numeric($item_id)) {
6205
            $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
6206
            $sql = "SELECT lp.* FROM " . $tbl_lp_item . " as lp
6207
                    WHERE c_id = ".$course_id." AND lp.id = " . intval($item_id);
6208
            $result = Database::query($sql);
6209
            while ($row = Database :: fetch_array($result,'ASSOC')) {
0 ignored issues
show
Bug introduced by
It seems like $result can be null; however, fetch_array() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
6210
                $_SESSION['parent_item_id'] = ($row['item_type'] == 'dokeos_chapter' || $row['item_type'] == 'dokeos_module' || $row['item_type'] == 'dir') ? $item_id : 0;
6211
6212
                // Prevents wrong parent selection for document, see Bug#1251.
6213
                if ($row['item_type'] != 'dokeos_chapter' || $row['item_type'] != 'dokeos_module') {
6214
                    $_SESSION['parent_item_id'] = $row['parent_item_id'];
6215
                }
6216
6217
                if ($show_actions) {
6218
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
6219
                }
6220
                $return .= '<div style="padding:10px;">';
6221
6222
                if ($msg != '')
6223
                    $return .= $msg;
6224
6225
                $return .= '<h3>'.$row['title'].'</h3>';
6226
                switch ($row['item_type']) {
6227
                    case TOOL_QUIZ:
6228
                        if (!empty($row['path'])) {
6229
                            $exercise = new Exercise();
6230
                            $exercise->read($row['path']);
6231
                            $return .= $exercise->description.'<br />';
6232
                        }
6233
                        break;
6234
                    case TOOL_DOCUMENT:
6235
                        $tbl_doc = Database :: get_course_table(TABLE_DOCUMENT);
6236
                        $sql_doc = "SELECT path FROM " . $tbl_doc . "
6237
                                    WHERE c_id = ".$course_id." AND id = " . intval($row['path']);
6238
                        $result = Database::query($sql_doc);
6239
                        $path_file = Database::result($result, 0, 0);
6240
                        $path_parts = pathinfo($path_file);
6241
                        // TODO: Correct the following naive comparisons, also, htm extension is missing.
6242
                        if (in_array($path_parts['extension'], array(
6243
                            'html',
6244
                            'txt',
6245
                            'png',
6246
                            'jpg',
6247
                            'JPG',
6248
                            'jpeg',
6249
                            'JPEG',
6250
                            'gif',
6251
                            'swf'
6252
                        ))) {
6253
                            $return .= $this->display_document($row['path'], true, true);
6254
                        }
6255
                        break;
6256
                }
6257
                $return .= '</div>';
6258
            }
6259
        }
6260
6261
        return $return;
6262
    }
6263
6264
    /**
6265
     * Shows the needed forms for editing a specific item
6266
     * @param int $item_id
6267
     * @return string
6268
     */
6269
    public function display_edit_item($item_id)
6270
    {
6271
        $course_id = api_get_course_int_id();
6272
        $return = '';
6273
        if (is_numeric($item_id)) {
6274
            $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
6275
            $sql = "SELECT * FROM $tbl_lp_item
6276
                    WHERE c_id = ".$course_id." AND id = " . intval($item_id);
6277
            $res = Database::query($sql);
6278
            $row = Database::fetch_array($res);
6279
            switch ($row['item_type']) {
6280
                case 'dokeos_chapter' :
6281
                case 'dir' :
6282
                case 'asset' :
6283 View Code Duplication
                case 'sco' :
6284
                    if (isset ($_GET['view']) && $_GET['view'] == 'build') {
6285
                        $return .= $this->display_manipulate($item_id, $row['item_type']);
6286
                        $return .= $this->display_item_form($row['item_type'], get_lang('EditCurrentChapter') . ' :', 'edit', $item_id, $row);
6287
                    } else {
6288
                        $return .= $this->display_item_small_form($row['item_type'], get_lang('EditCurrentChapter') . ' :', $row);
6289
                    }
6290
                    break;
6291 View Code Duplication
                case TOOL_DOCUMENT :
6292
                    $tbl_doc = Database :: get_course_table(TABLE_DOCUMENT);
6293
                    $sql = "SELECT lp.*, doc.path as dir
6294
                            FROM " . $tbl_lp_item . " as lp
6295
                            LEFT JOIN " . $tbl_doc . " as doc
6296
                            ON doc.id = lp.path
6297
                            WHERE
6298
                                lp.c_id = $course_id AND
6299
                                doc.c_id = $course_id AND
6300
                                lp.id = " . intval($item_id);
6301
                    $res_step = Database::query($sql);
6302
                    $row_step = Database :: fetch_array($res_step, 'ASSOC');
6303
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
6304
                    $return .= $this->display_document_form('edit', $item_id, $row_step);
6305
                    break;
6306
                case TOOL_LINK :
6307
                    $link_id = (string) $row['path'];
6308
                    if (ctype_digit($link_id)) {
6309
                        $tbl_link = Database :: get_course_table(TABLE_LINK);
6310
                        $sql_select = 'SELECT url FROM ' . $tbl_link . '
6311
                                       WHERE c_id = '.$course_id.' AND id = ' . intval($link_id);
6312
                        $res_link = Database::query($sql_select);
6313
                        $row_link = Database :: fetch_array($res_link);
6314
                        if (is_array($row_link)) {
6315
                            $row['url'] = $row_link['url'];
6316
                        }
6317
                    }
6318
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
6319
                    $return .= $this->display_link_form('edit', $item_id, $row);
6320
                    break;
6321 View Code Duplication
                case TOOL_FINAL_ITEM :
6322
                    $_SESSION['finalItem'] = true;
6323
                    $tbl_doc = Database :: get_course_table(TABLE_DOCUMENT);
6324
                    $sql = "SELECT lp.*, doc.path as dir
6325
                            FROM " . $tbl_lp_item . " as lp
6326
                            LEFT JOIN " . $tbl_doc . " as doc
6327
                            ON doc.id = lp.path
6328
                            WHERE
6329
                                lp.c_id = $course_id AND
6330
                                doc.c_id = $course_id AND
6331
                                lp.id = " . intval($item_id);
6332
                    $res_step = Database::query($sql);
6333
                    $row_step = Database :: fetch_array($res_step, 'ASSOC');
6334
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
6335
                    $return .= $this->display_document_form('edit', $item_id, $row_step);
6336
                    break;
6337 View Code Duplication
                case 'dokeos_module' :
6338
                    if (isset ($_GET['view']) && $_GET['view'] == 'build') {
6339
                        $return .= $this->display_manipulate($item_id, $row['item_type']);
6340
                        $return .= $this->display_item_form($row['item_type'], get_lang('EditCurrentModule') . ' :', 'edit', $item_id, $row);
6341
                    } else {
6342
                        $return .= $this->display_item_small_form($row['item_type'], get_lang('EditCurrentModule') . ' :', $row);
6343
                    }
6344
                    break;
6345 View Code Duplication
                case TOOL_QUIZ :
6346
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
6347
                    $return .= $this->display_quiz_form('edit', $item_id, $row);
6348
                    break;
6349
                case TOOL_HOTPOTATOES :
6350
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
6351
                    $return .= $this->display_hotpotatoes_form('edit', $item_id, $row);
6352
                    break;
6353 View Code Duplication
                case TOOL_STUDENTPUBLICATION :
6354
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
6355
                    $return .= $this->display_student_publication_form('edit', $item_id, $row);
6356
                    break;
6357
                case TOOL_FORUM :
6358
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
6359
                    $return .= $this->display_forum_form('edit', $item_id, $row);
6360
                    break;
6361 View Code Duplication
                case TOOL_THREAD :
6362
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
6363
                    $return .= $this->display_thread_form('edit', $item_id, $row);
6364
                    break;
6365
            }
6366
        }
6367
6368
        return $return;
6369
    }
6370
6371
    /**
6372
     * Function that displays a list with al the resources that
6373
     * could be added to the learning path
6374
     * @return string
6375
     */
6376
    public function display_resources()
6377
    {
6378
        $course_code = api_get_course_id();
6379
6380
        // Get all the docs.
6381
        $documents = $this->get_documents(true);
6382
6383
        // Get all the exercises.
6384
        $exercises = $this->get_exercises();
6385
6386
        // Get all the links.
6387
        $links = $this->get_links();
6388
6389
        // Get al the student publications.
6390
        $works = $this->get_student_publications();
6391
6392
        // Get al the forums.
6393
        $forums = $this->get_forums(null, $course_code);
6394
6395
        $finish = $this->getFinalItemForm();
6396
6397
        $headers = array(
6398
            Display::return_icon('folder_document.png', get_lang('Documents'), array(), ICON_SIZE_BIG),
6399
            Display::return_icon('quiz.png',  get_lang('Quiz'), array(), ICON_SIZE_BIG),
6400
            Display::return_icon('links.png', get_lang('Links'), array(), ICON_SIZE_BIG),
6401
            Display::return_icon('works.png', get_lang('Works'), array(), ICON_SIZE_BIG),
6402
            Display::return_icon('forum.png', get_lang('Forums'), array(), ICON_SIZE_BIG),
6403
            Display::return_icon('add_learnpath_section.png', get_lang('NewChapter'), array(), ICON_SIZE_BIG),
6404
            Display::return_icon('certificate.png', get_lang('Certificate'), [], ICON_SIZE_BIG),
6405
        );
6406
6407
        echo Display::display_normal_message(get_lang('ClickOnTheLearnerViewToSeeYourLearningPath'));
6408
        $chapter = $_SESSION['oLP']->display_item_form('chapter', get_lang('EnterDataNewChapter'), 'add_item');
6409
        echo Display::tabs(
6410
            $headers,
6411
            array($documents, $exercises, $links, $works, $forums, $chapter, $finish), 'resource_tab'
6412
        );
6413
6414
        return true;
6415
    }
6416
6417
    /**
6418
     * Returns the extension of a document
6419
     * @param string filename
6420
     * @return string Extension (part after the last dot)
6421
     */
6422
    public function get_extension($filename)
6423
    {
6424
        $explode = explode('.', $filename);
6425
        return $explode[count($explode) - 1];
6426
    }
6427
6428
    /**
6429
     * Displays a document by id
6430
     *
6431
     * @param int $id
6432
     * @return string
6433
     */
6434
    public function display_document($id, $show_title = false, $iframe = true, $edit_link = false)
6435
    {
6436
        $_course = api_get_course_info();
6437
        $course_id = api_get_course_int_id();
6438
        $return = '';
6439
        $tbl_doc = Database :: get_course_table(TABLE_DOCUMENT);
6440
        $sql_doc = "SELECT * FROM " . $tbl_doc . "
6441
                    WHERE c_id = ".$course_id." AND id = " . $id;
6442
        $res_doc = Database::query($sql_doc);
6443
        $row_doc = Database :: fetch_array($res_doc);
6444
6445
        // TODO: Add a path filter.
6446
        if ($iframe) {
6447
            $return .= '<iframe id="learnpath_preview_frame" frameborder="0" height="400" width="100%" scrolling="auto" src="' . api_get_path(WEB_COURSE_PATH) . $_course['path'] . '/document' . str_replace('%2F', '/', urlencode($row_doc['path'])) . '?' . api_get_cidreq() . '"></iframe>';
6448
        } else {
6449
            $return .= file_get_contents(api_get_path(SYS_COURSE_PATH) . $_course['path'] . '/document' . $row_doc['path']);
6450
        }
6451
6452
        return $return;
6453
    }
6454
6455
    /**
6456
     * Return HTML form to add/edit a quiz
6457
     * @param	string	Action (add/edit)
6458
     * @param	integer	Item ID if already exists
6459
     * @param	mixed	Extra information (quiz ID if integer)
6460
     * @return	string	HTML form
6461
     */
6462
    public function display_quiz_form($action = 'add', $id = 0, $extra_info = '')
6463
    {
6464
        $course_id = api_get_course_int_id();
6465
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
6466
        $tbl_quiz = Database :: get_course_table(TABLE_QUIZ_TEST);
6467
6468 View Code Duplication
        if ($id != 0 && is_array($extra_info)) {
6469
            $item_title = $extra_info['title'];
6470
            $item_description = $extra_info['description'];
6471
        } elseif (is_numeric($extra_info)) {
6472
            $sql = "SELECT title, description
6473
                    FROM " . $tbl_quiz . "
6474
                    WHERE c_id = ".$course_id." AND id = " . $extra_info;
6475
6476
            $result = Database::query($sql);
6477
            $row = Database::fetch_array($result);
6478
            $item_title = $row['title'];
6479
            $item_description = $row['description'];
6480
        } else {
6481
            $item_title = '';
6482
            $item_description = '';
6483
        }
6484
        $item_title			= Security::remove_XSS($item_title);
6485
        $item_description 	= Security::remove_XSS($item_description);
6486
6487
        $legend = '<legend>';
6488 View Code Duplication
        if ($id != 0 && is_array($extra_info))
6489
            $parent = $extra_info['parent_item_id'];
6490
        else
6491
            $parent = 0;
6492
6493
        $sql = "SELECT * FROM " . $tbl_lp_item . "
6494
                WHERE c_id = ".$course_id." AND lp_id = " . $this->lp_id;
6495
6496
        $result = Database::query($sql);
6497
        $arrLP = array ();
6498 View Code Duplication
        while ($row = Database :: fetch_array($result)) {
6499
            $arrLP[] = array (
6500
                'id' => $row['id'],
6501
                'item_type' => $row['item_type'],
6502
                'title' => $row['title'],
6503
                'path' => $row['path'],
6504
                'description' => $row['description'],
6505
                'parent_item_id' => $row['parent_item_id'],
6506
                'previous_item_id' => $row['previous_item_id'],
6507
                'next_item_id' => $row['next_item_id'],
6508
                'display_order' => $row['display_order'],
6509
                'max_score' => $row['max_score'],
6510
                'min_score' => $row['min_score'],
6511
                'mastery_score' => $row['mastery_score'],
6512
                'prerequisite' => $row['prerequisite'],
6513
                'max_time_allowed' => $row['max_time_allowed']
6514
            );
6515
        }
6516
6517
        $this->tree_array($arrLP);
6518
        $arrLP = isset($this->arrMenu) ? $this->arrMenu : null;
6519
        unset ($this->arrMenu);
6520
6521
        if ($action == 'add') {
6522
            $legend .= get_lang('CreateTheExercise') . '&nbsp;:';
6523
        } elseif ($action == 'move') {
6524
            $legend .= get_lang('MoveTheCurrentExercise') . '&nbsp;:';
6525
        } else {
6526
            $legend .= get_lang('EditCurrentExecice') . '&nbsp;:';
6527
        }
6528
6529 View Code Duplication
        if (isset ($_GET['edit']) && $_GET['edit'] == 'true') {
6530
            $legend .= Display :: return_warning_message(get_lang('Warning') . ' ! ' . get_lang('WarningEditingDocument'));
6531
        }
6532
6533
        $legend .= '</legend>';
6534
        $return = '';
6535
        $return .= '<div class="sectioncomment">';
6536
6537
        $return .= '<form method="POST">';
6538
        $return .= $legend;
6539
        $return .= '<table class="lp_form">';
6540
6541 View Code Duplication
        if ($action != 'move') {
6542
            $return .= '<tr>';
6543
            $return .= '<td class="label"><label for="idTitle">' . get_lang('Title') . '</label></td>';
6544
            $return .= '<td class="input"><input id="idTitle" name="title" size="44" type="text" value="' . $item_title . '" /></td>';
6545
            $return .= '</tr>';
6546
        }
6547
6548
        $return .= '<tr>';
6549
6550
        $return .= '<td class="label"><label for="idParent">' . get_lang('Parent') . '</label></td>';
6551
        $return .= '<td class="input">';
6552
6553
        // Select for Parent item, root or chapter
6554
        $return .= '<select id="idParent" style="width:100%;" name="parent" onChange="javascript: load_cbo(this.value);" size="1">';
6555
6556
        $return .= '<option class="top" value="0">' . $this->name . '</option>';
6557
6558
        $arrHide = array (
6559
            $id
6560
        );
6561 View Code Duplication
        for ($i = 0; $i < count($arrLP); $i++) {
6562
            if ($action != 'add') {
6563
                if (($arrLP[$i]['item_type'] == 'dokeos_module' || $arrLP[$i]['item_type'] == 'dokeos_chapter' || $arrLP[$i]['item_type'] == 'dir') && !in_array($arrLP[$i]['id'], $arrHide) && !in_array($arrLP[$i]['parent_item_id'], $arrHide)) {
6564
                    $return .= '<option ' . (($parent == $arrLP[$i]['id']) ? 'selected="selected" ' : '') . 'style="padding-left:' . ($arrLP[$i]['depth'] * 10) . 'px;" value="' . $arrLP[$i]['id'] . '">' . $arrLP[$i]['title'] . '</option>';
6565
                } else {
6566
                    $arrHide[] = $arrLP[$i]['id'];
6567
                }
6568
            } else {
6569
                if ($arrLP[$i]['item_type'] == 'dokeos_module' || $arrLP[$i]['item_type'] == 'dokeos_chapter' || $arrLP[$i]['item_type'] == 'dir')
6570
                    $return .= '<option ' . (($parent == $arrLP[$i]['id']) ? 'selected="selected" ' : '') . 'style="padding-left:' . ($arrLP[$i]['depth'] * 10) . 'px;" value="' . $arrLP[$i]['id'] . '">' . $arrLP[$i]['title'] . '</option>';
6571
            }
6572
        }
6573
        if (is_array($arrLP)) {
6574
            reset($arrLP);
6575
        }
6576
6577
        $return .= '</select>';
6578
        $return .= '</td>';
6579
        $return .= '</tr>';
6580
        $return .= '<tr>';
6581
6582
        $return .= '<td class="label"><label for="previous">' . get_lang('Position') . '</label></td>';
6583
        $return .= '<td class="input">';
6584
6585
        $return .= '<select class="learnpath_item_form" style="width:100%;" id="previous" name="previous" size="1">';
6586
        $return .= '<option class="top" value="0">' . get_lang('FirstPosition') . '</option>';
6587 View Code Duplication
        for ($i = 0; $i < count($arrLP); $i++) {
6588
            if ($arrLP[$i]['parent_item_id'] == $parent && $arrLP[$i]['id'] != $id) {
6589
                if (is_array($extra_info)) {
6590
                    if ($extra_info['previous_item_id'] == $arrLP[$i]['id']) {
6591
                        $selected = 'selected="selected" ';
6592
                    }
6593
                } elseif ($action == 'add') {
6594
                    $selected = 'selected="selected" ';
6595
                } else {
6596
                    $selected = '';
6597
                }
6598
                $return .= '<option ' . $selected . 'value="' . $arrLP[$i]['id'] . '">' . get_lang('After') . ' "' . $arrLP[$i]['title'] . '"</option>';
6599
            }
6600
        }
6601
        $return .= '</select>';
6602
6603
        $return .= '</td>';
6604
        $return .= '</tr>';
6605
        if ($action != 'move') {
6606
            $id_prerequisite = 0;
6607
            if (is_array($arrLP)) {
6608
                foreach ($arrLP as $key => $value) {
6609
                    if ($value['id'] == $id) {
6610
                        $id_prerequisite = $value['prerequisite'];
6611
                        break;
6612
                    }
6613
                }
6614
            }
6615
            $arrHide = array ();
6616
            for ($i = 0; $i < count($arrLP); $i++) {
6617
                if ($arrLP[$i]['id'] != $id && $arrLP[$i]['item_type'] != 'dokeos_chapter') {
6618
                    if (is_array($extra_info)) {
6619
                        if ($extra_info['previous_item_id'] == $arrLP[$i]['id']) {
6620
                            $s_selected_position = $arrLP[$i]['id'];
6621
                        }
6622
                    } elseif ($action == 'add') {
6623
                        $s_selected_position = 0;
6624
                    }
6625
                    $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title'];
6626
                }
6627
            }
6628
            /*// Commented the prerequisites, only visible in edit (exercise).
6629
            $return .= '<tr>';
6630
            $return .= '<td class="label"><label for="idPrerequisites">'.get_lang('LearnpathPrerequisites').'</label></td>';
6631
            $return .= '<td class="input"><select name="prerequisites" id="prerequisites" class="learnpath_item_form"><option value="0">'.get_lang('NoPrerequisites').'</option>';
6632
6633
                foreach($arrHide as $key => $value){
6634
                    if($key==$s_selected_position && $action == 'add'){
6635
                        $return .= '<option value="'.$key.'" selected="selected">'.$value['value'].'</option>';
6636
                    }
6637
                    elseif($key==$id_prerequisite && $action == 'edit'){
6638
                        $return .= '<option value="'.$key.'" selected="selected">'.$value['value'].'</option>';
6639
                    }
6640
                    else{
6641
                        $return .= '<option value="'.$key.'">'.$value['value'].'</option>';
6642
                    }
6643
                }
6644
6645
            $return .= "</select></td>";
6646
            */
6647
            $return .= '</tr>';
6648
            /*$return .= '<tr>';
6649
            $return .= '<td class="label"><label for="maxTimeAllowed">' . get_lang('MaxTimeAllowed') . '</label></td>';
6650
            $return .= '<td class="input"><input name="maxTimeAllowed" style="width:98%;" id="maxTimeAllowed" value="' . $extra_info['max_time_allowed'] . '" /></td>';
6651
6652
            // Remove temporarily the test description.
6653
            //$return .= '<td class="label"><label for="idDescription">'.get_lang('Description').' :</label></td>';
6654
            //$return .= '<td class="input"><textarea id="idDescription" name="description" rows="4">' . $item_description . '</textarea></td>';
6655
6656
            $return .= '</tr>'; */
6657
        }
6658
6659
        $return .= '<tr>';
6660
        if ($action == 'add') {
6661
            $return .= '<td>&nbsp;</td><td><button class="save" name="submit_button" type="submit">' . get_lang('AddExercise') . '</button></td>';
6662
        } else {
6663
            $return .= '<td>&nbsp;</td><td><button class="save" name="submit_button" type="submit">' . get_lang('EditCurrentExecice') . '</button></td>';
6664
        }
6665
6666
        $return .= '</tr>';
6667
        $return .= '</table>';
6668
6669 View Code Duplication
        if ($action == 'move') {
6670
            $return .= '<input name="title" type="hidden" value="' . $item_title . '" />';
6671
            $return .= '<input name="description" type="hidden" value="' . $item_description . '" />';
6672
        }
6673
6674 View Code Duplication
        if (is_numeric($extra_info)) {
6675
            $return .= '<input name="path" type="hidden" value="' . $extra_info . '" />';
6676
        } elseif (is_array($extra_info)) {
6677
            $return .= '<input name="path" type="hidden" value="' . $extra_info['path'] . '" />';
6678
        }
6679
6680
        $return .= '<input name="type" type="hidden" value="' . TOOL_QUIZ . '" />';
6681
        $return .= '<input name="post_time" type="hidden" value="' . time() . '" />';
6682
6683
        $return .= '</form>';
6684
        $return .= '</div>';
6685
6686
        return $return;
6687
    }
6688
6689
    /**
6690
     * Addition of Hotpotatoes tests
6691
     * @param	string	Action
6692
     * @param	integer	Internal ID of the item
6693
     * @param	mixed	Extra information - can be an array with title and description indexes
6694
     * @return  string	HTML structure to display the hotpotatoes addition formular
6695
     */
6696
    public function display_hotpotatoes_form($action = 'add', $id = 0, $extra_info = '')
6697
    {
6698
        $course_id = api_get_course_int_id();
6699
        $uploadPath = DIR_HOTPOTATOES; //defined in main_api
6700
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
6701
6702
        if ($id != 0 && is_array($extra_info)) {
6703
            $item_title = stripslashes($extra_info['title']);
6704
            $item_description = stripslashes($extra_info['description']);
6705
        } elseif (is_numeric($extra_info)) {
6706
            $TBL_DOCUMENT = Database :: get_course_table(TABLE_DOCUMENT);
6707
6708
            $sql = "SELECT * FROM " . $TBL_DOCUMENT . "
6709
                    WHERE
6710
                        c_id = ".$course_id." AND
6711
                        path LIKE '" . $uploadPath . "/%/%htm%' AND
6712
                        id = " . (int) $extra_info . "
6713
                    ORDER BY id ASC";
6714
6715
            $res_hot = Database::query($sql);
6716
            $row = Database::fetch_array($res_hot);
6717
6718
            $item_title = $row['title'];
6719
            $item_description = $row['description'];
6720
6721
            if (!empty ($row['comment'])) {
6722
                $item_title = $row['comment'];
6723
            }
6724
        } else {
6725
            $item_title = '';
6726
            $item_description = '';
6727
        }
6728
6729 View Code Duplication
        if ($id != 0 && is_array($extra_info)) {
6730
            $parent = $extra_info['parent_item_id'];
6731
        } else {
6732
            $parent = 0;
6733
        }
6734
6735
        $sql = "SELECT * FROM $tbl_lp_item
6736
                WHERE c_id = ".$course_id." AND lp_id = " . $this->lp_id;
6737
        $result = Database::query($sql);
6738
        $arrLP = array ();
6739 View Code Duplication
        while ($row = Database :: fetch_array($result)) {
6740
            $arrLP[] = array (
6741
                'id' => $row['id'],
6742
                'item_type' => $row['item_type'],
6743
                'title' => $row['title'],
6744
                'path' => $row['path'],
6745
                'description' => $row['description'],
6746
                'parent_item_id' => $row['parent_item_id'],
6747
                'previous_item_id' => $row['previous_item_id'],
6748
                'next_item_id' => $row['next_item_id'],
6749
                'display_order' => $row['display_order'],
6750
                'max_score' => $row['max_score'],
6751
                'min_score' => $row['min_score'],
6752
                'mastery_score' => $row['mastery_score'],
6753
                'prerequisite' => $row['prerequisite'],
6754
                'max_time_allowed' => $row['max_time_allowed']
6755
            );
6756
        }
6757
6758
        $legend = '<legend>';
6759
        if ($action == 'add')
6760
            $legend .= get_lang('CreateTheExercise');
6761
        elseif ($action == 'move') $legend .= get_lang('MoveTheCurrentExercise');
6762
        else
6763
            $legend .= get_lang('EditCurrentExecice');
6764 View Code Duplication
        if (isset ($_GET['edit']) && $_GET['edit'] == 'true') {
6765
            $legend .= Display :: return_warning_message(get_lang('Warning') . ' ! ' . get_lang('WarningEditingDocument'));
6766
        }
6767
        $legend .= '</legend>';
6768
6769
        $return = '<form method="POST">';
6770
        $return .= $legend;
6771
        $return .= '<table cellpadding="0" cellspacing="0" class="lp_form">';
6772
        $return .= '<tr>';
6773
        $return .= '<td class="label"><label for="idParent">' . get_lang('Parent') . ' :</label></td>';
6774
        $return .= '<td class="input">';
6775
        $return .= '<select id="idParent" name="parent" onChange="javascript: load_cbo(this.value);" size="1">';
6776
        $return .= '<option class="top" value="0">' . $this->name . '</option>';
6777
        $arrHide = array (
6778
            $id
6779
        );
6780
6781
        if (count($arrLP) > 0) {
6782 View Code Duplication
            for ($i = 0; $i < count($arrLP); $i++) {
6783
                if ($action != 'add') {
6784
                    if (($arrLP[$i]['item_type'] == 'dokeos_module' || $arrLP[$i]['item_type'] == 'dokeos_chapter' || $arrLP[$i]['item_type'] == 'dir') && !in_array($arrLP[$i]['id'], $arrHide) && !in_array($arrLP[$i]['parent_item_id'], $arrHide)) {
6785
                        $return .= '<option ' . (($parent == $arrLP[$i]['id']) ? 'selected="selected" ' : '') . 'style="padding-left:' . ($arrLP[$i]['depth'] * 10) . 'px;" value="' . $arrLP[$i]['id'] . '">' . $arrLP[$i]['title'] . '</option>';
6786
                    } else {
6787
                        $arrHide[] = $arrLP[$i]['id'];
6788
                    }
6789
                } else {
6790
                    if ($arrLP[$i]['item_type'] == 'dokeos_module' || $arrLP[$i]['item_type'] == 'dokeos_chapter' || $arrLP[$i]['item_type'] == 'dir')
6791
                        $return .= '<option ' . (($parent == $arrLP[$i]['id']) ? 'selected="selected" ' : '') . 'style="padding-left:' . ($arrLP[$i]['depth'] * 10) . 'px;" value="' . $arrLP[$i]['id'] . '">' . $arrLP[$i]['title'] . '</option>';
6792
                }
6793
            }
6794
6795
            reset($arrLP);
6796
        }
6797
6798
        $return .= '</select>';
6799
        $return .= '</td>';
6800
        $return .= '</tr>';
6801
        $return .= '<tr>';
6802
        $return .= '<td class="label"><label for="previous">' . get_lang('Position') . ' :</label></td>';
6803
        $return .= '<td class="input">';
6804
        $return .= '<select id="previous" name="previous" size="1">';
6805
        $return .= '<option class="top" value="0">' . get_lang('FirstPosition') . '</option>';
6806
6807 View Code Duplication
        for ($i = 0; $i < count($arrLP); $i++) {
6808
            if ($arrLP[$i]['parent_item_id'] == $parent && $arrLP[$i]['id'] != $id) {
6809
                if ($extra_info['previous_item_id'] == $arrLP[$i]['id'])
6810
                    $selected = 'selected="selected" ';
6811
                elseif ($action == 'add') $selected = 'selected="selected" ';
6812
                else
6813
                    $selected = '';
6814
6815
                $return .= '<option ' . $selected . 'value="' . $arrLP[$i]['id'] . '">' . get_lang('After') . ' "' . $arrLP[$i]['title'] . '"</option>';
6816
            }
6817
        }
6818
6819
        $return .= '</select>';
6820
        $return .= '</td>';
6821
        $return .= '</tr>';
6822
6823
        if ($action != 'move') {
6824
            $return .= '<tr>';
6825
            $return .= '<td class="label"><label for="idTitle">' . get_lang('Title') . ' :</label></td>';
6826
            $return .= '<td class="input"><input id="idTitle" name="title" type="text" value="' . $item_title . '" /></td>';
6827
            $return .= '</tr>';
6828
            $id_prerequisite = 0;
6829 View Code Duplication
            if (is_array($arrLP) && count($arrLP) > 0) {
6830
                foreach ($arrLP as $key => $value) {
6831
                    if ($value['id'] == $id) {
6832
                        $id_prerequisite = $value['prerequisite'];
6833
                        break;
6834
                    }
6835
                }
6836
6837
                $arrHide = array ();
6838
                for ($i = 0; $i < count($arrLP); $i++) {
6839
                    if ($arrLP[$i]['id'] != $id && $arrLP[$i]['item_type'] != 'dokeos_chapter') {
6840
                        if ($extra_info['previous_item_id'] == $arrLP[$i]['id'])
6841
                            $s_selected_position = $arrLP[$i]['id'];
6842
                        elseif ($action == 'add') $s_selected_position = 0;
6843
                        $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title'];
6844
6845
                    }
6846
                }
6847
            }
6848
        }
6849
6850
        $return .= '<tr>';
6851
        $return .= '<td>&nbsp; </td><td><button class="save" name="submit_button" action="edit" type="submit">' . get_lang('SaveHotpotatoes') . '</button></td>';
6852
        $return .= '</tr>';
6853
        $return .= '</table>';
6854
6855 View Code Duplication
        if ($action == 'move') {
6856
            $return .= '<input name="title" type="hidden" value="' . $item_title . '" />';
6857
            $return .= '<input name="description" type="hidden" value="' . $item_description . '" />';
6858
        }
6859
6860 View Code Duplication
        if (is_numeric($extra_info)) {
6861
            $return .= '<input name="path" type="hidden" value="' . $extra_info . '" />';
6862
        } elseif (is_array($extra_info)) {
6863
            $return .= '<input name="path" type="hidden" value="' . $extra_info['path'] . '" />';
6864
        }
6865
        $return .= '<input name="type" type="hidden" value="' . TOOL_HOTPOTATOES . '" />';
6866
        $return .= '<input name="post_time" type="hidden" value="' . time() . '" />';
6867
        $return .= '</form>';
6868
6869
        return $return;
6870
    }
6871
6872
    /**
6873
     * Return the form to display the forum edit/add option
6874
     * @param	string	Action (add/edit)
6875
     * @param	integer	ID of the lp_item if already exists
6876
     * @param	mixed	Forum ID or title
6877
     * @return	string	HTML form
6878
     */
6879
    public function display_forum_form($action = 'add', $id = 0, $extra_info = '')
6880
    {
6881
        $course_id = api_get_course_int_id();
6882
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
6883
        $tbl_forum = Database :: get_course_table(TABLE_FORUM);
6884
6885 View Code Duplication
        if ($id != 0 && is_array($extra_info)) {
6886
            $item_title = stripslashes($extra_info['title']);
6887
        } elseif (is_numeric($extra_info)) {
6888
            $sql = "SELECT forum_title as title, forum_comment as comment
6889
                    FROM " . $tbl_forum . "
6890
                    WHERE c_id = ".$course_id." AND forum_id = " . $extra_info;
6891
6892
            $result = Database::query($sql);
6893
            $row = Database :: fetch_array($result);
6894
6895
            $item_title = $row['title'];
6896
            $item_description = $row['comment'];
6897
        } else {
6898
            $item_title = '';
6899
            $item_description = '';
6900
        }
6901
6902
        $legend = '<legend>';
6903
6904 View Code Duplication
        if ($id != 0 && is_array($extra_info)) {
6905
            $parent = $extra_info['parent_item_id'];
6906
        } else {
6907
            $parent = 0;
6908
        }
6909
6910
        $sql = "SELECT * FROM " . $tbl_lp_item . "
6911
                WHERE
6912
                    c_id = ".$course_id." AND
6913
                    lp_id = " . $this->lp_id;
6914
        $result = Database::query($sql);
6915
        $arrLP = array();
6916
6917 View Code Duplication
        while ($row = Database :: fetch_array($result)) {
6918
            $arrLP[] = array (
6919
                'id' => $row['id'],
6920
                'item_type' => $row['item_type'],
6921
                'title' => $row['title'],
6922
                'path' => $row['path'],
6923
                'description' => $row['description'],
6924
                'parent_item_id' => $row['parent_item_id'],
6925
                'previous_item_id' => $row['previous_item_id'],
6926
                'next_item_id' => $row['next_item_id'],
6927
                'display_order' => $row['display_order'],
6928
                'max_score' => $row['max_score'],
6929
                'min_score' => $row['min_score'],
6930
                'mastery_score' => $row['mastery_score'],
6931
                'prerequisite' => $row['prerequisite']
6932
            );
6933
        }
6934
6935
        $this->tree_array($arrLP);
6936
        $arrLP = isset($this->arrMenu) ? $this->arrMenu : null;
6937
        unset($this->arrMenu);
6938
6939
        if ($action == 'add')
6940
            $legend .= get_lang('CreateTheForum') . '&nbsp;:';
6941
        elseif ($action == 'move') $legend .= get_lang('MoveTheCurrentForum') . '&nbsp;:';
6942
        else
6943
            $legend .= get_lang('EditCurrentForum') . '&nbsp;:';
6944
6945
        $legend .= '</legend>';
6946
        $return = '<div class="sectioncomment">';
6947
        $return .= '<form method="POST">';
6948
        $return .= $legend;
6949
        $return .= '<table class="lp_form">';
6950
6951 View Code Duplication
        if ($action != 'move') {
6952
            $return .= '<tr>';
6953
            $return .= '<td class="label"><label for="idTitle">' . get_lang('Title') . '</label></td>';
6954
            $return .= '<td class="input"><input id="idTitle" size="44" name="title" type="text" value="' . $item_title . '" class="learnpath_item_form" /></td>';
6955
            $return .= '</tr>';
6956
        }
6957
6958
        $return .= '<tr>';
6959
        $return .= '<td class="label"><label for="idParent">' . get_lang('Parent') . '</label></td>';
6960
        $return .= '<td class="input">';
6961
        $return .= '<select id="idParent" style="width:100%;" name="parent" onChange="javascript: load_cbo(this.value);" class="learnpath_item_form" size="1">';
6962
        $return .= '<option class="top" value="0">' . $this->name . '</option>';
6963
        $arrHide = array(
6964
            $id
6965
        );
6966
6967
        //$parent_item_id = $_SESSION['parent_item_id'];
6968 View Code Duplication
        for ($i = 0; $i < count($arrLP); $i++) {
6969
            if ($action != 'add') {
6970
                if (($arrLP[$i]['item_type'] == 'dokeos_module' || $arrLP[$i]['item_type'] == 'dokeos_chapter' || $arrLP[$i]['item_type'] == 'dir') && !in_array($arrLP[$i]['id'], $arrHide) && !in_array($arrLP[$i]['parent_item_id'], $arrHide)) {
6971
                    $return .= '<option ' . (($parent == $arrLP[$i]['id']) ? 'selected="selected" ' : '') . 'style="padding-left:' . ($arrLP[$i]['depth'] * 10) . 'px;" value="' . $arrLP[$i]['id'] . '">' . $arrLP[$i]['title'] . '</option>';
6972
                } else {
6973
                    $arrHide[] = $arrLP[$i]['id'];
6974
                }
6975
            } else {
6976
                if ($arrLP[$i]['item_type'] == 'dokeos_module' || $arrLP[$i]['item_type'] == 'dokeos_chapter' || $arrLP[$i]['item_type'] == 'dir')
6977
                    $return .= '<option ' . (($parent == $arrLP[$i]['id']) ? 'selected="selected" ' : '') . 'style="padding-left:' . ($arrLP[$i]['depth'] * 10) . 'px;" value="' . $arrLP[$i]['id'] . '">' . $arrLP[$i]['title'] . '</option>';
6978
            }
6979
        }
6980
        if (is_array($arrLP)) {
6981
            reset($arrLP);
6982
        }
6983
6984
        $return .= '</select>';
6985
        $return .= '</td>';
6986
        $return .= '</tr>';
6987
        $return .= '<tr>';
6988
        $return .= '<td class="label"><label for="previous">' . get_lang('Position') . '</label></td>';
6989
        $return .= '<td class="input">';
6990
        $return .= '<select id="previous" name="previous" style="width:100%;" size="1" class="learnpath_item_form">';
6991
        $return .= '<option class="top" value="0">' . get_lang('FirstPosition') . '</option>';
6992
6993 View Code Duplication
        for ($i = 0; $i < count($arrLP); $i++) {
6994
            if ($arrLP[$i]['parent_item_id'] == $parent && $arrLP[$i]['id'] != $id) {
6995
                if ($extra_info['previous_item_id'] == $arrLP[$i]['id'])
6996
                    $selected = 'selected="selected" ';
6997
                elseif ($action == 'add') $selected = 'selected="selected" ';
6998
                else
6999
                    $selected = '';
7000
7001
                $return .= '<option ' . $selected . 'value="' . $arrLP[$i]['id'] . '">' .
7002
                    get_lang('After') . ' "' . $arrLP[$i]['title'] . '"</option>';
7003
            }
7004
        }
7005
7006
        $return .= '</select>';
7007
        $return .= '</td>';
7008
        $return .= '</tr>';
7009
        if ($action != 'move') {
7010
            $return .= '<tr>';
7011
            $return .= '</tr>';
7012
            $id_prerequisite = 0;
7013
            if (is_array($arrLP)) {
7014
                foreach ($arrLP as $key => $value) {
7015
                    if ($value['id'] == $id) {
7016
                        $id_prerequisite = $value['prerequisite'];
7017
                        break;
7018
                    }
7019
                }
7020
            }
7021
7022
            $arrHide = array();
7023
            for ($i = 0; $i < count($arrLP); $i++) {
7024
                if ($arrLP[$i]['id'] != $id && $arrLP[$i]['item_type'] != 'dokeos_chapter') {
7025
                    if ($extra_info['previous_item_id'] == $arrLP[$i]['id'])
7026
                        $s_selected_position = $arrLP[$i]['id'];
7027
                    elseif ($action == 'add') $s_selected_position = 0;
7028
                    $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title'];
7029
                }
7030
            }
7031
            $return .= '</tr>';
7032
        }
7033
        $return .= '<tr>';
7034
7035
        if ($action == 'add') {
7036
            $return .= '<td>&nbsp;</td><td><button class="save" name="submit_button" type="submit"> ' . get_lang('AddForumToCourse') . ' </button></td>';
7037
        } else {
7038
            $return .= '<td>&nbsp;</td><td><button class="save" name="submit_button" type="submit"> ' . get_lang('EditCurrentForum') . ' </button></td>';
7039
        }
7040
        $return .= '</tr>';
7041
        $return .= '</table>';
7042
7043 View Code Duplication
        if ($action == 'move') {
7044
            $return .= '<input name="title" type="hidden" value="' . $item_title . '" />';
7045
            $return .= '<input name="description" type="hidden" value="' . $item_description . '" />';
7046
        }
7047
7048 View Code Duplication
        if (is_numeric($extra_info)) {
7049
            $return .= '<input name="path" type="hidden" value="' . $extra_info . '" />';
7050
        } elseif (is_array($extra_info)) {
7051
            $return .= '<input name="path" type="hidden" value="' . $extra_info['path'] . '" />';
7052
        }
7053
        $return .= '<input name="type" type="hidden" value="' . TOOL_FORUM . '" />';
7054
        $return .= '<input name="post_time" type="hidden" value="' . time() . '" />';
7055
        $return .= '</form>';
7056
        $return .= '</div>';
7057
7058
        return $return;
7059
    }
7060
7061
    /**
7062
     * Return HTML form to add/edit forum threads
7063
     * @param	string	Action (add/edit)
7064
     * @param	integer	Item ID if already exists in learning path
7065
     * @param	mixed	Extra information (thread ID if integer)
7066
     * @return 	string	HTML form
7067
     */
7068
    public function display_thread_form($action = 'add', $id = 0, $extra_info = '')
7069
    {
7070
        $course_id = api_get_course_int_id();
7071
        if (empty($course_id)) {
7072
            return null;
7073
        }
7074
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
7075
        $tbl_forum = Database :: get_course_table(TABLE_FORUM_THREAD);
7076
7077
        if ($id != 0 && is_array($extra_info)) {
7078
            $item_title = stripslashes($extra_info['title']);
7079 View Code Duplication
        } elseif (is_numeric($extra_info)) {
7080
            $sql = "SELECT thread_title as title FROM $tbl_forum
7081
                    WHERE c_id = $course_id AND thread_id = " . $extra_info;
7082
7083
            $result = Database::query($sql);
7084
            $row = Database :: fetch_array($result);
7085
7086
            $item_title = $row['title'];
7087
            $item_description = '';
7088
        } else {
7089
            $item_title = '';
7090
            $item_description = '';
7091
        }
7092
7093
        $return = null;
7094
7095 View Code Duplication
        if ($id != 0 && is_array($extra_info)) {
7096
            $parent = $extra_info['parent_item_id'];
7097
        } else {
7098
            $parent = 0;
7099
        }
7100
7101
        $sql = "SELECT * FROM " . $tbl_lp_item . "
7102
                WHERE c_id = ".$course_id." AND lp_id = " . $this->lp_id;
7103
7104
        $result = Database::query($sql);
7105
7106
        $arrLP = array ();
7107
7108 View Code Duplication
        while ($row = Database :: fetch_array($result)) {
7109
            $arrLP[] = array (
7110
                'id' => $row['id'],
7111
                'item_type' => $row['item_type'],
7112
                'title' => $row['title'],
7113
                'path' => $row['path'],
7114
                'description' => $row['description'],
7115
                'parent_item_id' => $row['parent_item_id'],
7116
                'previous_item_id' => $row['previous_item_id'],
7117
                'next_item_id' => $row['next_item_id'],
7118
                'display_order' => $row['display_order'],
7119
                'max_score' => $row['max_score'],
7120
                'min_score' => $row['min_score'],
7121
                'mastery_score' => $row['mastery_score'],
7122
                'prerequisite' => $row['prerequisite']
7123
            );
7124
        }
7125
7126
        $this->tree_array($arrLP);
7127
        $arrLP = isset($this->arrMenu) ? $this->arrMenu : null;
7128
        unset ($this->arrMenu);
7129
7130
        $return .= '<form method="POST">';
7131
        if ($action == 'add')
7132
            $return .= '<legend>' . get_lang('CreateTheForum') . '</legend>';
7133
        elseif ($action == 'move') $return .= '<p class="lp_title">' . get_lang('MoveTheCurrentForum') . '&nbsp;:</p>';
7134
        else
7135
            $return .= '<legend>' . get_lang('EditCurrentForum') . '</legend>';
7136
7137
        $return .= '<table cellpadding="0" cellspacing="0" class="lp_form">';
7138
        $return .= '<tr>';
7139
        $return .= '<td class="label"><label for="idParent">' . get_lang('Parent') . '</label></td>';
7140
        $return .= '<td class="input">';
7141
        $return .= '<select id="idParent" name="parent" onChange="javascript: load_cbo(this.value);" size="1">';
7142
        $return .= '<option class="top" value="0">' . $this->name . '</option>';
7143
        $arrHide = array (
7144
            $id
7145
        );
7146
7147 View Code Duplication
        for ($i = 0; $i < count($arrLP); $i++) {
7148
            if ($action != 'add') {
7149
                if (($arrLP[$i]['item_type'] == 'dokeos_module' || $arrLP[$i]['item_type'] == 'dokeos_chapter' || $arrLP[$i]['item_type'] == 'dir') && !in_array($arrLP[$i]['id'], $arrHide) && !in_array($arrLP[$i]['parent_item_id'], $arrHide)) {
7150
                    $return .= '<option ' . (($parent == $arrLP[$i]['id']) ? 'selected="selected" ' : '') . 'style="padding-left:' . ($arrLP[$i]['depth'] * 10) . 'px;" value="' . $arrLP[$i]['id'] . '">' . $arrLP[$i]['title'] . '</option>';
7151
                } else {
7152
                    $arrHide[] = $arrLP[$i]['id'];
7153
                }
7154
            } else {
7155
                if ($arrLP[$i]['item_type'] == 'dokeos_module' || $arrLP[$i]['item_type'] == 'dokeos_chapter' || $arrLP[$i]['item_type'] == 'dir')
7156
                    $return .= '<option ' . (($parent == $arrLP[$i]['id']) ? 'selected="selected" ' : '') . 'style="padding-left:' . ($arrLP[$i]['depth'] * 10) . 'px;" value="' . $arrLP[$i]['id'] . '">' . $arrLP[$i]['title'] . '</option>';
7157
            }
7158
        }
7159
7160
        if ($arrLP != null) {
7161
            reset($arrLP);
7162
        }
7163
7164
        $return .= '</select>';
7165
        $return .= '</td>';
7166
        $return .= '</tr>';
7167
        $return .= '<tr>';
7168
        $return .= '<td class="label"><label for="previous">' . get_lang('Position') . '</label></td>';
7169
        $return .= '<td class="input">';
7170
        $return .= '<select id="previous" name="previous" size="1">';
7171
        $return .= '<option class="top" value="0">' . get_lang('FirstPosition') . '</option>';
7172 View Code Duplication
        for ($i = 0; $i < count($arrLP); $i++) {
7173
            if ($arrLP[$i]['parent_item_id'] == $parent && $arrLP[$i]['id'] != $id) {
7174
                if ($extra_info['previous_item_id'] == $arrLP[$i]['id'])
7175
                    $selected = 'selected="selected" ';
7176
                elseif ($action == 'add') $selected = 'selected="selected" ';
7177
                else
7178
                    $selected = '';
7179
7180
                $return .= '<option ' . $selected . 'value="' . $arrLP[$i]['id'] . '">' . get_lang('After') . ' "' . $arrLP[$i]['title'] . '"</option>';
7181
            }
7182
        }
7183
        $return .= '</select>';
7184
        $return .= '</td>';
7185
        $return .= '</tr>';
7186
        if ($action != 'move') {
7187
            $return .= '<tr>';
7188
            $return .= '<td class="label"><label for="idTitle">' . get_lang('Title') . '</label></td>';
7189
            $return .= '<td class="input"><input id="idTitle" name="title" type="text" value="' . $item_title . '" /></td>';
7190
            $return .= '</tr>';
7191
            $return .= '<tr>';
7192
            $return .= '</tr>';
7193
7194
            $id_prerequisite = 0;
7195
            if ($arrLP != null) {
7196
                foreach ($arrLP as $key => $value) {
7197
                    if ($value['id'] == $id) {
7198
                        $id_prerequisite = $value['prerequisite'];
7199
                        break;
7200
                    }
7201
                }
7202
            }
7203
7204
            $arrHide = array();
7205
            for ($i = 0; $i < count($arrLP); $i++) {
7206
                if ($arrLP[$i]['id'] != $id && $arrLP[$i]['item_type'] != 'dokeos_chapter') {
7207
                    if ($extra_info['previous_item_id'] == $arrLP[$i]['id'])
7208
                        $s_selected_position = $arrLP[$i]['id'];
7209
                    elseif ($action == 'add') $s_selected_position = 0;
7210
                    $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title'];
7211
7212
                }
7213
            }
7214
7215
            $return .= '<tr>';
7216
            $return .= '<td class="label"><label for="idPrerequisites">' . get_lang('LearnpathPrerequisites') . '</label></td>';
7217
            $return .= '<td class="input"><select name="prerequisites" id="prerequisites"><option value="0">' . get_lang('NoPrerequisites') . '</option>';
7218
7219
            foreach ($arrHide as $key => $value) {
7220
                if ($key == $s_selected_position && $action == 'add') {
7221
                    $return .= '<option value="' . $key . '" selected="selected">' . $value['value'] . '</option>';
7222
                }
7223
                elseif ($key == $id_prerequisite && $action == 'edit') {
7224
                    $return .= '<option value="' . $key . '" selected="selected">' . $value['value'] . '</option>';
7225
                } else {
7226
                    $return .= '<option value="' . $key . '">' . $value['value'] . '</option>';
7227
                }
7228
            }
7229
            $return .= "</select></td>";
7230
            $return .= '</tr>';
7231
7232
        }
7233
        $return .= '<tr>';
7234
        $return .= '<td></td><td>
7235
                    <button class="save" name="submit_button" type="submit" value="'.get_lang('Ok').'" />'.get_lang('Ok').'</button></td>';
7236
        $return .= '</tr>';
7237
        $return .= '</table>';
7238
7239 View Code Duplication
        if ($action == 'move') {
7240
            $return .= '<input name="title" type="hidden" value="' . $item_title . '" />';
7241
            $return .= '<input name="description" type="hidden" value="' . $item_description . '" />';
7242
        }
7243
7244 View Code Duplication
        if (is_numeric($extra_info)) {
7245
            $return .= '<input name="path" type="hidden" value="' . $extra_info . '" />';
7246
        }
7247
        elseif (is_array($extra_info)) {
7248
            $return .= '<input name="path" type="hidden" value="' . $extra_info['path'] . '" />';
7249
        }
7250
7251
        $return .= '<input name="type" type="hidden" value="' . TOOL_THREAD . '" />';
7252
        $return .= '<input name="post_time" type="hidden" value="' . time() . '" />';
7253
        $return .= '</form>';
7254
        $return .= '</div>';
7255
7256
        return $return;
7257
    }
7258
7259
    /**
7260
     * Return the HTML form to display an item (generally a section/module item)
7261
     * @param	string	Item type (module/dokeos_module)
7262
     * @param	string	Title (optional, only when creating)
7263
     * @param	string	Action ('add'/'edit')
7264
     * @param	integer	lp_item ID
7265
     * @param	mixed	Extra info
7266
     * @return	string 	HTML form
7267
     */
7268
    public function display_item_form($item_type, $title = '', $action = 'add_item', $id = 0, $extra_info = 'new')
7269
    {
7270
        $course_id = api_get_course_int_id();
7271
        $_course = api_get_course_info();
7272
7273
        global $charset;
7274
7275
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
7276
7277
        if ($id != 0 && is_array($extra_info)) {
7278
            $item_title 		= $extra_info['title'];
7279
            $item_description 	= $extra_info['description'];
7280
            $item_path = api_get_path(WEB_COURSE_PATH) . $_course['path'] . '/scorm/' . $this->path . '/' . stripslashes($extra_info['path']);
7281
            $item_path_fck = '/scorm/' . $this->path . '/' . stripslashes($extra_info['path']);
7282
        } else {
7283
            $item_title = '';
7284
            $item_description = '';
7285
            $item_path_fck = '';
7286
        }
7287
7288 View Code Duplication
        if ($id != 0 && is_array($extra_info)) {
7289
            $parent = $extra_info['parent_item_id'];
7290
        } else {
7291
            $parent = 0;
7292
        }
7293
7294
        $id  = intval($id);
7295
        $sql = "SELECT * FROM " . $tbl_lp_item . "
7296
                WHERE
7297
                    c_id = ".$course_id." AND
7298
                    lp_id = " . $this->lp_id . " AND
7299
                    id != $id";
7300
7301
        if ($item_type == 'module')
7302
            $sql .= " AND parent_item_id = 0";
7303
7304
        $result = Database::query($sql);
7305
        $arrLP = array ();
7306
7307 View Code Duplication
        while ($row = Database :: fetch_array($result)) {
7308
            $arrLP[] = array(
7309
                'id' => $row['id'],
7310
                'item_type' => $row['item_type'],
7311
                'title' => $row['title'],
7312
                'path' => $row['path'],
7313
                'description' => $row['description'],
7314
                'parent_item_id' => $row['parent_item_id'],
7315
                'previous_item_id' => $row['previous_item_id'],
7316
                'next_item_id' => $row['next_item_id'],
7317
                'max_score' => $row['max_score'],
7318
                'min_score' => $row['min_score'],
7319
                'mastery_score' => $row['mastery_score'],
7320
                'prerequisite' => $row['prerequisite'],
7321
                'display_order' => $row['display_order']
7322
            );
7323
        }
7324
7325
        $this->tree_array($arrLP);
7326
7327
        $arrLP = isset($this->arrMenu) ? $this->arrMenu : null;
7328
7329
        unset ($this->arrMenu);
7330
7331
        $gradebook = isset($_GET['gradebook']) ? Security :: remove_XSS($_GET['gradebook']) : null;
7332
7333
        $url = api_get_self() . '?' .api_get_cidreq().'&gradeboook='.$gradebook.'&action='.$action.'&type='.$item_type.'&lp_id='.$this->lp_id;
7334
7335
        $form = new FormValidator('form', 'POST',  $url);
7336
7337
        $defaults['title'] = api_html_entity_decode($item_title, ENT_QUOTES, $charset);
7338
        $defaults['description'] = $item_description;
7339
7340
        $form->addElement('header', $title);
7341
7342
        //$arrHide = array($id);
7343
        $arrHide[0]['value'] = Security :: remove_XSS($this->name);
7344
        $arrHide[0]['padding'] = 3;
7345
        $charset = api_get_system_encoding();
7346
7347
        if ($item_type != 'module' && $item_type != 'dokeos_module') {
7348 View Code Duplication
            for ($i = 0; $i < count($arrLP); $i++) {
7349
                if ($action != 'add') {
7350
                    if (($arrLP[$i]['item_type'] == 'dokeos_module' || $arrLP[$i]['item_type'] == 'dokeos_chapter' || $arrLP[$i]['item_type'] == 'dir') && !in_array($arrLP[$i]['id'], $arrHide) && !in_array($arrLP[$i]['parent_item_id'], $arrHide)) {
7351
                        $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title'];
7352
                        $arrHide[$arrLP[$i]['id']]['padding'] = 3 + $arrLP[$i]['depth'] * 10;
7353
                        if ($parent == $arrLP[$i]['id']) {
7354
                            $s_selected_parent = $arrHide[$arrLP[$i]['id']];
7355
                        }
7356
                    }
7357
                } else {
7358
                    if ($arrLP[$i]['item_type'] == 'dokeos_module' || $arrLP[$i]['item_type'] == 'dokeos_chapter' || $arrLP[$i]['item_type'] == 'dir') {
7359
                        $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title'];
7360
                        $arrHide[$arrLP[$i]['id']]['padding'] = 3 + $arrLP[$i]['depth'] * 10;
7361
                        if ($parent == $arrLP[$i]['id']) {
7362
                            $s_selected_parent = $arrHide[$arrLP[$i]['id']];
7363
                        }
7364
                    }
7365
                }
7366
            }
7367
7368
            if ($action != 'move') {
7369
                $form->addElement('text', 'title', get_lang('Title'));
7370
                $form->applyFilter('title', 'html_filter');
7371
                $form->addRule('title', get_lang('ThisFieldIsRequired'), 'required');
7372
            } else {
7373
                $form->addElement('hidden', 'title');
7374
            }
7375
7376
            $parent_select = $form->addElement('select', 'parent', get_lang('Parent'), '', array('id' => 'idParent', 'onchange' => "javascript: load_cbo(this.value);"));
7377
7378
            foreach ($arrHide as $key => $value) {
7379
                $parent_select->addOption($value['value'], $key, 'style="padding-left:' . $value['padding'] . 'px;"');
7380
            }
7381
            if (!empty($s_selected_parent)) {
7382
                $parent_select->setSelected($s_selected_parent);
7383
            }
7384
        }
7385
        if (is_array($arrLP)) {
7386
            reset($arrLP);
7387
        }
7388
7389
        $arrHide = array();
7390
7391
        // POSITION
7392
        for ($i = 0; $i < count($arrLP); $i++) {
7393
            if ($arrLP[$i]['parent_item_id'] == $parent && $arrLP[$i]['id'] != $id) {
7394
                //this is the same!
7395
                if (isset($extra_info['previous_item_id']) && $extra_info['previous_item_id'] == $arrLP[$i]['id']) {
7396
                    $s_selected_position = $arrLP[$i]['id'];
7397
                } elseif ($action == 'add') {
7398
                    $s_selected_position = $arrLP[$i]['id'];
7399
                }
7400
7401
                $arrHide[$arrLP[$i]['id']]['value'] = get_lang('After') . ' "' . $arrLP[$i]['title'] . '"';
7402
            }
7403
        }
7404
7405
        $position = $form->addElement('select', 'previous', get_lang('Position'), '', array('id' => 'previous'));
7406
        $padding = isset($value['padding']) ? $value['padding'] : 0;
7407
        $position->addOption(get_lang('FirstPosition'), 0, 'style="padding-left:' . $padding . 'px;"');
7408
7409
        foreach ($arrHide as $key => $value) {
7410
            $position->addOption($value['value'] . '"', $key, 'style="padding-left:' . $padding . 'px;"');
7411
        }
7412
7413
        if (!empty ($s_selected_position)) {
7414
            $position->setSelected($s_selected_position);
7415
        }
7416
7417
        if (is_array($arrLP)) {
7418
            reset($arrLP);
7419
        }
7420
7421
        $form->addButtonSave(get_lang('SaveSection'), 'submit_button');
7422
7423
        if ($item_type == 'module' || $item_type == 'dokeos_module') {
7424
            $form->addElement('hidden', 'parent', '0');
7425
        }
7426
        //fix in order to use the tab
7427
        if ($item_type == 'chapter') {
7428
            $form->addElement('hidden', 'type', 'chapter');
7429
        }
7430
7431
        $extension = null;
7432
        if (!empty($item_path)) {
7433
            $extension = pathinfo($item_path, PATHINFO_EXTENSION);
7434
        }
7435
7436
        //assets can't be modified
7437
7438
        //$item_type == 'asset' ||
7439
        if (( $item_type == 'sco') && ($extension == 'html' || $extension == 'htm')) {
7440
7441
            if ($item_type == 'sco') {
7442
                $form->addElement('html', '<script type="text/javascript">alert("' . get_lang('WarningWhenEditingScorm') . '")</script>');
7443
            }
7444
            $renderer = $form->defaultRenderer();
7445
            $renderer->setElementTemplate('<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{label}<br />{element}', 'content_lp');
7446
7447
            $relative_prefix = '';
7448
7449
            $editor_config = array( 'ToolbarSet' 			=> 'LearningPathDocuments',
7450
                'Width' 				=> '100%',
7451
                'Height' 				=> '500',
7452
                'FullPage' 				=> true,
7453
                'CreateDocumentDir' 	=> $relative_prefix,
7454
                'CreateDocumentWebDir' 	=> api_get_path(WEB_COURSE_PATH) . api_get_course_path().'/scorm/',
7455
                'BaseHref' 				=> api_get_path(WEB_COURSE_PATH) . api_get_course_path().$item_path_fck
7456
            );
7457
7458
            $form->addElement('html_editor', 'content_lp', '', null, $editor_config);
7459
            $content_path = (api_get_path(SYS_COURSE_PATH).api_get_course_path().$item_path_fck);
7460
            //$defaults['content_lp'] = file_get_contents($item_path);
7461
            $defaults['content_lp'] = file_get_contents($content_path);
7462
        }
7463
7464
        $form->addElement('hidden', 'type', 'dokeos_' . $item_type);
7465
        $form->addElement('hidden', 'post_time', time());
7466
        $form->setDefaults($defaults);
7467
        return $form->return_form();
0 ignored issues
show
Deprecated Code introduced by
The method FormValidator::return_form() has been deprecated with message: use returnForm()

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

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

Loading history...
7468
    }
7469
7470
    /**
7471
     * Returns the form to update or create a document
7472
     * @param	string	Action (add/edit)
7473
     * @param	integer	ID of the lp_item (if already exists)
7474
     * @param	mixed	Integer if document ID, string if info ('new')
7475
     * @return	string	HTML form
7476
     */
7477
    public function display_document_form($action = 'add', $id = 0, $extra_info = 'new')
7478
    {
7479
        $course_id = api_get_course_int_id();
7480
        $_course = api_get_course_info();
7481
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
7482
        $tbl_doc = Database :: get_course_table(TABLE_DOCUMENT);
7483
7484
        $no_display_edit_textarea = false;
7485
        $item_description = '';
7486
        //If action==edit document
7487
        //We don't display the document form if it's not an editable document (html or txt file)
7488
        if ($action == "edit") {
7489
            if (is_array($extra_info)) {
7490
                $path_parts = pathinfo($extra_info['dir']);
7491
                if ($path_parts['extension'] != "txt" && $path_parts['extension'] != "html") {
7492
                    $no_display_edit_textarea = true;
7493
                }
7494
            }
7495
        }
7496
        $no_display_add = false;
7497
7498
        // If action==add an existing document
7499
        // We don't display the document form if it's not an editable document (html or txt file).
7500
        if ($action == "add") {
7501
            if (is_numeric($extra_info)) {
7502
                $sql_doc = "SELECT path FROM " . $tbl_doc . "
7503
                            WHERE c_id = ".$course_id." AND id = " . intval($extra_info);
7504
                $result = Database::query($sql_doc);
7505
                $path_file = Database :: result($result, 0, 0);
7506
                $path_parts = pathinfo($path_file);
7507
                if ($path_parts['extension'] != "txt" && $path_parts['extension'] != "html") {
7508
                    $no_display_add = true;
7509
                }
7510
            }
7511
        }
7512
        if ($id != 0 && is_array($extra_info)) {
7513
            $item_title = stripslashes($extra_info['title']);
7514
            $item_description = stripslashes($extra_info['description']);
7515
            $item_terms = stripslashes($extra_info['terms']);
7516 View Code Duplication
            if (empty ($item_title)) {
7517
                $path_parts = pathinfo($extra_info['path']);
7518
                $item_title = stripslashes($path_parts['filename']);
7519
            }
7520
        } elseif (is_numeric($extra_info)) {
7521
            $sql_doc = "SELECT path, title FROM " . $tbl_doc . "
7522
                        WHERE
7523
                            c_id = ".$course_id." AND
7524
                            id = " . intval($extra_info);
7525
7526
            $result = Database::query($sql_doc);
7527
            $row 	= Database::fetch_array($result);
7528
            $item_title = $row['title'];
7529
            $item_title = str_replace('_', ' ', $item_title);
7530 View Code Duplication
            if (empty ($item_title)) {
7531
                $path_parts = pathinfo($row['path']);
7532
                $item_title = stripslashes($path_parts['filename']);
7533
            }
7534
        } else {
7535
            $item_title = '';
7536
            $item_description = '';
7537
        }
7538
        $return = '<legend>';
7539
7540 View Code Duplication
        if ($id != 0 && is_array($extra_info)) {
7541
            $parent = $extra_info['parent_item_id'];
7542
        } else {
7543
            $parent = 0;
7544
        }
7545
7546
        $sql = "SELECT * FROM " . $tbl_lp_item . "
7547
                WHERE c_id = ".$course_id." AND lp_id = " . $this->lp_id;
7548
7549
        $result = Database::query($sql);
7550
        $arrLP = array ();
7551 View Code Duplication
        while ($row = Database :: fetch_array($result)) {
7552
            $arrLP[] = array(
7553
                'id' => $row['id'],
7554
                'item_type' => $row['item_type'],
7555
                'title' => $row['title'],
7556
                'path' => $row['path'],
7557
                'description' => $row['description'],
7558
                'parent_item_id' => $row['parent_item_id'],
7559
                'previous_item_id' => $row['previous_item_id'],
7560
                'next_item_id' => $row['next_item_id'],
7561
                'display_order' => $row['display_order'],
7562
                'max_score' => $row['max_score'],
7563
                'min_score' => $row['min_score'],
7564
                'mastery_score' => $row['mastery_score'],
7565
                'prerequisite' => $row['prerequisite']
7566
            );
7567
        }
7568
7569
        $this->tree_array($arrLP);
7570
        $arrLP = isset($this->arrMenu) ? $this->arrMenu : null;
7571
        unset ($this->arrMenu);
7572
7573
        if ($action == 'add') {
7574
            $return .= get_lang('CreateTheDocument');
7575
        } elseif ($action == 'move') {
7576
            $return .= get_lang('MoveTheCurrentDocument');
7577
        } else {
7578
            $return .= get_lang('EditTheCurrentDocument');
7579
        }
7580
7581
        $return .= '</legend>';
7582
7583 View Code Duplication
        if (isset ($_GET['edit']) && $_GET['edit'] == 'true') {
7584
            $return .= Display :: return_warning_message('<strong>' . get_lang('Warning') . ' !</strong><br />' . get_lang('WarningEditingDocument'), false);
7585
        }
7586
        $form = new FormValidator('form', 'POST', api_get_self() . '?' .$_SERVER['QUERY_STRING'], '', array('enctype'=> "multipart/form-data"));
7587
        $defaults['title'] = Security :: remove_XSS($item_title);
7588
        if (empty($item_title)) {
7589
            $defaults['title'] = Security::remove_XSS($item_title);
7590
        }
7591
        $defaults['description'] = $item_description;
7592
        $form->addElement('html', $return);
7593
        if ($action != 'move') {
7594
            $form->addElement('text', 'title', get_lang('Title'), array('id' => 'idTitle', 'class' => 'col-md-4'));
7595
            $form->applyFilter('title', 'html_filter');
7596
        }
7597
7598
        $arrHide[0]['value'] = $this->name;
7599
        $arrHide[0]['padding'] = 3;
7600
7601 View Code Duplication
        for ($i = 0; $i < count($arrLP); $i++) {
7602
            if ($action != 'add') {
7603
                if (($arrLP[$i]['item_type'] == 'dokeos_module' || $arrLP[$i]['item_type'] == 'dokeos_chapter' || $arrLP[$i]['item_type'] == 'dir') && !in_array($arrLP[$i]['id'], $arrHide) && !in_array($arrLP[$i]['parent_item_id'], $arrHide)) {
7604
                    $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title'];
7605
                    $arrHide[$arrLP[$i]['id']]['padding'] = 3 + $arrLP[$i]['depth'] * 10;
7606
                    if ($parent == $arrLP[$i]['id']) {
7607
                        $s_selected_parent = $arrHide[$arrLP[$i]['id']];
7608
                    }
7609
                }
7610
            } else {
7611
                if ($arrLP[$i]['item_type'] == 'dokeos_module' || $arrLP[$i]['item_type'] == 'dokeos_chapter' || $arrLP[$i]['item_type'] == 'dir') {
7612
                    $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title'];
7613
                    $arrHide[$arrLP[$i]['id']]['padding'] = 3 + $arrLP[$i]['depth'] * 10;
7614
                    if ($parent == $arrLP[$i]['id']) {
7615
                        $s_selected_parent = $arrHide[$arrLP[$i]['id']];
7616
                    }
7617
                }
7618
            }
7619
        }
7620
7621
        $parent_select = $form->addElement('select', 'parent', get_lang('Parent'), '', 'class="form-control" id="idParent" " onchange="javascript: load_cbo(this.value);"');
7622
        $my_count=0;
7623
        foreach ($arrHide as $key => $value) {
7624
            if ($my_count!=0) {
7625
                // The LP name is also the first section and is not in the same charset like the other sections.
7626
                $value['value'] = Security :: remove_XSS($value['value']);
7627
                $parent_select->addOption($value['value'], $key, 'style="padding-left:' . $value['padding'] . 'px;"');
7628
            } else {
7629
                $value['value'] = Security :: remove_XSS($value['value']);
7630
                $parent_select->addOption($value['value'], $key, 'style="padding-left:' . $value['padding'] . 'px;"');
7631
            }
7632
            $my_count++;
7633
        }
7634
7635
        if (!empty($id)) {
7636
            $parent_select->setSelected($parent);
7637
        } else {
7638
            $parent_item_id = isset($_SESSION['parent_item_id']) ? $_SESSION['parent_item_id'] : 0 ;
7639
            $parent_select->setSelected($parent_item_id);
7640
        }
7641
7642
        if (is_array($arrLP)) {
7643
            reset($arrLP);
7644
        }
7645
7646
        $arrHide = array();
7647
        $s_selected_position = null;
7648
7649
        //POSITION
7650
        for ($i = 0; $i < count($arrLP); $i++) {
7651
            if ($arrLP[$i]['parent_item_id'] == $parent && $arrLP[$i]['id'] != $id || $arrLP[$i]['item_type'] == TOOL_FINAL_ITEM) {
7652
                if (isset($extra_info['previous_item_id']) && $extra_info['previous_item_id'] == $arrLP[$i]['id'] || $action == 'add') {
7653
                    $s_selected_position = $arrLP[$i]['id'];
7654
                }
7655
                $arrHide[$arrLP[$i]['id']]['value'] = get_lang('After') . ' "' . $arrLP[$i]['title'] . '"';
7656
            }
7657
        }
7658
7659
        $position = $form->addElement('select', 'previous', get_lang('Position'), '', 'id="previous" class="form-control"');
7660
        $position->addOption(get_lang('FirstPosition'), 0);
7661
7662
        foreach ($arrHide as $key => $value) {
7663
            $padding = isset($value['padding']) ? $value['padding']: 0;
7664
            $position->addOption($value['value'], $key, 'style="padding-left:' . $padding . 'px;"');
7665
        }
7666
7667
        $position->setSelected($s_selected_position);
7668
7669
        if (is_array($arrLP)) {
7670
            reset($arrLP);
7671
        }
7672
7673
        if ($action != 'move') {
7674
            $id_prerequisite = 0;
7675
            if (is_array($arrLP)) {
7676
                foreach ($arrLP as $key => $value) {
7677
                    if ($value['id'] == $id) {
7678
                        $id_prerequisite = $value['prerequisite'];
7679
                        break;
7680
                    }
7681
                }
7682
            }
7683
7684
            $arrHide = array();
7685
7686
            for ($i = 0; $i < count($arrLP); $i++) {
7687
                if ($arrLP[$i]['id'] != $id && $arrLP[$i]['item_type'] != 'dokeos_chapter' && $arrLP[$i]['item_type'] !== TOOL_FINAL_ITEM) {
7688
                    if (isset($extra_info['previous_item_id']) && $extra_info['previous_item_id'] == $arrLP[$i]['id'])
7689
                        $s_selected_position = $arrLP[$i]['id'];
7690
                    elseif ($action == 'add') $s_selected_position = $arrLP[$i]['id'];
7691
7692
                    $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title'];
7693
7694
                }
7695
            }
7696
7697
            if (!$no_display_add) {
7698
                $item_type = isset($extra_info['item_type']) ? $extra_info['item_type'] : null;
7699
                $edit = isset($_GET['edit']) ? $_GET['edit'] : null;
7700
                if (($extra_info == 'new' || $item_type == TOOL_DOCUMENT || $item_type == TOOL_FINAL_ITEM || $edit == 'true')) {
7701
                    if (isset ($_POST['content']))
7702
                        $content = stripslashes($_POST['content']);
7703
                    elseif (is_array($extra_info)) {
7704
                        //If it's an html document or a text file
7705
                        if (!$no_display_edit_textarea) {
7706
                            $content = $this->display_document($extra_info['path'], false, false);
7707
                        }
7708
                    } elseif (is_numeric($extra_info))
7709
                        $content = $this->display_document($extra_info, false, false);
7710
                    else
7711
                        $content = '';
7712
7713
                    if (!$no_display_edit_textarea) {
7714
                        // We need to calculate here some specific settings for the online editor.
7715
                        // The calculated settings work for documents in the Documents tool
7716
                        // (on the root or in subfolders).
7717
                        // For documents in native scorm packages it is unclear whether the
7718
                        // online editor should be activated or not.
7719
7720
                        // A new document, it is in the root of the repository.
7721
                        $relative_path 	 = '';
7722
                        $relative_prefix = '';
7723
7724
                        if (is_array($extra_info) && $extra_info != 'new') {
7725
                            // The document already exists. Whe have to determine its relative path towards the repository root.
7726
                            $relative_path = explode('/', $extra_info['dir']);
7727
                            $cnt = count($relative_path) - 2;
7728
                            if ($cnt < 0) {
7729
                                $cnt = 0;
7730
                            }
7731
                            $relative_prefix = str_repeat('../', $cnt);
7732
                            $relative_path 	 = array_slice($relative_path, 1, $cnt);
7733
                            $relative_path 	 = implode('/', $relative_path);
7734
                            if (strlen($relative_path) > 0) {
7735
                                $relative_path = $relative_path . '/';
7736
                            }
7737
                        } else {
7738
                            $result = $this->generate_lp_folder($_course);
7739
                            $relative_path = api_substr($result['dir'], 1, strlen($result['dir']));
7740
                            $relative_prefix = '../../';
7741
                        }
7742
7743
                        $editor_config = array(
7744
                            'ToolbarSet'=> 'LearningPathDocuments',
7745
                            'Width' 				=> '100%',
7746
                            'Height' 				=> '500',
7747
                            'FullPage' 				=> true,
7748
                            'CreateDocumentDir' 	=> $relative_prefix,
7749
                            'CreateDocumentWebDir' 	=> api_get_path(WEB_COURSE_PATH) . api_get_course_path().'/document/',
7750
                            'BaseHref' 				=> api_get_path(WEB_COURSE_PATH) . api_get_course_path().'/document/'.$relative_path
7751
                        );
7752
7753
                        if ($_GET['action'] == 'add_item') {
7754
                            $class = 'add';
7755
                            $text = get_lang('LPCreateDocument');
7756
                        } else {
7757
                            if ($_GET['action'] == 'edit_item') {
7758
                                $class = 'save';
7759
                                $text = get_lang('SaveDocument');
7760
                            }
7761
                        }
7762
7763
                        $form->addButtonSave($text, 'submit_button');
7764
                        $renderer = $form->defaultRenderer();
7765
                        $renderer->setElementTemplate('&nbsp;{label}{element}', 'content_lp');
7766
                        $form->addElement('html', '<div class="editor-lp">');
7767
                        $form->addHtmlEditor('content_lp', null, null, true, $editor_config, true);
7768
                        $form->addElement('html', '</div>');
7769
                        $defaults['content_lp'] = $content;
7770
                    }
7771
                } elseif (is_numeric($extra_info)) {
7772
                    $form->addButtonSave(get_lang('SaveDocument'), 'submit_button');
7773
7774
                    $return = $this->display_document($extra_info, true, true, true);
7775
                    $form->addElement('html', $return);
7776
                }
7777
            }
7778
        }
7779
7780
        if ($action == 'move') {
7781
            $form->addElement('hidden', 'title', $item_title);
7782
            $form->addElement('hidden', 'description', $item_description);
7783
        }
7784
        if (is_numeric($extra_info)) {
7785
            $form->addButtonSave(get_lang('SaveDocument'), 'submit_button');
7786
            $form->addElement('hidden', 'path', $extra_info);
7787
        } elseif (is_array($extra_info)) {
7788
            $form->addButtonSave(get_lang('SaveDocument'), 'submit_button');
7789
            $form->addElement('hidden', 'path', $extra_info['path']);
7790
        }
7791
        $form->addElement('hidden', 'type', TOOL_DOCUMENT);
7792
        $form->addElement('hidden', 'post_time', time());
7793
        $form->setDefaults($defaults);
7794
7795
        return $form->return_form();
0 ignored issues
show
Deprecated Code introduced by
The method FormValidator::return_form() has been deprecated with message: use returnForm()

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

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

Loading history...
7796
    }
7797
7798
    /**
7799
     * Return HTML form to add/edit a link item
7800
     * @param string	$action (add/edit)
7801
     * @param integer	$id Item ID if exists
7802
     * @param mixed		$extra_info
7803
     * @return	string	HTML form
7804
     */
7805
    public function display_link_form($action = 'add', $id = 0, $extra_info = '')
7806
    {
7807
        $course_id = api_get_course_int_id();
7808
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
7809
        $tbl_link = Database :: get_course_table(TABLE_LINK);
7810
7811
        if ($id != 0 && is_array($extra_info)) {
7812
            $item_title = stripslashes($extra_info['title']);
7813
            $item_description = stripslashes($extra_info['description']);
7814
            $item_url = stripslashes($extra_info['url']);
7815
        } elseif (is_numeric($extra_info)) {
7816
            $extra_info = intval($extra_info);
7817
            $sql = "SELECT title, description, url FROM " . $tbl_link . "
7818
                    WHERE c_id = ".$course_id." AND id = " . $extra_info;
7819
            $result = Database::query($sql);
7820
            $row = Database :: fetch_array($result);
7821
            $item_title       = $row['title'];
7822
            $item_description = $row['description'];
7823
            $item_url = $row['url'];
7824
        } else {
7825
            $item_title = '';
7826
            $item_description = '';
7827
            $item_url = '';
7828
        }
7829
7830
        $legend = '<legend>';
7831
7832 View Code Duplication
        if ($id != 0 && is_array($extra_info)) {
7833
            $parent = $extra_info['parent_item_id'];
7834
        } else {
7835
            $parent = 0;
7836
        }
7837
7838
        $sql = "SELECT * FROM " . $tbl_lp_item . "
7839
                WHERE c_id = ".$course_id." AND lp_id = " . $this->lp_id;
7840
        $result = Database::query($sql);
7841
        $arrLP = array();
7842
7843 View Code Duplication
        while ($row = Database :: fetch_array($result)) {
7844
            $arrLP[] = array(
7845
                'id' => $row['id'],
7846
                'item_type' => $row['item_type'],
7847
                'title' => $row['title'],
7848
                'path' => $row['path'],
7849
                'description' => $row['description'],
7850
                'parent_item_id' => $row['parent_item_id'],
7851
                'previous_item_id' => $row['previous_item_id'],
7852
                'next_item_id' => $row['next_item_id'],
7853
                'display_order' => $row['display_order'],
7854
                'max_score' => $row['max_score'],
7855
                'min_score' => $row['min_score'],
7856
                'mastery_score' => $row['mastery_score'],
7857
                'prerequisite' => $row['prerequisite']
7858
            );
7859
        }
7860
7861
        $this->tree_array($arrLP);
7862
        $arrLP = isset($this->arrMenu) ? $this->arrMenu : null;
7863
        unset ($this->arrMenu);
7864
7865
        if ($action == 'add')
7866
            $legend .= get_lang('CreateTheLink') . '&nbsp;:';
7867
        elseif ($action == 'move') $legend .= get_lang('MoveCurrentLink') . '&nbsp;:';
7868
        else
7869
            $legend .= get_lang('EditCurrentLink') . '&nbsp;:';
7870
7871
        $legend .= '</legend>';
7872
7873
        $return = '<div class="sectioncomment">';
7874
        $return .= '<form method="POST">';
7875
        $return .= $legend;
7876
        $return .= '<table>';
7877
7878 View Code Duplication
        if ($action != 'move') {
7879
            $return .= '<tr>';
7880
            $return .= '<td class="label"><label for="idTitle">' . get_lang('Title') . '</label></td>';
7881
            $return .= '<td class="input"><input id="idTitle" name="title" size="44" type="text" value="' . $item_title . '" class="learnpath_item_form"/></td>';
7882
            $return .= '</tr>';
7883
        }
7884
7885
        $return .= '<tr>';
7886
        $return .= '<td class="label"><label for="idParent">' . get_lang('Parent') . '</label></td>';
7887
        $return .= '<td class="input">';
7888
        $return .= '<select id="idParent" style="width:100%;" name="parent" onChange="javascript: load_cbo(this.value);" class="learnpath_item_form" size="1">';
7889
        $return .= '<option class="top" value="0">' . $this->name . '</option>';
7890
        $arrHide = array(
7891
            $id
7892
        );
7893
7894
        $parent_item_id = $_SESSION['parent_item_id'];
7895
7896 View Code Duplication
        for ($i = 0; $i < count($arrLP); $i++) {
7897
            if ($action != 'add') {
7898
                if (($arrLP[$i]['item_type'] == 'dokeos_module' || $arrLP[$i]['item_type'] == 'dokeos_chapter' || $arrLP[$i]['item_type'] == 'dir') && !in_array($arrLP[$i]['id'], $arrHide) && !in_array($arrLP[$i]['parent_item_id'], $arrHide)) {
7899
                    $return .= '<option ' . (($parent == $arrLP[$i]['id']) ? 'selected="selected" ' : '') . 'style="padding-left:' . ($arrLP[$i]['depth'] * 10) . 'px;" value="' . $arrLP[$i]['id'] . '">' . $arrLP[$i]['title'] . '</option>';
7900
                } else {
7901
                    $arrHide[] = $arrLP[$i]['id'];
7902
                }
7903
            } else {
7904
                if ($arrLP[$i]['item_type'] == 'dokeos_module' || $arrLP[$i]['item_type'] == 'dokeos_chapter' || $arrLP[$i]['item_type'] == 'dir')
7905
                    $return .= '<option ' . (($parent_item_id == $arrLP[$i]['id']) ? 'selected="selected" ' : '') . 'style="padding-left:' . ($arrLP[$i]['depth'] * 10) . 'px;" value="' . $arrLP[$i]['id'] . '">' . $arrLP[$i]['title'] . '</option>';
7906
            }
7907
        }
7908
7909
        if (is_array($arrLP)) {
7910
            reset($arrLP);
7911
        }
7912
7913
        $return .= '</select>';
7914
        $return .= '</td>';
7915
        $return .= '</tr>';
7916
        $return .= '<tr>';
7917
        $return .= '<td class="label"><label for="previous">' . get_lang('Position') . '</label></td>';
7918
        $return .= '<td class="input">';
7919
7920
        $return .= '<select id="previous" name="previous" style="width:100%;" size="1" class="learnpath_item_form">';
7921
        $return .= '<option class="top" value="0">' . get_lang('FirstPosition') . '</option>';
7922 View Code Duplication
        for ($i = 0; $i < count($arrLP); $i++) {
7923
            if ($arrLP[$i]['parent_item_id'] == $parent && $arrLP[$i]['id'] != $id) {
7924
                if ($extra_info['previous_item_id'] == $arrLP[$i]['id'])
7925
                    $selected = 'selected="selected" ';
7926
                elseif ($action == 'add')
7927
                    $selected = 'selected="selected" ';
7928
                else
7929
                    $selected = '';
7930
7931
                $return .= '<option ' . $selected . 'value="' . $arrLP[$i]['id'] . '">' . get_lang('After') . ' "' . $arrLP[$i]['title'] . '"</option>';
7932
            }
7933
        }
7934
        $return .= '</select>';
7935
        $return .= '</td>';
7936
        $return .= '</tr>';
7937
7938
        if ($action != 'move') {
7939
            $return .= '<tr>';
7940
            $return .= '<td class="label"><label for="idURL">' . get_lang('Url') . '</label></td>';
7941
            $return .= '<td class="input"><input' . (is_numeric($extra_info) ? ' disabled="disabled"' : '') . ' id="idURL" name="url" style="width:99%;" type="text" value="' . $item_url . '" class="learnpath_item_form" /></td>';
7942
            $return .= '</tr>';
7943
            $id_prerequisite = 0;
7944
            if (is_array($arrLP)) {
7945
                foreach ($arrLP as $key => $value) {
7946
                    if ($value['id'] == $id) {
7947
                        $id_prerequisite = $value['prerequisite'];
7948
                        break;
7949
                    }
7950
                }
7951
            }
7952
7953
            $arrHide = array();
7954
            for ($i = 0; $i < count($arrLP); $i++) {
7955
                if ($arrLP[$i]['id'] != $id && $arrLP[$i]['item_type'] != 'dokeos_chapter') {
7956
                    if ($extra_info['previous_item_id'] == $arrLP[$i]['id'])
7957
                        $s_selected_position = $arrLP[$i]['id'];
7958
                    elseif ($action == 'add') $s_selected_position = 0;
7959
                    $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title'];
7960
7961
                }
7962
            }
7963
            $return .= '</tr>';
7964
        }
7965
7966
        $return .= '<tr>';
7967
        if ($action == 'add') {
7968
            $return .= '<td>&nbsp;</td><td><button class="save" name="submit_button" type="submit">' . get_lang('AddLinkToCourse') . '</button></td>';
7969
        } else {
7970
            $return .= '<td>&nbsp;</td><td><button class="save" name="submit_button" type="submit">' . get_lang('EditCurrentLink') . '</button></td>';
7971
        }
7972
        $return .= '</tr>';
7973
        $return .= '</table>';
7974
7975 View Code Duplication
        if ($action == 'move') {
7976
            $return .= '<input name="title" type="hidden" value="' . $item_title . '" />';
7977
            $return .= '<input name="description" type="hidden" value="' . $item_description . '" />';
7978
        }
7979
7980 View Code Duplication
        if (is_numeric($extra_info)) {
7981
            $return .= '<input name="path" type="hidden" value="' . $extra_info . '" />';
7982
        } elseif (is_array($extra_info)) {
7983
            $return .= '<input name="path" type="hidden" value="' . $extra_info['path'] . '" />';
7984
        }
7985
        $return .= '<input name="type" type="hidden" value="' . TOOL_LINK . '" />';
7986
        $return .= '<input name="post_time" type="hidden" value="' . time() . '" />';
7987
        $return .= '</form>';
7988
        $return .= '</div>';
7989
7990
        return $return;
7991
    }
7992
7993
    /**
7994
     * Return HTML form to add/edit a student publication (work)
7995
     * @param	string	Action (add/edit)
7996
     * @param	integer	Item ID if already exists
7997
     * @param	mixed	Extra info (work ID if integer)
7998
     * @return	string	HTML form
7999
     */
8000
    public function display_student_publication_form($action = 'add', $id = 0, $extra_info = '')
8001
    {
8002
        $course_id = api_get_course_int_id();
8003
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
8004
        $tbl_publication = Database :: get_course_table(TABLE_STUDENT_PUBLICATION);
8005
8006
        if ($id != 0 && is_array($extra_info)) {
8007
            $item_title = stripslashes($extra_info['title']);
8008
            $item_description = stripslashes($extra_info['description']);
8009
        } elseif (is_numeric($extra_info)) {
8010
            $extra_info = intval($extra_info);
8011
            $sql = "SELECT title, description
8012
                    FROM " . $tbl_publication . "
8013
                    WHERE c_id = ".$course_id." AND id = " . $extra_info;
8014
8015
            $result = Database::query($sql);
8016
            $row = Database :: fetch_array($result);
8017
8018
            $item_title = $row['title'];
8019
        } else {
8020
            $item_title = get_lang('Student_publication');
8021
        }
8022
8023 View Code Duplication
        if ($id != 0 && is_array($extra_info)) {
8024
            $parent = $extra_info['parent_item_id'];
8025
        } else {
8026
            $parent = 0;
8027
        }
8028
8029
        $sql = "SELECT * FROM " . $tbl_lp_item . "
8030
                WHERE c_id = ".$course_id." AND lp_id = " . $this->lp_id;
8031
8032
        $result = Database::query($sql);
8033
        $arrLP = array();
8034 View Code Duplication
        while ($row = Database :: fetch_array($result)) {
8035
            $arrLP[] = array (
8036
                'id' => $row['id'],
8037
                'item_type' => $row['item_type'],
8038
                'title' => $row['title'],
8039
                'path' => $row['path'],
8040
                'description' => $row['description'],
8041
                'parent_item_id' => $row['parent_item_id'],
8042
                'previous_item_id' => $row['previous_item_id'],
8043
                'next_item_id' => $row['next_item_id'],
8044
                'display_order' => $row['display_order'],
8045
                'max_score' => $row['max_score'],
8046
                'min_score' => $row['min_score'],
8047
                'mastery_score' => $row['mastery_score'],
8048
                'prerequisite' => $row['prerequisite']
8049
            );
8050
        }
8051
8052
        $this->tree_array($arrLP);
8053
        $arrLP = isset($this->arrMenu) ? $this->arrMenu : null;
8054
        unset ($this->arrMenu);
8055
8056
        $form = new FormValidator('frm_student_publication', 'post', '#');
8057
8058
        if ($action == 'add') {
8059
            $form->addHeader(get_lang('Student_publication'));
8060
        } elseif ($action == 'move') {
8061
            $form->addHeader(get_lang('MoveCurrentStudentPublication'));
8062
        } else {
8063
            $form->addHeader(get_lang('EditCurrentStudentPublication'));
8064
        }
8065
8066
        if ($action != 'move') {
8067
            $form->addText('title', get_lang('Title'), true, ['class' => 'learnpath_item_form', 'id' => 'idTitle']);
8068
        }
8069
8070
        $parentSelect = $form->addSelect(
8071
            'parent',
8072
            get_lang('Parent'),
8073
            ['0' => $this->name],
8074
            [
8075
                'onchange' => 'javascript: load_cbo(this.value);',
8076
                'class' => 'learnpath_item_form',
8077
                'id' => 'idParent'
8078
            ]
8079
        );
8080
8081
        $arrHide = array (
8082
            $id
8083
        );
8084
8085
        for ($i = 0; $i < count($arrLP); $i++) {
8086
            if ($action != 'add') {
8087
                if (
8088
                    (
8089
                        $arrLP[$i]['item_type'] == 'dokeos_module' ||
8090
                        $arrLP[$i]['item_type'] == 'dokeos_chapter' ||
8091
                        $arrLP[$i]['item_type'] == 'dir'
8092
                    ) &&
8093
                    !in_array($arrLP[$i]['id'], $arrHide) &&
8094
                    !in_array($arrLP[$i]['parent_item_id'], $arrHide)
8095
                ) {
8096
                    $parentSelect->addOption(
8097
                        $arrLP[$i]['title'],
8098
                        $arrLP[$i]['id'],
8099
                        ['style' => 'padding-left: ' . (($arrLP[$i]['depth'] * 10) + 20) . 'px;']
8100
                    );
8101
8102
                    if ($parent == $arrLP[$i]['id']) {
8103
                        $parentSelect->setSelected($arrLP[$i]['id']);
8104
                    }
8105
                } else {
8106
                    $arrHide[] = $arrLP[$i]['id'];
8107
                }
8108
            } else {
8109
                if (
8110
                    $arrLP[$i]['item_type'] == 'dokeos_module' ||
8111
                    $arrLP[$i]['item_type'] == 'dokeos_chapter' || $arrLP[$i]['item_type'] == 'dir'
8112
                ) {
8113
                    $parentSelect->addOption(
8114
                        $arrLP[$i]['title'],
8115
                        $arrLP[$i]['id'],
8116
                        ['style' => 'padding-left: ' . (($arrLP[$i]['depth'] * 10) + 20) . 'px;']
8117
                    );
8118
8119
                    if ($parent == $arrLP[$i]['id']) {
8120
                        $parentSelect->setSelected($arrLP[$i]['id']);
8121
                    }
8122
                }
8123
            }
8124
        }
8125
8126
        if (is_array($arrLP)) {
8127
            reset($arrLP);
8128
        }
8129
8130
        $previousSelect = $form->addSelect(
8131
            'previous',
8132
            get_lang('Position'),
8133
            ['0' => get_lang('FirstPosition')],
8134
            ['id' => 'previous', 'class' => 'learnpath_item_form']
8135
        );
8136
8137
        for ($i = 0; $i < count($arrLP); $i++) {
8138
            if ($arrLP[$i]['parent_item_id'] == $parent && $arrLP[$i]['id'] != $id) {
8139
                $previousSelect->addOption(
8140
                    get_lang('After') . ' "' . $arrLP[$i]['title'] . '"',
8141
                    $arrLP[$i]['id']
8142
                );
8143
8144
                if ($extra_info['previous_item_id'] == $arrLP[$i]['id']) {
8145
                    $previousSelect->setSelected($arrLP[$i]['id']);
8146
                } elseif ($action == 'add') {
8147
                    $previousSelect->setSelected($arrLP[$i]['id']);
8148
                }
8149
            }
8150
        }
8151
8152 View Code Duplication
        if ($action != 'move') {
8153
            $id_prerequisite = 0;
8154
            if (is_array($arrLP)) {
8155
                foreach ($arrLP as $key => $value) {
8156
                    if ($value['id'] == $id) {
8157
                        $id_prerequisite = $value['prerequisite'];
8158
                        break;
8159
                    }
8160
                }
8161
            }
8162
            $arrHide = array ();
8163
            for ($i = 0; $i < count($arrLP); $i++) {
8164
                if ($arrLP[$i]['id'] != $id && $arrLP[$i]['item_type'] != 'dokeos_chapter') {
8165
                    if ($extra_info['previous_item_id'] == $arrLP[$i]['id'])
8166
                        $s_selected_position = $arrLP[$i]['id'];
8167
                    elseif ($action == 'add') $s_selected_position = 0;
8168
                    $arrHide[$arrLP[$i]['id']]['value'] = $arrLP[$i]['title'];
8169
8170
                }
8171
            }
8172
        }
8173
8174
        if ($action == 'add') {
8175
            $form->addButtonCreate(get_lang('AddAssignmentToCourse'), 'submit_button');
8176
        } else {
8177
            $form->addButtonCreate(get_lang('EditCurrentStudentPublication'), 'submit_button');
8178
        }
8179
8180
        if ($action == 'move') {
8181
            $form->addHidden('title', $item_title);
8182
            $form->addHidden('description', $item_description);
8183
        }
8184
8185
        if (is_numeric($extra_info)) {
8186
            $form->addHidden('path', $extra_info);
8187
        } elseif (is_array($extra_info)) {
8188
            $form->addHidden('path', $extra_info['path']);
8189
        }
8190
8191
        $form->addHidden('type', TOOL_STUDENTPUBLICATION);
8192
        $form->addHidden('post_time', time());
8193
        $form->setDefaults(['title' => $item_title]);
8194
8195
        $return = '<div class="sectioncomment">';
8196
        $return .= $form->returnForm();
8197
        $return .= '</div>';
8198
8199
        return $return;
8200
    }
8201
8202
    /**
8203
     * Displays the menu for manipulating a step
8204
     *
8205
     * @param $item_id
8206
     * @param string $item_type
8207
     * @return string
8208
     */
8209
    public function display_manipulate($item_id, $item_type = TOOL_DOCUMENT)
8210
    {
8211
        $_course = api_get_course_info();
8212
        $course_id = api_get_course_int_id();
8213
        $course_code = api_get_course_id();
8214
8215
        $return = '<div class="actions">';
8216
8217
        switch ($item_type) {
8218
            case 'dokeos_chapter' :
8219
            case 'chapter' :
8220
                // Commented the message cause should not show it.
8221
                //$lang = get_lang('TitleManipulateChapter');
8222
                break;
8223
8224
            case 'dokeos_module' :
8225
            case 'module' :
8226
                // Commented the message cause should not show it.
8227
                //$lang = get_lang('TitleManipulateModule');
8228
                break;
8229
            case TOOL_FINAL_ITEM :
8230
            case TOOL_DOCUMENT :
8231
                // Commented the message cause should not show it.
8232
                //$lang = get_lang('TitleManipulateDocument');
8233
                break;
8234
8235
            case TOOL_LINK :
8236
            case 'link' :
8237
                // Commented the message cause should not show it.
8238
                //$lang = get_lang('TitleManipulateLink');
8239
                break;
8240
8241
            case TOOL_QUIZ :
8242
                // Commented the message cause should not show it.
8243
                //$lang = get_lang('TitleManipulateQuiz');
8244
                break;
8245
8246
            case TOOL_STUDENTPUBLICATION :
8247
                // Commented the message cause should not show it.
8248
                //$lang = get_lang('TitleManipulateStudentPublication');
8249
                break;
8250
        }
8251
8252
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
8253
        $item_id = intval($item_id);
8254
        $sql = "SELECT * FROM " . $tbl_lp_item . " as lp
8255
                WHERE lp.c_id = ".$course_id." AND lp.id = " . $item_id;
8256
        $result = Database::query($sql);
8257
        $row = Database::fetch_assoc($result);
8258
8259
        $audio_player = null;
8260
        // We display an audio player if needed.
8261
        if (!empty($row['audio'])) {
8262
            $audio_player .= '<div class="lp_mediaplayer" id="container">
8263
                              <a href="http://www.macromedia.com/go/getflashplayer">Get the Flash Player</a> to see this player.
8264
                              </div>';
8265
            $audio_player .= '<script type="text/javascript" src="../inc/lib/mediaplayer/swfobject.js"></script>';
8266
            $audio_player .= '<script>
8267
                                var s1 = new SWFObject("../inc/lib/mediaplayer/player.swf","ply","250","20","9","#FFFFFF");
8268
                                s1.addParam("allowscriptaccess","always");
8269
                                s1.addParam("flashvars","file=../../courses/' . $_course['path'] . '/document/audio/' . $row['audio'] . '&autostart=true");
8270
                                s1.write("container");
8271
                            </script>';
8272
        }
8273
8274
        $url = api_get_self().'?cidReq='.Security::remove_XSS($_GET['cidReq']).'&view=build&id='.$item_id .'&lp_id='.$this->lp_id;
8275
8276
        $return .= Display::url(
8277
            Display::return_icon('edit.png', get_lang('Edit'), array(), ICON_SIZE_SMALL),
8278
            $url.'&action=edit_item&path_item=' . $row['path']
8279
        );
8280
8281
        $return .= Display::url(
8282
            Display::return_icon('move.png', get_lang('Move'), array(), ICON_SIZE_SMALL),
8283
            $url.'&action=move_item'
8284
        );
8285
8286
        // Commented for now as prerequisites cannot be added to chapters.
8287
        if ($item_type != 'dokeos_chapter' && $item_type != 'chapter') {
8288
            $return .= Display::url(
8289
                Display::return_icon('accept.png', get_lang('LearnpathPrerequisites'), array(), ICON_SIZE_SMALL),
8290
                $url.'&action=edit_item_prereq'
8291
            );
8292
        }
8293
        $return .= Display::url(
8294
            Display::return_icon('delete.png', get_lang('Delete'), array(), ICON_SIZE_SMALL),
8295
            $url.'&action=delete_item'
8296
        );
8297
8298 View Code Duplication
        if ($item_type == TOOL_HOTPOTATOES ) {
8299
            $document_data = DocumentManager::get_document_data_by_id($row['path'], $course_code);
8300
            $return .= get_lang('File').': '.$document_data['absolute_path_from_document'];
8301
        }
8302
8303 View Code Duplication
        if ($item_type == TOOL_DOCUMENT || $item_type == TOOL_FINAL_ITEM) {
8304
            $document_data = DocumentManager::get_document_data_by_id($row['path'], $course_code);
8305
            $return .= get_lang('File').': '.$document_data['absolute_path_from_document'];
8306
        }
8307
8308
        $return .= '</div>';
8309
8310
        if (!empty($audio_player)) {
8311
            $return .= '<br />'.$audio_player;
8312
        }
8313
8314
        return $return;
8315
    }
8316
8317
    /**
8318
     * Creates the javascript needed for filling up the checkboxes without page reload
8319
     * @return string
8320
     */
8321
    public function get_js_dropdown_array()
8322
    {
8323
        $course_id = api_get_course_int_id();
8324
        $return = 'var child_name = new Array();' . "\n";
8325
        $return .= 'var child_value = new Array();' . "\n\n";
8326
        $return .= 'child_name[0] = new Array();' . "\n";
8327
        $return .= 'child_value[0] = new Array();' . "\n\n";
8328
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
8329
        $sql_zero = "SELECT * FROM " . $tbl_lp_item . "
8330
                    WHERE c_id = ".$course_id." AND lp_id = " . $this->lp_id . " AND parent_item_id = 0
8331
                    ORDER BY display_order ASC";
8332
        $res_zero = Database::query($sql_zero);
8333
        $i = 0;
8334
8335
        while ($row_zero = Database :: fetch_array($res_zero)) {
8336
            if ($row_zero['item_type'] == TOOL_QUIZ) {
8337
                $row_zero['title'] = Exercise::get_formated_title_variable($row_zero['title']);
8338
            }
8339
            $js_var = json_encode(get_lang('After').' '.$row_zero['title']);
8340
            $return .= 'child_name[0][' . $i . '] = '.$js_var.' ;' . "\n";
8341
            $return .= 'child_value[0][' . $i++ . '] = "' . $row_zero['id'] . '";' . "\n";
8342
        }
8343
        $return .= "\n";
8344
        $sql = "SELECT * FROM " . $tbl_lp_item . "
8345
                WHERE c_id = ".$course_id." AND lp_id = " . $this->lp_id;
8346
        $res = Database::query($sql);
8347
        while ($row = Database :: fetch_array($res)) {
8348
            $sql_parent = "SELECT * FROM " . $tbl_lp_item . "
8349
                           WHERE
8350
                                c_id = ".$course_id." AND
8351
                                parent_item_id = " . $row['id'] . "
8352
                           ORDER BY display_order ASC";
8353
            $res_parent = Database::query($sql_parent);
8354
            $i = 0;
8355
            $return .= 'child_name[' . $row['id'] . '] = new Array();' . "\n";
8356
            $return .= 'child_value[' . $row['id'] . '] = new Array();' . "\n\n";
8357
8358
            while ($row_parent = Database :: fetch_array($res_parent)) {
8359
                $js_var = json_encode(get_lang('After').' '.$row_parent['title']);
8360
                $return .= 'child_name[' . $row['id'] . '][' . $i . '] =   '.$js_var.' ;' . "\n";
8361
                $return .= 'child_value[' . $row['id'] . '][' . $i++ . '] = "' . $row_parent['id'] . '";' . "\n";
8362
            }
8363
            $return .= "\n";
8364
        }
8365
8366
        return $return;
8367
    }
8368
8369
    /**
8370
     * Display the form to allow moving an item
8371
     * @param	integer		Item ID
8372
     * @return	string		HTML form
8373
     */
8374
    public function display_move_item($item_id)
8375
    {
8376
        $course_id = api_get_course_int_id();
8377
        $return = '';
8378
8379
        if (is_numeric($item_id)) {
8380
            $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
8381
8382
            $sql = "SELECT * FROM " . $tbl_lp_item . "
8383
                    WHERE c_id = ".$course_id." AND id = " . $item_id;
8384
8385
            $res = Database::query($sql);
8386
            $row = Database :: fetch_array($res);
8387
8388
            switch ($row['item_type']) {
8389
                case 'dokeos_chapter' :
8390
                case 'dir' :
8391
                case 'asset' :
8392
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
8393
                    $return .= $this->display_item_form($row['item_type'], get_lang('MoveCurrentChapter'), 'move', $item_id, $row);
8394
                    break;
8395
                case 'dokeos_module' :
8396
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
8397
                    $return .= $this->display_item_form($row['item_type'], 'Move th current module:', 'move', $item_id, $row);
8398
                    break;
8399
                case TOOL_DOCUMENT :
8400
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
8401
                    $return .= $this->display_document_form('move', $item_id, $row);
8402
                    break;
8403 View Code Duplication
                case TOOL_LINK :
8404
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
8405
                    $return .= $this->display_link_form('move', $item_id, $row);
8406
                    break;
8407 View Code Duplication
                case TOOL_HOTPOTATOES :
8408
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
8409
                    $return .= $this->display_link_form('move', $item_id, $row);
8410
                    break;
8411 View Code Duplication
                case TOOL_QUIZ :
8412
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
8413
                    $return .= $this->display_quiz_form('move', $item_id, $row);
8414
                    break;
8415 View Code Duplication
                case TOOL_STUDENTPUBLICATION :
8416
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
8417
                    $return .= $this->display_student_publication_form('move', $item_id, $row);
8418
                    break;
8419
                case TOOL_FORUM :
8420
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
8421
                    $return .= $this->display_forum_form('move', $item_id, $row);
8422
                    break;
8423 View Code Duplication
                case TOOL_THREAD :
8424
                    $return .= $this->display_manipulate($item_id, $row['item_type']);
8425
                    $return .= $this->display_forum_form('move', $item_id, $row);
8426
                    break;
8427
            }
8428
        }
8429
8430
        return $return;
8431
    }
8432
8433
    /**
8434
     * Displays a basic form on the overview page for changing the item title and the item description.
8435
     * @param string $item_type
8436
     * @param string $title
8437
     * @param array $data
8438
     * @return string
8439
     */
8440
    public function display_item_small_form($item_type, $title = '', $data = array())
8441
    {
8442
        $url = api_get_self() . '?' .api_get_cidreq().'&action=edit_item&lp_id='.$this->lp_id;
8443
        $form = new FormValidator('small_form', 'post', $url);
8444
        $form->addElement('header', $title);
8445
        $form->addElement('text', 'title', get_lang('Title'));
8446
        $form->addButtonSave(get_lang('Save'), 'submit_button');
8447
        $form->addElement('hidden', 'id', $data['id']);
8448
        $form->addElement('hidden', 'parent', $data['parent_item_id']);
8449
        $form->addElement('hidden', 'previous', $data['previous_item_id']);
8450
        $form->setDefaults(array('title' => $data['title']));
8451
8452
        return $form->toHtml();
8453
    }
8454
8455
    /**
8456
     * Return HTML form to allow prerequisites selection
8457
     * @todo use FormValidator
8458
     * @param	integer Item ID
8459
     * @return	string	HTML form
8460
     */
8461
    public function display_item_prerequisites_form($item_id)
8462
    {
8463
        $course_id = api_get_course_int_id();
8464
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
8465
        $item_id = intval($item_id);
8466
        /* Current prerequisite */
8467
        $sql = "SELECT * FROM $tbl_lp_item
8468
                WHERE c_id = $course_id AND id = " . $item_id;
8469
        $result = Database::query($sql);
8470
        $row    = Database::fetch_array($result);
8471
        $prerequisiteId = $row['prerequisite'];
8472
        $return = '<legend>';
8473
        $return .= get_lang('AddEditPrerequisites');
8474
        $return .= '</legend>';
8475
        $return .= '<form method="POST">';
8476
        $return .= '<table class="data_table">';
8477
        $return .= '<tr>';
8478
        $return .= '<th height="24">' . get_lang('LearnpathPrerequisites') . '</th>';
8479
        $return .= '<th width="70" >' . get_lang('Minimum') . '</th>';
8480
        $return .= '<th width="70">' . get_lang('Maximum') . '</th>';
8481
        $return .= '</tr>';
8482
8483
        // Adding the none option to the prerequisites see http://www.chamilo.org/es/node/146
8484
        $return .= '<tr >';
8485
        $return .= '<td colspan="3" class="radio">';
8486
        $return .= '<input checked="checked" id="idNone" name="prerequisites"  style="margin-left:0px; margin-right:10px;" type="radio" />';
8487
        $return .= '<label for="idNone">' . get_lang('None') . '</label>';
8488
        $return .= '</tr>';
8489
8490
        $sql = "SELECT * FROM $tbl_lp_item
8491
                WHERE c_id = $course_id AND lp_id = " . $this->lp_id;
8492
        $result = Database::query($sql);
8493
        $arrLP = array();
8494
8495
        $selectedMinScore = array();
8496
        $selectedMaxScore = array();
8497
        while ($row = Database :: fetch_array($result)) {
8498
            if ($row['id'] == $item_id) {
8499
                $selectedMinScore[$row['prerequisite']] = $row['prerequisite_min_score'];
8500
                $selectedMaxScore[$row['prerequisite']] = $row['prerequisite_max_score'];
8501
            }
8502
            $arrLP[] = array(
8503
                'id' => $row['id'],
8504
                'item_type' => $row['item_type'],
8505
                'title' => $row['title'],
8506
                'ref' => $row['ref'],
8507
                'description' => $row['description'],
8508
                'parent_item_id' => $row['parent_item_id'],
8509
                'previous_item_id' => $row['previous_item_id'],
8510
                'next_item_id' => $row['next_item_id'],
8511
                'max_score' => $row['max_score'],
8512
                'min_score' => $row['min_score'],
8513
                'mastery_score' => $row['mastery_score'],
8514
                'prerequisite' => $row['prerequisite'],
8515
                'next_item_id' => $row['next_item_id'],
8516
                'display_order' => $row['display_order'],
8517
                'prerequisite_min_score' => $row['prerequisite_min_score'],
8518
                'prerequisite_max_score' => $row['prerequisite_max_score'],
8519
            );
8520
        }
8521
8522
        $this->tree_array($arrLP);
8523
        $arrLP = isset($this->arrMenu) ? $this->arrMenu : null;
8524
        unset($this->arrMenu);
8525
8526
        for ($i = 0; $i < count($arrLP); $i++) {
8527
            $item = $arrLP[$i];
8528
8529
            if ($item['id'] == $item_id) {
8530
                break;
8531
            }
8532
8533
            $selectedMaxScoreValue = isset($selectedMaxScore[$item['id']]) ? $selectedMaxScore[$item['id']] : $item['max_score'];
8534
            $selectedMinScoreValue = isset($selectedMinScore[$item['id']]) ? $selectedMinScore[$item['id']]: 0;
8535
8536
            $return .= '<tr>';
8537
            $return .= '<td class="radio"' . (($item['item_type'] != TOOL_QUIZ && $item['item_type'] != TOOL_HOTPOTATOES) ? ' colspan="3"' : '') . '>';
8538
            $return .= '<label for="id' . $item['id'] . '">';
8539
            $return .= '<input' . (in_array($prerequisiteId, array($item['id'], $item['ref'])) ? ' checked="checked" ' : '') . (($item['item_type'] == 'dokeos_module' || $item['item_type'] == 'dokeos_chapter') ? ' disabled="disabled" ' : ' ') . 'id="id' . $item['id'] . '" name="prerequisites" style="margin-left:' . $item['depth'] * 10 . 'px; margin-right:10px;" type="radio" value="' . $item['id'] . '" />';
8540
            $icon_name = str_replace(' ', '', $item['item_type']);
8541
8542
            if (file_exists('../img/lp_' . $icon_name . '.png')) {
8543
                $return .= Display::return_icon('lp_' . $icon_name . '.png');
8544
            } else {
8545
                if (file_exists('../img/lp_' . $icon_name . '.gif')) {
8546
                    $return .= Display::return_icon('lp_' . $icon_name . '.gif');
8547
                } else {
8548
                    $return .= Display::return_icon('folder_document.gif', '', array('style'=>'margin-right:5px;'));
8549
                }
8550
            }
8551
8552
            $return .=  $item['title'] . '</label>';
8553
            $return .= '</td>';
8554
8555
            if ($item['item_type'] == TOOL_QUIZ) {
8556
                // lets update max_score Quiz information depending of the Quiz Advanced properties
8557
                $tmp_obj_lp_item = new LpItem($course_id, $item['id']);
8558
                $tmp_obj_exercice = new Exercise();
8559
                $tmp_obj_exercice->read($tmp_obj_lp_item->path);
8560
                $tmp_obj_lp_item->max_score = $tmp_obj_exercice->get_max_score();
8561
8562
                $tmp_obj_lp_item->update_in_bdd();
8563
                $item['max_score'] = $tmp_obj_lp_item->max_score;
8564
8565
                $return .= '<td class="exercise">';
8566
                $return .= '<input size="4" maxlength="3" name="min_' . $item['id'] . '" type="number" min="0" step="any" max="'.$item['max_score'].'" value="' . $selectedMinScoreValue. '" />';
8567
                $return .= '</td>';
8568
                $return .= '<td class="exercise">';
8569
                $return .= '<input size="4" maxlength="3" name="max_' . $item['id'] . '" type="number" min="0" step="any" max="'.$item['max_score'].'" value="' . $selectedMaxScoreValue . '" />';
8570
                $return .= '</td>';
8571
            }
8572
8573
            if ($item['item_type'] == TOOL_HOTPOTATOES) {
8574
                $return .= '<td class="exercise">';
8575
                $return .= '<center><input size="4" maxlength="3" name="min_' . $item['id'] . '" type="number" min="0" step="any" max="'.$item['max_score'].'" value="' . $selectedMinScoreValue . '" /></center>';
8576
                $return .= '</td>';
8577
                $return .= '<td class="exercise"">';
8578
                $return .= '<center><input size="4" maxlength="3" name="max_' . $item['id'] . '" type="number" min="0" step="any" max="'.$item['max_score'].'"  value="'.$selectedMaxScoreValue . '" /></center>';
8579
                $return .= '</td>';
8580
            }
8581
            $return .= '</tr>';
8582
        }
8583
        $return .= '<tr>';
8584
        $return .= '</tr>';
8585
        $return .= '</table>';
8586
        $return .= '<div style="padding-top:3px;">';
8587
        $return .= '<button class="btn btn-primary" name="submit_button" type="submit">' . get_lang('ModifyPrerequisites') . '</button>';
8588
        $return .= '</form>';
8589
8590
        return $return;
8591
    }
8592
8593
    /**
8594
     * Return HTML list to allow prerequisites selection for lp
8595
     * @param	integer Item ID
8596
     * @return	string	HTML form
8597
     */
8598
    public function display_lp_prerequisites_list()
8599
    {
8600
        $course_id = api_get_course_int_id();
8601
        $lp_id = $this->lp_id;
8602
        $tbl_lp = Database :: get_course_table(TABLE_LP_MAIN);
8603
8604
        // get current prerequisite
8605
        $sql = "SELECT * FROM $tbl_lp WHERE c_id = $course_id AND id = $lp_id ";
8606
        $result = Database::query($sql);
8607
        $row = Database :: fetch_array($result);
8608
        $prerequisiteId = $row['prerequisite'];
8609
        $session_id = api_get_session_id();
8610
        $session_condition = api_get_session_condition($session_id);
8611
        $sql = "SELECT * FROM $tbl_lp
8612
                WHERE c_id = $course_id $session_condition
8613
                ORDER BY display_order ";
8614
        $rs = Database::query($sql);
8615
        $return = '';
8616
        $return .= '<select name="prerequisites" class="form-control">';
8617
        $return .= '<option value="0">'.get_lang('None').'</option>';
8618
        if (Database::num_rows($rs) > 0) {
8619
            while ($row = Database::fetch_array($rs)) {
8620
                if ($row['id'] == $lp_id) {
8621
                    continue;
8622
                }
8623
                $return .= '<option value="'.$row['id'].'" '.(($row['id']==$prerequisiteId)?' selected ' : '').'>'.$row['name'].'</option>';
8624
            }
8625
        }
8626
        $return .= '</select>';
8627
8628
        return $return;
8629
    }
8630
8631
    /**
8632
     * Creates a list with all the documents in it
8633
     * @param bool $showInvisibleFiles
8634
     * @return string
8635
     */
8636
    public function get_documents($showInvisibleFiles = false)
8637
    {
8638
        $course_info = api_get_course_info();
8639
        $sessionId = api_get_session_id();
8640
8641
        $document_tree = DocumentManager::get_document_preview(
8642
            $course_info,
8643
            $this->lp_id,
8644
            null,
8645
            $sessionId,
8646
            true,
8647
            null,
8648
            null,
8649
            $showInvisibleFiles,
8650
            true
8651
        );
8652
8653
        return $document_tree;
8654
    }
8655
8656
    /**
8657
     * Creates a list with all the exercises (quiz) in it
8658
     * @return string
8659
     */
8660
    public function get_exercises()
8661
    {
8662
        $course_id = api_get_course_int_id();
8663
8664
        // New for hotpotatoes.
8665
        $uploadPath = DIR_HOTPOTATOES; //defined in main_api
8666
        $tbl_doc = Database :: get_course_table(TABLE_DOCUMENT);
8667
        $tbl_quiz = Database :: get_course_table(TABLE_QUIZ_TEST);
8668
8669
        $session_id = api_get_session_id();
8670
        $condition_session = api_get_session_condition($session_id);
8671
8672
        $setting = api_get_configuration_value('show_invisible_exercise_in_lp_list');
8673
8674
        $activeCondition = " active <> -1 ";
8675
        if ($setting) {
8676
            $activeCondition = " active = 1 ";
8677
        }
8678
8679
        $sql_quiz = "SELECT * FROM $tbl_quiz
8680
                     WHERE c_id = $course_id AND $activeCondition $condition_session
8681
                     ORDER BY title ASC";
8682
8683
        $sql_hot  = "SELECT * FROM $tbl_doc
8684
                     WHERE c_id = $course_id AND path LIKE '" . $uploadPath . "/%/%htm%'  $condition_session
8685
                     ORDER BY id ASC";
8686
8687
        $res_quiz = Database::query($sql_quiz);
8688
        $res_hot  = Database::query($sql_hot);
8689
8690
        $return = '<ul class="lp_resource">';
8691
        $return .= '<li class="lp_resource_element">';
8692
        $return .= Display::return_icon('new_test_small.gif');
8693
        $return .= '<a href="' . api_get_path(WEB_CODE_PATH) . 'exercice/exercise_admin.php?'.api_get_cidreq().'&lp_id=' . $this->lp_id . '">' .
8694
            get_lang('NewExercise') . '</a>';
8695
        $return .= '</li>';
8696
8697
        // Display hotpotatoes
8698
        while ($row_hot = Database :: fetch_array($res_hot)) {
8699
            $return .= '<li class="lp_resource_element" data_id="'.$row_hot['id'].'" data_type="hotpotatoes" title="'.$row_hot['title'].'" >';
8700
8701
            $return .= '<a class="moved" href="#">';
8702
            $return .= Display::return_icon('move_everywhere.png', get_lang('Move'), array(), ICON_SIZE_TINY);
8703
            $return .= '</a> ';
8704
8705
            $return .= Display::return_icon('hotpotatoes_s.png');
8706
            $return .= '<a href="' . api_get_self() . '?' . api_get_cidreq().'&action=add_item&type=' . TOOL_HOTPOTATOES . '&file=' . $row_hot['id'] . '&lp_id=' . $this->lp_id . '">'.
8707
                ((!empty ($row_hot['comment'])) ? $row_hot['comment'] : Security :: remove_XSS($row_hot['title'])) . '</a>';
8708
            $return .= '</li>';
8709
        }
8710
8711
        while ($row_quiz = Database :: fetch_array($res_quiz)) {
8712
            $return .= '<li class="lp_resource_element" data_id="'.$row_quiz['id'].'" data_type="quiz" title="'.$row_quiz['title'].'" >';
8713
            $return .= '<a class="moved" href="#">';
8714
            $return .= Display::return_icon('move_everywhere.png', get_lang('Move'), array(), ICON_SIZE_TINY);
8715
            $return .= '</a> ';
8716
            $return .= Display::return_icon('quizz_small.gif', '', array(), ICON_SIZE_TINY);
8717
            $return .= '<a href="' . api_get_self() . '?'.api_get_cidreq().'&action=add_item&type=' . TOOL_QUIZ . '&file=' . $row_quiz['id'] . '&lp_id=' . $this->lp_id . '">' .
8718
                Security :: remove_XSS(cut($row_quiz['title'], 80)).
8719
                '</a>';
8720
            $return .= '</li>';
8721
        }
8722
8723
        $return .= '</ul>';
8724
8725
        return $return;
8726
    }
8727
8728
    /**
8729
     * Creates a list with all the links in it
8730
     * @return string
8731
     */
8732
    public function get_links()
8733
    {
8734
        $selfUrl = api_get_self();
8735
        $courseIdReq = api_get_cidreq();
8736
        $course = api_get_course_info();
8737
        $course_id = $course['real_id'];
8738
        $tbl_link = Database::get_course_table(TABLE_LINK);
8739
        $linkCategoryTable = Database::get_course_table(TABLE_LINK_CATEGORY);
8740
        $moveEverywhereIcon = Display::return_icon('move_everywhere.png', get_lang('Move'), array(), ICON_SIZE_TINY);
8741
8742
        $session_id = api_get_session_id();
8743
        $condition_session = api_get_session_condition($session_id, true, null, "link.session_id");
8744
8745
        $sql = "SELECT link.id as link_id,
8746
                    link.title as link_title,
8747
                    link.category_id as category_id,
8748
                    link_category.category_title as category_title
8749
                FROM $tbl_link as link
8750
                LEFT JOIN $linkCategoryTable as link_category
8751
                ON link.category_id = link_category.id
8752
                WHERE link.c_id = ".$course_id." $condition_session
8753
                ORDER BY link_category.category_title ASC, link.title ASC";
8754
        $links = Database::query($sql);
8755
8756
        $categorizedLinks = array();
8757
        $categories = array();
8758
8759
        while ($link = Database :: fetch_array($links)) {
8760
            if (!$link['category_id']) {
8761
                $link['category_title'] = get_lang('Uncategorized');
8762
            }
8763
            $categories[$link['category_id']] = $link['category_title'];
8764
            $categorizedLinks[$link['category_id']][$link['link_id']] = $link['link_title'];
8765
        }
8766
8767
        $linksHtmlCode =
8768
            '<script>
8769
            function toggle_tool(tool, id){
8770
                if(document.getElementById(tool+"_"+id+"_content").style.display == "none"){
8771
                    document.getElementById(tool+"_"+id+"_content").style.display = "block";
8772
                    document.getElementById(tool+"_"+id+"_opener").src = "' . Display::returnIconPath('remove.gif').'";
8773
                } else {
8774
                    document.getElementById(tool+"_"+id+"_content").style.display = "none";
8775
                    document.getElementById(tool+"_"+id+"_opener").src = "'.Display::returnIconPath('add.gif').'";
8776
                }
8777
            }
8778
        </script>
8779
8780
        <ul class="lp_resource">
8781
            <li class="lp_resource_element">
8782
                '.Display::return_icon('linksnew.gif').'
8783
                <a href="'.api_get_path(WEB_CODE_PATH).'link/link.php?'.$courseIdReq.'&action=addlink&lp_id='.$this->lp_id.'" title="'.get_lang('LinkAdd').'">'.
8784
                get_lang('LinkAdd').'
8785
                </a>
8786
            </li>';
8787
8788
        foreach ($categorizedLinks as $categoryId => $links) {
8789
            $linkNodes = null;
8790
            foreach ($links as $key => $title) {
8791
                if (api_get_item_visibility($course, TOOL_LINK, $key, $session_id) != 2)  {
8792
                    $linkNodes .=
8793
                        '<li class="lp_resource_element" data_id="'.$key.'" data_type="'.TOOL_LINK.'" title="'.$title.'" >
8794
                        <a class="moved" href="#">'.
8795
                        $moveEverywhereIcon.
8796
                        '</a>
8797
                        '.Display::return_icon('lp_link.png').'
8798
                        <a href="'.$selfUrl.'?'.$courseIdReq.'&action=add_item&type='.
8799
                        TOOL_LINK.'&file='.$key.'&lp_id='.$this->lp_id.'">'.
8800
                        Security::remove_XSS($title).
8801
                        '</a>
8802
                    </li>';
8803
                }
8804
            }
8805
            $linksHtmlCode .=
8806
                '<li>
8807
                <a style="cursor:hand" onclick="javascript: toggle_tool(\''.TOOL_LINK.'\','.$categoryId.')" style="vertical-align:middle">
8808
                    <img src="'.Display::returnIconPath('add.gif').'" id="'.TOOL_LINK.'_'.$categoryId.'_opener"
8809
                    align="absbottom" />
8810
                </a>
8811
                <span style="vertical-align:middle">'.Security::remove_XSS($categories[$categoryId]).'</span>
8812
            </li>
8813
            <div style="display:none" id="'.TOOL_LINK.'_'.$categoryId.'_content">'.$linkNodes.'</div>';
8814
        }
8815
        $linksHtmlCode .= '</ul>';
8816
8817
        return $linksHtmlCode;
8818
    }
8819
8820
    /**
8821
     * Creates a list with all the student publications in it
8822
     * @return unknown
8823
     */
8824
    public function get_student_publications()
8825
    {
8826
        $return = '<div class="lp_resource" >';
8827
        $return .= '<div class="lp_resource_element">';
8828
        $return .= Display::return_icon('works_small.gif', '', array(), ICON_SIZE_TINY);
8829
        $return .= '<a href="' . api_get_self() . '?' . api_get_cidreq() . '&action=add_item&type=' . TOOL_STUDENTPUBLICATION . '&lp_id=' . $this->lp_id . '">' . get_lang('AddAssignmentPage') . '</a>';
8830
        $return .= '</div>';
8831
        $return .= '</div>';
8832
        return $return;
8833
    }
8834
8835
    /**
8836
     * Creates a list with all the forums in it
8837
     * @return string
8838
     */
8839
    public function get_forums()
8840
    {
8841
        require_once '../forum/forumfunction.inc.php';
8842
        require_once '../forum/forumconfig.inc.php';
8843
8844
        $a_forums = get_forums();
8845
        $return = '<ul class="lp_resource">';
8846
8847
        //First add link
8848
        $return .= '<li class="lp_resource_element">';
8849
        $return .= Display::return_icon('forum_new_small.gif');
8850
        $return .= Display::url(
8851
            get_lang('CreateANewForum'),
8852
            api_get_path(WEB_CODE_PATH) . 'forum/index.php?' . api_get_cidreq() . '&' . http_build_query([
8853
                'action' => 'add',
8854
                'content' => 'forum',
8855
                'lp_id' => $this->lp_id
8856
            ]),
8857
            ['title' => get_lang('CreateANewForum')]
8858
        );
8859
        $return .= '</li>';
8860
8861
        $return .= '<script>
8862
                    function toggle_forum(forum_id){
8863
                        if(document.getElementById("forum_"+forum_id+"_content").style.display == "none"){
8864
                            document.getElementById("forum_"+forum_id+"_content").style.display = "block";
8865
                            document.getElementById("forum_"+forum_id+"_opener").src = "' . Display::returnIconPath('remove.gif').'";
8866
                        } else {
8867
                            document.getElementById("forum_"+forum_id+"_content").style.display = "none";
8868
                            document.getElementById("forum_"+forum_id+"_opener").src = "' . Display::returnIconPath('add.gif').'";
8869
                        }
8870
                    }
8871
                </script>';
8872
8873
        foreach ($a_forums as $forum) {
8874
            if (!empty($forum['forum_id'])) {
8875
                $return .= '<li class="lp_resource_element" data_id="'.$forum['forum_id'].'" data_type="'.TOOL_FORUM.'" title="'.$forum['forum_title'].'" >';
8876
                $return .= '<a class="moved" href="#">';
8877
                $return .= Display::return_icon('move_everywhere.png', get_lang('Move'), array(), ICON_SIZE_TINY);
8878
                $return .= ' </a>';
8879
                $return .= Display::return_icon('lp_forum.png', '', array(), ICON_SIZE_TINY);
8880
                $return .= '<a style="cursor:hand" onclick="javascript: toggle_forum(' . $forum['forum_id'] . ')" style="vertical-align:middle">
8881
                                <img src="' . Display::returnIconPath('add.gif').'" id="forum_' . $forum['forum_id'] . '_opener" align="absbottom" />
8882
                            </a>
8883
                            <a href="' . api_get_self() . '?'.api_get_cidreq().'&action=add_item&type=' . TOOL_FORUM . '&forum_id=' . $forum['forum_id'] . '&lp_id=' . $this->lp_id . '" style="vertical-align:middle">' .
8884
                    Security :: remove_XSS($forum['forum_title']) . '</a>';
8885
8886
                $return .= '</li>';
8887
8888
                $return .= '<div style="display:none" id="forum_' . $forum['forum_id'] . '_content">';
8889
                $a_threads = get_threads($forum['forum_id']);
8890
                if (is_array($a_threads)) {
8891
                    foreach ($a_threads as $thread) {
8892
                        $return .= '<li class="lp_resource_element" data_id="'.$thread['thread_id'].'" data_type="'.TOOL_THREAD.'" title="'.$thread['thread_title'].'" >';
8893
                        $return .= '&nbsp;<a class="moved" href="#">';
8894
                        $return .= Display::return_icon('move_everywhere.png', get_lang('Move'), array(), ICON_SIZE_TINY);
8895
                        $return .= ' </a>';
8896
                        $return .= Display::return_icon('forumthread.png', get_lang('Thread'), array(), ICON_SIZE_TINY);
8897
                        $return .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=add_item&type=' . TOOL_THREAD . '&thread_id=' . $thread['thread_id'] . '&lp_id=' . $this->lp_id . '">' .
8898
                            Security :: remove_XSS($thread['thread_title']) . '</a>';
8899
                        $return .= '</li>';
8900
                    }
8901
                }
8902
                $return .= '</div>';
8903
            }
8904
        }
8905
        $return .= '</ul>';
8906
8907
        return $return;
8908
    }
8909
8910
    /**
8911
     * // TODO: The output encoding should be equal to the system encoding.
8912
     *
8913
     * Exports the learning path as a SCORM package. This is the main function that
8914
     * gathers the content, transforms it, writes the imsmanifest.xml file, zips the
8915
     * whole thing and returns the zip.
8916
     *
8917
     * This method needs to be called in PHP5, as it will fail with non-adequate
8918
     * XML package (like the ones for PHP4), and it is *not* a static method, so
8919
     * you need to call it on a learnpath object.
8920
     * @TODO The method might be redefined later on in the scorm class itself to avoid
8921
     * creating a SCORM structure if there is one already. However, if the initial SCORM
8922
     * path has been modified, it should use the generic method here below.
8923
     * @TODO link this function with the export_lp() function in the same class
8924
     * @param	string	Optional name of zip file. If none, title of learnpath is
8925
     * 					domesticated and trailed with ".zip"
8926
     * @return	string	Returns the zip package string, or null if error
8927
     */
8928
    public function scorm_export()
8929
    {
8930
        $_course = api_get_course_info();
8931
        $course_id = $_course['real_id'];
8932
8933
        // Remove memory and time limits as much as possible as this might be a long process...
8934
        if (function_exists('ini_set')) {
8935
            api_set_memory_limit('128M');
8936
            ini_set('max_execution_time', 600);
8937
        }
8938
8939
        // Create the zip handler (this will remain available throughout the method).
8940
        $archive_path = api_get_path(SYS_ARCHIVE_PATH);
8941
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
8942
        $temp_dir_short = uniqid();
8943
        $temp_zip_dir = $archive_path.'/'.$temp_dir_short;
8944
        $temp_zip_file = $temp_zip_dir.'/'.md5(time()).'.zip';
8945
        $zip_folder = new PclZip($temp_zip_file);
8946
        $current_course_path = api_get_path(SYS_COURSE_PATH).api_get_course_path();
8947
        $root_path = $main_path = api_get_path(SYS_PATH);
8948
        $files_cleanup = array();
8949
8950
        // Place to temporarily stash the zip file.
8951
        // create the temp dir if it doesn't exist
8952
        // or do a cleanup before creating the zip file.
8953
        if (!is_dir($temp_zip_dir)) {
8954
            mkdir($temp_zip_dir, api_get_permissions_for_new_directories());
8955
        } else {
8956
            // Cleanup: Check the temp dir for old files and delete them.
8957
            $handle = opendir($temp_zip_dir);
8958
            while (false !== ($file = readdir($handle))) {
8959
                if ($file != '.' && $file != '..') {
8960
                    unlink("$temp_zip_dir/$file");
8961
                }
8962
            }
8963
            closedir($handle);
8964
        }
8965
        $zip_files = $zip_files_abs = $zip_files_dist = array();
8966
        if (is_dir($current_course_path.'/scorm/'.$this->path) && is_file($current_course_path.'/scorm/'.$this->path.'/imsmanifest.xml')) {
8967
            // Remove the possible . at the end of the path.
8968
            $dest_path_to_lp = substr($this->path, -1) == '.' ? substr($this->path, 0, -1) : $this->path;
8969
            $dest_path_to_scorm_folder = str_replace('//','/',$temp_zip_dir.'/scorm/'.$dest_path_to_lp);
8970
            mkdir($dest_path_to_scorm_folder, api_get_permissions_for_new_directories(), true);
8971
            $zip_files_dist = copyr($current_course_path.'/scorm/'.$this->path, $dest_path_to_scorm_folder, array('imsmanifest'), $zip_files);
8972
        }
8973
8974
        // Build a dummy imsmanifest structure.
8975
        // Do not add to the zip yet (we still need it).
8976
        // This structure is developed following regulations for SCORM 1.2 packaging in the SCORM 1.2 Content
8977
        // Aggregation Model official document, section "2.3 Content Packaging".
8978
        // We are going to build a UTF-8 encoded manifest. Later we will recode it to the desired (and supported) encoding.
8979
        $xmldoc = new DOMDocument('1.0');
8980
        $root = $xmldoc->createElement('manifest');
8981
        $root->setAttribute('identifier', 'SingleCourseManifest');
8982
        $root->setAttribute('version', '1.1');
8983
        $root->setAttribute('xmlns', 'http://www.imsproject.org/xsd/imscp_rootv1p1p2');
8984
        $root->setAttribute('xmlns:adlcp', 'http://www.adlnet.org/xsd/adlcp_rootv1p2');
8985
        $root->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
8986
        $root->setAttribute('xsi:schemaLocation', 'http://www.imsproject.org/xsd/imscp_rootv1p1p2 imscp_rootv1p1p2.xsd http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 imsmd_rootv1p2p1.xsd http://www.adlnet.org/xsd/adlcp_rootv1p2 adlcp_rootv1p2.xsd');
8987
        // Build mandatory sub-root container elements.
8988
        $metadata = $xmldoc->createElement('metadata');
8989
        $md_schema = $xmldoc->createElement('schema', 'ADL SCORM');
8990
        $metadata->appendChild($md_schema);
8991
        $md_schemaversion = $xmldoc->createElement('schemaversion', '1.2');
8992
        $metadata->appendChild($md_schemaversion);
8993
        $root->appendChild($metadata);
8994
8995
        $organizations = $xmldoc->createElement('organizations');
8996
        $resources = $xmldoc->createElement('resources');
8997
8998
        // Build the only organization we will use in building our learnpaths.
8999
        $organizations->setAttribute('default', 'chamilo_scorm_export');
9000
        $organization = $xmldoc->createElement('organization');
9001
        $organization->setAttribute('identifier', 'chamilo_scorm_export');
9002
        // To set the title of the SCORM entity (=organization), we take the name given
9003
        // in Chamilo and convert it to HTML entities using the Chamilo charset (not the
9004
        // learning path charset) as it is the encoding that defines how it is stored
9005
        // in the database. Then we convert it to HTML entities again as the "&" character
9006
        // alone is not authorized in XML (must be &amp;).
9007
        // The title is then decoded twice when extracting (see scorm::parse_manifest).
9008
        $org_title = $xmldoc->createElement('title', api_utf8_encode($this->get_name()));
9009
        $organization->appendChild($org_title);
9010
9011
        $folder_name = 'document';
9012
9013
        // Removes the learning_path/scorm_folder path when exporting see #4841
9014
        $path_to_remove = null;
9015
        $result = $this->generate_lp_folder($_course);
9016
9017
        if (isset($result['dir']) && strpos($result['dir'], 'learning_path')) {
9018
            $path_to_remove = 'document'.$result['dir'];
9019
            $path_to_replace = $folder_name.'/';
9020
        }
9021
9022
        //Fixes chamilo scorm exports
9023
        if ($this->ref == 'chamilo_scorm_export') {
9024
            $path_to_remove = 'scorm/'.$this->path.'/document/';
9025
        }
9026
9027
        // For each element, add it to the imsmanifest structure, then add it to the zip.
9028
        // Always call the learnpathItem->scorm_export() method to change it to the SCORM format.
9029
        $link_updates = array();
9030
        $links_to_create = array();
9031
        foreach ($this->items as $index => $item) {
9032
            if (!in_array($item->type, array(TOOL_QUIZ, TOOL_FORUM, TOOL_THREAD, TOOL_LINK, TOOL_STUDENTPUBLICATION))) {
9033
                // Get included documents from this item.
9034
                if ($item->type == 'sco') {
9035
                    $inc_docs = $item->get_resources_from_source(
9036
                        null,
9037
                        api_get_path(SYS_COURSE_PATH) . api_get_course_path() . '/' . 'scorm/' . $this->path . '/' . $item->get_path()
9038
                    );
9039
                } else {
9040
                    $inc_docs = $item->get_resources_from_source();
9041
                }
9042
                // Give a child element <item> to the <organization> element.
9043
                $my_item_id = $item->get_id();
9044
                $my_item = $xmldoc->createElement('item');
9045
                $my_item->setAttribute('identifier', 'ITEM_'.$my_item_id);
9046
                $my_item->setAttribute('identifierref', 'RESOURCE_'.$my_item_id);
9047
                $my_item->setAttribute('isvisible', 'true');
9048
                // Give a child element <title> to the <item> element.
9049
                $my_title = $xmldoc->createElement('title', htmlspecialchars(api_utf8_encode($item->get_title()), ENT_QUOTES, 'UTF-8'));
9050
                $my_item->appendChild($my_title);
9051
                // Give a child element <adlcp:prerequisites> to the <item> element.
9052
                $my_prereqs = $xmldoc->createElement('adlcp:prerequisites', $this->get_scorm_prereq_string($my_item_id));
9053
                $my_prereqs->setAttribute('type', 'aicc_script');
9054
                $my_item->appendChild($my_prereqs);
9055
                // Give a child element <adlcp:maxtimeallowed> to the <item> element - not yet supported.
9056
                //$xmldoc->createElement('adlcp:maxtimeallowed','');
9057
                // Give a child element <adlcp:timelimitaction> to the <item> element - not yet supported.
9058
                //$xmldoc->createElement('adlcp:timelimitaction','');
9059
                // Give a child element <adlcp:datafromlms> to the <item> element - not yet supported.
9060
                //$xmldoc->createElement('adlcp:datafromlms','');
9061
                // Give a child element <adlcp:masteryscore> to the <item> element.
9062
                $my_masteryscore = $xmldoc->createElement('adlcp:masteryscore', $item->get_mastery_score());
9063
                $my_item->appendChild($my_masteryscore);
9064
9065
                // Attach this item to the organization element or hits parent if there is one.
9066
                if (!empty($item->parent) && $item->parent != 0) {
9067
                    $children = $organization->childNodes;
9068
                    $possible_parent = &$this->get_scorm_xml_node($children, 'ITEM_'.$item->parent);
9069
                    if (is_object($possible_parent)) {
9070
                        $possible_parent->appendChild($my_item);
9071 View Code Duplication
                    } else {
9072
                        if ($this->debug > 0) { error_log('Parent ITEM_'.$item->parent.' of item ITEM_'.$my_item_id.' not found'); }
9073
                    }
9074
                } else {
9075
                    if ($this->debug > 0) { error_log('No parent'); }
9076
                    $organization->appendChild($my_item);
9077
                }
9078
9079
                // Get the path of the file(s) from the course directory root.
9080
                $my_file_path = $item->get_file_path('scorm/'.$this->path.'/');
9081
9082
                if (!empty($path_to_remove)) {
9083
                    //From docs
9084
                    $my_xml_file_path = str_replace($path_to_remove, $path_to_replace, $my_file_path);
9085
9086
                    //From quiz
9087
                    if ($this->ref == 'chamilo_scorm_export') {
9088
                        $path_to_remove = 'scorm/'.$this->path.'/';
9089
                        $my_xml_file_path = str_replace($path_to_remove, '', $my_file_path);
9090
                    }
9091
                } else {
9092
                    $my_xml_file_path = $my_file_path;
9093
                }
9094
9095
                $my_sub_dir = dirname($my_file_path);
9096
                $my_sub_dir = str_replace('\\', '/', $my_sub_dir);
9097
                $my_xml_sub_dir = $my_sub_dir;
9098
                // Give a <resource> child to the <resources> element
9099
                $my_resource = $xmldoc->createElement('resource');
9100
                $my_resource->setAttribute('identifier', 'RESOURCE_'.$item->get_id());
9101
                $my_resource->setAttribute('type', 'webcontent');
9102
                $my_resource->setAttribute('href', $my_xml_file_path);
9103
                // adlcp:scormtype can be either 'sco' or 'asset'.
9104
                if ($item->type == 'sco') {
9105
                    $my_resource->setAttribute('adlcp:scormtype', 'sco');
9106
                } else {
9107
                    $my_resource->setAttribute('adlcp:scormtype', 'asset');
9108
                }
9109
                // xml:base is the base directory to find the files declared in this resource.
9110
                $my_resource->setAttribute('xml:base', '');
9111
                // Give a <file> child to the <resource> element.
9112
                $my_file = $xmldoc->createElement('file');
9113
                $my_file->setAttribute('href', $my_xml_file_path);
9114
                $my_resource->appendChild($my_file);
9115
9116
                // Dependency to other files - not yet supported.
9117
                $i = 1;
9118
                foreach ($inc_docs as $doc_info) {
9119
                    if (count($doc_info) < 1 || empty($doc_info[0])) { continue; }
9120
                    $my_dep = $xmldoc->createElement('resource');
9121
                    $res_id = 'RESOURCE_'.$item->get_id().'_'.$i;
9122
                    $my_dep->setAttribute('identifier', $res_id);
9123
                    $my_dep->setAttribute('type', 'webcontent');
9124
                    $my_dep->setAttribute('adlcp:scormtype', 'asset');
9125
                    $my_dep_file = $xmldoc->createElement('file');
9126
                    // Check type of URL.
9127
                    //error_log(__LINE__.'Now dealing with '.$doc_info[0].' of type '.$doc_info[1].'-'.$doc_info[2], 0);
9128
                    if ($doc_info[1] == 'remote') {
9129
                        // Remote file. Save url as is.
9130
                        $my_dep_file->setAttribute('href', $doc_info[0]);
9131
                        $my_dep->setAttribute('xml:base', '');
9132
                    } elseif ($doc_info[1] == 'local') {
9133
                        switch ($doc_info[2]) {
9134
                            case 'url': // Local URL - save path as url for now, don't zip file.
9135
                                $abs_path = api_get_path(SYS_PATH).str_replace(api_get_path(WEB_PATH), '', $doc_info[0]);
9136
                                $current_dir = dirname($abs_path);
9137
                                $current_dir = str_replace('\\', '/', $current_dir);
9138
                                $file_path = realpath($abs_path);
9139
                                $file_path = str_replace('\\', '/', $file_path);
9140
                                $my_dep_file->setAttribute('href', $file_path);
9141
                                $my_dep->setAttribute('xml:base', '');
9142
                                if (strstr($file_path, $main_path) !== false) {
9143
                                    // The calculated real path is really inside Chamilo's root path.
9144
                                    // Reduce file path to what's under the DocumentRoot.
9145
                                    $file_path = substr($file_path, strlen($root_path) - 1);
9146
                                    //echo $file_path;echo '<br /><br />';
9147
                                    //error_log(__LINE__.'Reduced url path: '.$file_path, 0);
9148
                                    $zip_files_abs[] = $file_path;
9149
                                    $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path);
9150
                                    $my_dep_file->setAttribute('href', $file_path);
9151
                                    $my_dep->setAttribute('xml:base', '');
9152
                                } elseif (empty($file_path)) {
9153
                                    /*$document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH), api_get_path(REL_PATH)));
9154
                                    if (strpos($document_root, -1) == '/') {
9155
                                        $document_root = substr(0, -1, $document_root);
9156
                                    }*/
9157
                                    $file_path = $_SERVER['DOCUMENT_ROOT'].$abs_path;
9158
                                    $file_path = str_replace('//', '/', $file_path);
9159
                                    if (file_exists($file_path)) {
9160
                                        $file_path = substr($file_path, strlen($current_dir)); // We get the relative path.
9161
                                        $zip_files[] = $my_sub_dir.'/'.$file_path;
9162
                                        $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path);
9163
                                        $my_dep_file->setAttribute('href', $file_path);
9164
                                        $my_dep->setAttribute('xml:base', '');
9165
                                    }
9166
                                }
9167
                                break;
9168
                            case 'abs': // Absolute path from DocumentRoot. Save file and leave path as is in the zip.
9169
                                $my_dep_file->setAttribute('href', $doc_info[0]);
9170
                                $my_dep->setAttribute('xml:base', '');
9171
9172
                                // The next lines fix a bug when using the "subdir" mode of Chamilo, whereas
9173
                                // an image path would be constructed as /var/www/subdir/subdir/img/foo.bar
9174
                                $abs_img_path_without_subdir = $doc_info[0];
9175
                                $relp = api_get_path(REL_PATH); // The url-append config param.
9176
                                $pos = strpos($abs_img_path_without_subdir, $relp);
9177
                                if ($pos === 0) {
9178
                                    $abs_img_path_without_subdir = '/'.substr($abs_img_path_without_subdir, strlen($relp));
9179
                                }
9180
                                $file_path = realpath(api_get_path(SYS_PATH).$abs_img_path_without_subdir);
9181
                                $file_path = str_replace('\\', '/', $file_path);
9182
                                $file_path = str_replace('//', '/', $file_path);
9183
9184
                                // Prepare the current directory path (until just under 'document') with a trailing slash.
9185
                                $cur_path = substr($current_course_path, -1) == '/' ? $current_course_path : $current_course_path.'/';
9186
                                // Check if the current document is in that path.
9187
                                if (strstr($file_path, $cur_path) !== false) {
9188
                                    // The document is in that path, now get the relative path
9189
                                    // to the containing document.
9190
                                    $orig_file_path = dirname($cur_path.$my_file_path).'/';
9191
                                    $orig_file_path = str_replace('\\', '/', $orig_file_path);
9192
                                    $relative_path = '';
9193
                                    if (strstr($file_path, $cur_path) !== false) {
9194
                                        //$relative_path = substr($file_path, strlen($orig_file_path));
9195
                                        $relative_path = str_replace($cur_path, '', $file_path);
9196
                                        $file_path = substr($file_path, strlen($cur_path));
9197
                                    } else {
9198
                                        // This case is still a problem as it's difficult to calculate a relative path easily
9199
                                        // might still generate wrong links.
9200
                                        //$file_path = substr($file_path,strlen($cur_path));
9201
                                        // Calculate the directory path to the current file (without trailing slash).
9202
                                        $my_relative_path = dirname($file_path);
9203
                                        $my_relative_path = str_replace('\\', '/', $my_relative_path);
9204
                                        $my_relative_file = basename($file_path);
9205
                                        // Calculate the directory path to the containing file (without trailing slash).
9206
                                        $my_orig_file_path = substr($orig_file_path, 0, -1);
9207
                                        $dotdot = '';
9208
                                        $subdir = '';
9209
                                        while (strstr($my_relative_path, $my_orig_file_path) === false && (strlen($my_orig_file_path) > 1) && (strlen($my_relative_path) > 1)) {
9210
                                            $my_relative_path2 = dirname($my_relative_path);
9211
                                            $my_relative_path2 = str_replace('\\', '/', $my_relative_path2);
9212
                                            $my_orig_file_path = dirname($my_orig_file_path);
9213
                                            $my_orig_file_path = str_replace('\\', '/', $my_orig_file_path);
9214
                                            $subdir = substr($my_relative_path, strlen($my_relative_path2) + 1).'/'.$subdir;
9215
                                            $dotdot += '../';
9216
                                            $my_relative_path = $my_relative_path2;
9217
                                        }
9218
                                        $relative_path = $dotdot.$subdir.$my_relative_file;
9219
                                    }
9220
                                    // Put the current document in the zip (this array is the array
9221
                                    // that will manage documents already in the course folder - relative).
9222
                                    $zip_files[] = $file_path;
9223
                                    // Update the links to the current document in the containing document (make them relative).
9224
                                    $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $relative_path);
9225
                                    $my_dep_file->setAttribute('href', $file_path);
9226
                                    $my_dep->setAttribute('xml:base', '');
9227
                                } elseif (strstr($file_path, $main_path) !== false) {
9228
                                    // The calculated real path is really inside Chamilo's root path.
9229
                                    // Reduce file path to what's under the DocumentRoot.
9230
                                    $file_path = substr($file_path, strlen($root_path));
9231
                                    //echo $file_path;echo '<br /><br />';
9232
                                    //error_log('Reduced path: '.$file_path, 0);
9233
                                    $zip_files_abs[] = $file_path;
9234
                                    $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path);
9235
                                    $my_dep_file->setAttribute('href', 'document/'.$file_path);
9236
                                    $my_dep->setAttribute('xml:base', '');
9237
                                } elseif (empty($file_path)) {
9238
                                    /*$document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH), api_get_path(REL_PATH)));
9239
                                    if(strpos($document_root,-1) == '/') {
9240
                                        $document_root = substr(0, -1, $document_root);
9241
                                    }*/
9242
                                    $file_path = $_SERVER['DOCUMENT_ROOT'].$doc_info[0];
9243
                                    $file_path = str_replace('//', '/', $file_path);
9244
9245
                                    $abs_path = api_get_path(SYS_PATH).str_replace(api_get_path(WEB_PATH), '', $doc_info[0]);
9246
                                    $current_dir = dirname($abs_path);
9247
                                    $current_dir = str_replace('\\', '/', $current_dir);
9248
9249
                                    if (file_exists($file_path)) {
9250
                                        $file_path = substr($file_path, strlen($current_dir)); // We get the relative path.
9251
                                        $zip_files[] = $my_sub_dir.'/'.$file_path;
9252
                                        $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path);
9253
                                        $my_dep_file->setAttribute('href','document/'.$file_path);
9254
                                        $my_dep->setAttribute('xml:base', '');
9255
                                    }
9256
                                }
9257
                                break;
9258
                            case 'rel':
9259
                                // Path relative to the current document.
9260
                                // Save xml:base as current document's directory and save file in zip as subdir.file_path
9261
                                if (substr($doc_info[0], 0, 2) == '..') {
9262
                                    // Relative path going up.
9263
                                    $current_dir = dirname($current_course_path.'/'.$item->get_file_path()).'/';
9264
                                    $current_dir = str_replace('\\', '/', $current_dir);
9265
                                    $file_path = realpath($current_dir.$doc_info[0]);
9266
                                    $file_path = str_replace('\\', '/', $file_path);
9267
9268
                                    //error_log($file_path.' <-> '.$main_path,0);
9269
                                    if (strstr($file_path, $main_path) !== false) {
9270
                                        // The calculated real path is really inside Chamilo's root path.
9271
                                        // Reduce file path to what's under the DocumentRoot.
9272
                                        $file_path = substr($file_path, strlen($root_path));
9273
                                        //error_log('Reduced path: '.$file_path, 0);
9274
                                        $zip_files_abs[] = $file_path;
9275
                                        $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path);
9276
                                        $my_dep_file->setAttribute('href', 'document/'.$file_path);
9277
                                        $my_dep->setAttribute('xml:base', '');
9278
                                    }
9279 View Code Duplication
                                } else {
9280
                                    $zip_files[] = $my_sub_dir.'/'.$doc_info[0];
9281
                                    $my_dep_file->setAttribute('href', $doc_info[0]);
9282
                                    $my_dep->setAttribute('xml:base', $my_xml_sub_dir);
9283
                                }
9284
                                break;
9285
                            default:
9286
                                $my_dep_file->setAttribute('href', $doc_info[0]);
9287
                                $my_dep->setAttribute('xml:base', '');
9288
                                break;
9289
                        }
9290
                    }
9291
                    $my_dep->appendChild($my_dep_file);
9292
                    $resources->appendChild($my_dep);
9293
                    $dependency = $xmldoc->createElement('dependency');
9294
                    $dependency->setAttribute('identifierref', $res_id);
9295
                    $my_resource->appendChild($dependency);
9296
                    $i++;
9297
                }
9298
                $resources->appendChild($my_resource);
9299
                $zip_files[] = $my_file_path;
9300
            } else {
9301
9302
                // If the item is a quiz or a link or whatever non-exportable, we include a step indicating it.
9303
                switch ($item->type) {
9304
                    case TOOL_LINK:
9305
                        $my_item = $xmldoc->createElement('item');
9306
                        $my_item->setAttribute('identifier', 'ITEM_'.$item->get_id());
9307
                        $my_item->setAttribute('identifierref', 'RESOURCE_'.$item->get_id());
9308
                        $my_item->setAttribute('isvisible', 'true');
9309
                        // Give a child element <title> to the <item> element.
9310
                        $my_title = $xmldoc->createElement('title', htmlspecialchars(api_utf8_encode($item->get_title()), ENT_QUOTES, 'UTF-8'));
9311
                        $my_item->appendChild($my_title);
9312
                        // Give a child element <adlcp:prerequisites> to the <item> element.
9313
                        $my_prereqs = $xmldoc->createElement('adlcp:prerequisites', $item->get_prereq_string());
9314
                        $my_prereqs->setAttribute('type', 'aicc_script');
9315
                        $my_item->appendChild($my_prereqs);
9316
                        // Give a child element <adlcp:maxtimeallowed> to the <item> element - not yet supported.
9317
                        //$xmldoc->createElement('adlcp:maxtimeallowed', '');
9318
                        // Give a child element <adlcp:timelimitaction> to the <item> element - not yet supported.
9319
                        //$xmldoc->createElement('adlcp:timelimitaction', '');
9320
                        // Give a child element <adlcp:datafromlms> to the <item> element - not yet supported.
9321
                        //$xmldoc->createElement('adlcp:datafromlms', '');
9322
                        // Give a child element <adlcp:masteryscore> to the <item> element.
9323
                        $my_masteryscore = $xmldoc->createElement('adlcp:masteryscore', $item->get_mastery_score());
9324
                        $my_item->appendChild($my_masteryscore);
9325
9326
                        // Attach this item to the organization element or its parent if there is one.
9327 View Code Duplication
                        if (!empty($item->parent) && $item->parent != 0) {
9328
                            $children = $organization->childNodes;
9329
                            for ($i = 0; $i < $children->length; $i++) {
9330
                                $item_temp = $children->item($i);
9331
                                if ($item_temp -> nodeName == 'item') {
9332
                                    if ($item_temp->getAttribute('identifier') == 'ITEM_'.$item->parent) {
9333
                                        $item_temp -> appendChild($my_item);
9334
                                    }
9335
                                }
9336
                            }
9337
                        } else {
9338
                            $organization->appendChild($my_item);
9339
                        }
9340
9341
                        $my_file_path = 'link_'.$item->get_id().'.html';
9342
                        $sql = 'SELECT url, title FROM '.Database :: get_course_table(TABLE_LINK).'
9343
                                WHERE c_id = '.$course_id.' AND id='.$item->path;
9344
                        $rs = Database::query($sql);
9345
                        if ($link = Database :: fetch_array($rs)) {
9346
                            $url = $link['url'];
9347
                            $title = stripslashes($link['title']);
9348
                            $links_to_create[$my_file_path] = array('title' => $title, 'url' => $url);
9349
                            $my_xml_file_path = $my_file_path;
9350
                            $my_sub_dir = dirname($my_file_path);
9351
                            $my_sub_dir = str_replace('\\', '/', $my_sub_dir);
9352
                            $my_xml_sub_dir = $my_sub_dir;
9353
                            // Give a <resource> child to the <resources> element.
9354
                            $my_resource = $xmldoc->createElement('resource');
9355
                            $my_resource->setAttribute('identifier', 'RESOURCE_'.$item->get_id());
9356
                            $my_resource->setAttribute('type', 'webcontent');
9357
                            $my_resource->setAttribute('href', $my_xml_file_path);
9358
                            // adlcp:scormtype can be either 'sco' or 'asset'.
9359
                            $my_resource->setAttribute('adlcp:scormtype', 'asset');
9360
                            // xml:base is the base directory to find the files declared in this resource.
9361
                            $my_resource->setAttribute('xml:base', '');
9362
                            // give a <file> child to the <resource> element.
9363
                            $my_file = $xmldoc->createElement('file');
9364
                            $my_file->setAttribute('href', $my_xml_file_path);
9365
                            $my_resource->appendChild($my_file);
9366
                            $resources->appendChild($my_resource);
9367
                        }
9368
                        break;
9369
                    case TOOL_QUIZ:
9370
                        $exe_id = $item->path; // Should be using ref when everything will be cleaned up in this regard.
9371
                        $exe = new Exercise();
9372
                        $exe->read($exe_id);
9373
                        $my_item = $xmldoc->createElement('item');
9374
                        $my_item->setAttribute('identifier', 'ITEM_'.$item->get_id());
9375
                        $my_item->setAttribute('identifierref', 'RESOURCE_'.$item->get_id());
9376
                        $my_item->setAttribute('isvisible', 'true');
9377
                        // Give a child element <title> to the <item> element.
9378
                        $my_title = $xmldoc->createElement('title', htmlspecialchars(api_utf8_encode($item->get_title()), ENT_QUOTES, 'UTF-8'));
9379
                        $my_item->appendChild($my_title);
9380
                        $my_max_score = $xmldoc->createElement('max_score', $item->get_max());
9381
                        //$my_item->appendChild($my_max_score);
9382
                        // Give a child element <adlcp:prerequisites> to the <item> element.
9383
                        $my_prereqs = $xmldoc->createElement('adlcp:prerequisites', $item->get_prereq_string());
9384
                        $my_prereqs->setAttribute('type','aicc_script');
9385
                        $my_item->appendChild($my_prereqs);
9386
                        // Give a child element <adlcp:masteryscore> to the <item> element.
9387
                        $my_masteryscore = $xmldoc->createElement('adlcp:masteryscore', $item->get_mastery_score());
9388
                        $my_item->appendChild($my_masteryscore);
9389
9390
                        // Attach this item to the organization element or hits parent if there is one.
9391 View Code Duplication
                        if (!empty($item->parent) && $item->parent != 0) {
9392
                            $children = $organization->childNodes;
9393
                            for ($i = 0; $i < $children->length; $i++) {
9394
                                $item_temp = $children->item($i);
9395
                                if ($item_temp -> nodeName == 'item') {
9396
                                    if ($item_temp->getAttribute('identifier') == 'ITEM_'.$item->parent) {
9397
                                        $item_temp -> appendChild($my_item);
9398
                                    }
9399
                                }
9400
                            }
9401
                        } else {
9402
                            $organization->appendChild($my_item);
9403
                        }
9404
9405
                        // Get the path of the file(s) from the course directory root
9406
                        //$my_file_path = $item->get_file_path('scorm/'.$this->path.'/');
9407
                        $my_file_path = 'quiz_'.$item->get_id().'.html';
9408
                        // Write the contents of the exported exercise into a (big) html file
9409
                        // to later pack it into the exported SCORM. The file will be removed afterwards.
9410
                        $contents = ScormSection::export_exercise_to_scorm($exe_id, true);
9411
                        $tmp_file_path = $archive_path.$temp_dir_short.'/'.$my_file_path;
9412
                        $res = file_put_contents($tmp_file_path, $contents);
9413
                        if ($res === false) { error_log('Could not write into file '.$tmp_file_path.' '.__FILE__.' '.__LINE__, 0); }
9414
                        $files_cleanup[] = $tmp_file_path;
9415
                        //error_log($tmp_path); die();
9416
                        //$my_xml_file_path = api_htmlentities(api_utf8_encode($my_file_path), ENT_QUOTES, 'UTF-8');
9417
                        $my_xml_file_path = $my_file_path;
9418
                        $my_sub_dir = dirname($my_file_path);
9419
                        $my_sub_dir = str_replace('\\', '/', $my_sub_dir);
9420
                        //$my_xml_sub_dir = api_htmlentities(api_utf8_encode($my_sub_dir), ENT_QUOTES, 'UTF-8');
9421
                        $my_xml_sub_dir = $my_sub_dir;
9422
                        // Give a <resource> child to the <resources> element.
9423
                        $my_resource = $xmldoc->createElement('resource');
9424
                        $my_resource->setAttribute('identifier', 'RESOURCE_'.$item->get_id());
9425
                        $my_resource->setAttribute('type', 'webcontent');
9426
                        $my_resource->setAttribute('href', $my_xml_file_path);
9427
                        // adlcp:scormtype can be either 'sco' or 'asset'.
9428
                        $my_resource->setAttribute('adlcp:scormtype', 'sco');
9429
                        // xml:base is the base directory to find the files declared in this resource.
9430
                        $my_resource->setAttribute('xml:base', '');
9431
                        // Give a <file> child to the <resource> element.
9432
                        $my_file = $xmldoc->createElement('file');
9433
                        $my_file->setAttribute('href', $my_xml_file_path);
9434
                        $my_resource->appendChild($my_file);
9435
9436
                        // Get included docs.
9437
                        $inc_docs = $item->get_resources_from_source(null,$tmp_file_path);
9438
                        // Dependency to other files - not yet supported.
9439
                        $i = 1;
9440
                        foreach ($inc_docs as $doc_info) {
9441
                            if (count($doc_info) < 1 || empty($doc_info[0])) { continue; }
9442
                            $my_dep = $xmldoc->createElement('resource');
9443
                            $res_id = 'RESOURCE_'.$item->get_id().'_'.$i;
9444
                            $my_dep->setAttribute('identifier', $res_id);
9445
                            $my_dep->setAttribute('type', 'webcontent');
9446
                            $my_dep->setAttribute('adlcp:scormtype', 'asset');
9447
                            $my_dep_file = $xmldoc->createElement('file');
9448
                            // Check type of URL.
9449
                            if ($doc_info[1] == 'remote') {
9450
                                // Remote file. Save url as is.
9451
                                $my_dep_file->setAttribute('href', $doc_info[0]);
9452
                                $my_dep->setAttribute('xml:base', '');
9453
                            } elseif ($doc_info[1] == 'local') {
9454
                                switch ($doc_info[2]) {
9455
                                    case 'url': // Local URL - save path as url for now, don't zip file.
9456
                                        // Save file but as local file (retrieve from URL).
9457
                                        $abs_path = api_get_path(SYS_PATH).str_replace(api_get_path(WEB_PATH), '', $doc_info[0]);
9458
                                        $current_dir = dirname($abs_path);
9459
                                        $current_dir = str_replace('\\', '/', $current_dir);
9460
                                        $file_path = realpath($abs_path);
9461
                                        $file_path = str_replace('\\', '/', $file_path);
9462
                                        $my_dep_file->setAttribute('href', 'document/'.$file_path);
9463
                                        $my_dep->setAttribute('xml:base', '');
9464 View Code Duplication
                                        if (strstr($file_path, $main_path) !== false) {
9465
                                            // The calculated real path is really inside the chamilo root path.
9466
                                            // Reduce file path to what's under the DocumentRoot.
9467
                                            $file_path = substr($file_path, strlen($root_path));
9468
                                            //echo $file_path;echo '<br /><br />';
9469
                                            //error_log('Reduced path: '.$file_path, 0);
9470
                                            $zip_files_abs[] = $file_path;
9471
                                            $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => 'document/'.$file_path);
9472
                                            $my_dep_file->setAttribute('href', 'document/'.$file_path);
9473
                                            $my_dep->setAttribute('xml:base', '');
9474
                                        } elseif (empty($file_path)) {
9475
                                            /*$document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH),api_get_path(REL_PATH)));
9476
                                            if (strpos($document_root,-1) == '/') {
9477
                                                $document_root = substr(0, -1, $document_root);
9478
                                            }*/
9479
                                            $file_path = $_SERVER['DOCUMENT_ROOT'].$abs_path;
9480
                                            $file_path = str_replace('//', '/', $file_path);
9481
                                            if (file_exists($file_path)) {
9482
                                                $file_path = substr($file_path, strlen($current_dir)); // We get the relative path.
9483
                                                $zip_files[] = $my_sub_dir.'/'.$file_path;
9484
                                                $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => 'document/'.$file_path);
9485
                                                $my_dep_file->setAttribute('href', 'document/'.$file_path);
9486
                                                $my_dep->setAttribute('xml:base', '');
9487
                                            }
9488
                                        }
9489
                                        break;
9490
                                    case 'abs': // Absolute path from DocumentRoot. Save file and leave path as is in the zip.
9491
                                        $current_dir = dirname($current_course_path.'/'.$item->get_file_path()).'/';
9492
                                        $current_dir = str_replace('\\', '/', $current_dir);
9493
                                        $file_path = realpath($doc_info[0]);
9494
                                        $file_path = str_replace('\\', '/', $file_path);
9495
                                        $my_dep_file->setAttribute('href', $file_path);
9496
                                        $my_dep->setAttribute('xml:base', '');
9497
9498 View Code Duplication
                                        if (strstr($file_path,$main_path) !== false) {
9499
                                            // The calculated real path is really inside the chamilo root path.
9500
                                            // Reduce file path to what's under the DocumentRoot.
9501
                                            $file_path = substr($file_path, strlen($root_path));
9502
                                            //echo $file_path;echo '<br /><br />';
9503
                                            //error_log('Reduced path: '.$file_path, 0);
9504
                                            $zip_files_abs[] = $file_path;
9505
                                            $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path);
9506
                                            $my_dep_file->setAttribute('href', 'document/'.$file_path);
9507
                                            $my_dep->setAttribute('xml:base', '');
9508
                                        } elseif (empty($file_path)) {
9509
                                            /*$document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH), api_get_path(REL_PATH)));
9510
                                            if (strpos($document_root,-1) == '/') {
9511
                                                $document_root = substr(0, -1, $document_root);
9512
                                            }*/
9513
                                            $file_path = $_SERVER['DOCUMENT_ROOT'].$doc_info[0];
9514
                                            $file_path = str_replace('//', '/', $file_path);
9515
                                            if (file_exists($file_path)) {
9516
                                                $file_path = substr($file_path,strlen($current_dir)); // We get the relative path.
9517
                                                $zip_files[] = $my_sub_dir.'/'.$file_path;
9518
                                                $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path);
9519
                                                $my_dep_file->setAttribute('href', 'document/'.$file_path);
9520
                                                $my_dep->setAttribute('xml:base', '');
9521
                                            }
9522
                                        }
9523
                                        break;
9524
                                    case 'rel': // Path relative to the current document. Save xml:base as current document's directory and save file in zip as subdir.file_path
9525
                                        if (substr($doc_info[0], 0, 2) == '..') {
9526
                                            // Relative path going up.
9527
                                            $current_dir = dirname($current_course_path.'/'.$item->get_file_path()).'/';
9528
                                            $current_dir = str_replace('\\', '/', $current_dir);
9529
                                            $file_path = realpath($current_dir.$doc_info[0]);
9530
                                            $file_path = str_replace('\\', '/', $file_path);
9531
                                            //error_log($file_path.' <-> '.$main_path, 0);
9532
                                            if (strstr($file_path, $main_path) !== false) {
9533
                                                // The calculated real path is really inside Chamilo's root path.
9534
                                                // Reduce file path to what's under the DocumentRoot.
9535
9536
                                                $file_path = substr($file_path, strlen($root_path));
9537
                                                $file_path_dest = $file_path;
9538
9539
                                                // File path is courses/CHAMILO/document/....
9540
                                                $info_file_path = explode('/', $file_path);
9541
                                                if ($info_file_path[0] == 'courses') { // Add character "/" in file path.
9542
                                                    $file_path_dest = 'document/'.$file_path;
9543
                                                }
9544
9545
                                                //error_log('Reduced path: '.$file_path, 0);
9546
                                                $zip_files_abs[] = $file_path;
9547
9548
                                                $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path_dest);
9549
                                                $my_dep_file->setAttribute('href', 'document/'.$file_path);
9550
                                                $my_dep->setAttribute('xml:base', '');
9551
                                            }
9552 View Code Duplication
                                        } else {
9553
                                            $zip_files[] = $my_sub_dir.'/'.$doc_info[0];
9554
                                            $my_dep_file->setAttribute('href', $doc_info[0]);
9555
                                            $my_dep->setAttribute('xml:base', $my_xml_sub_dir);
9556
                                        }
9557
                                        break;
9558
                                    default:
9559
                                        $my_dep_file->setAttribute('href', $doc_info[0]); // ../../courses/
9560
                                        $my_dep->setAttribute('xml:base', '');
9561
                                        break;
9562
                                }
9563
                            }
9564
                            $my_dep->appendChild($my_dep_file);
9565
                            $resources->appendChild($my_dep);
9566
                            $dependency = $xmldoc->createElement('dependency');
9567
                            $dependency->setAttribute('identifierref', $res_id);
9568
                            $my_resource->appendChild($dependency);
9569
                            $i++;
9570
                        }
9571
                        $resources->appendChild($my_resource);
9572
                        $zip_files[] = $my_file_path;
9573
                        break;
9574
                    default:
9575
                        // Get the path of the file(s) from the course directory root
9576
                        $my_file_path = 'non_exportable.html';
9577
                        //$my_xml_file_path = api_htmlentities(api_utf8_encode($my_file_path), ENT_COMPAT, 'UTF-8');
9578
                        $my_xml_file_path = $my_file_path;
9579
                        $my_sub_dir = dirname($my_file_path);
9580
                        $my_sub_dir = str_replace('\\', '/', $my_sub_dir);
9581
                        //$my_xml_sub_dir = api_htmlentities(api_utf8_encode($my_sub_dir), ENT_COMPAT, 'UTF-8');
9582
                        $my_xml_sub_dir = $my_sub_dir;
9583
                        // Give a <resource> child to the <resources> element.
9584
                        $my_resource = $xmldoc->createElement('resource');
9585
                        $my_resource->setAttribute('identifier', 'RESOURCE_'.$item->get_id());
9586
                        $my_resource->setAttribute('type', 'webcontent');
9587
                        $my_resource->setAttribute('href', $folder_name.'/'.$my_xml_file_path);
9588
                        // adlcp:scormtype can be either 'sco' or 'asset'.
9589
                        $my_resource->setAttribute('adlcp:scormtype', 'asset');
9590
                        // xml:base is the base directory to find the files declared in this resource.
9591
                        $my_resource->setAttribute('xml:base', '');
9592
                        // Give a <file> child to the <resource> element.
9593
                        $my_file = $xmldoc->createElement('file');
9594
                        $my_file->setAttribute('href', 'document/'.$my_xml_file_path);
9595
                        $my_resource->appendChild($my_file);
9596
                        $resources->appendChild($my_resource);
9597
                        break;
9598
                }
9599
            }
9600
        }
9601
9602
        $organizations->appendChild($organization);
9603
        $root->appendChild($organizations);
9604
        $root->appendChild($resources);
9605
        $xmldoc->appendChild($root);
9606
9607
        // TODO: Add a readme file here, with a short description and a link to the Reload player
9608
        // then add the file to the zip, then destroy the file (this is done automatically).
9609
        // http://www.reload.ac.uk/scormplayer.html - once done, don't forget to close FS#138
9610
9611
        foreach ($zip_files as $file_path) {
9612
            if (empty($file_path)) {
9613
                continue;
9614
            }
9615
9616
            $dest_file = $archive_path.$temp_dir_short.'/'.$file_path;
9617
            if (!empty($path_to_remove) && !empty($path_to_replace)) {
9618
                $dest_file = str_replace($path_to_remove, $path_to_replace, $dest_file);
9619
            }
9620
            $this->create_path($dest_file);
9621
            @copy($sys_course_path.$_course['path'].'/'.$file_path, $dest_file);
9622
            // Check if the file needs a link update.
9623
            if (in_array($file_path, array_keys($link_updates))) {
9624
                $string = file_get_contents($dest_file);
9625
                unlink($dest_file);
9626
                foreach ($link_updates[$file_path] as $old_new) {
9627
                    // This is an ugly hack that allows .flv files to be found by the flv player that
9628
                    // will be added in document/main/inc/lib/flv_player/flv_player.swf and that needs
9629
                    // to find the flv to play in document/main/, so we replace main/ in the flv path by
9630
                    // ../../.. to return from inc/lib/flv_player to the document/main path.
9631
                    if (substr($old_new['dest'], -3) == 'flv' && substr($old_new['dest'], 0, 5) == 'main/') {
9632
                        $old_new['dest'] = str_replace('main/', '../../../', $old_new['dest']);
9633 View Code Duplication
                    } elseif (substr($old_new['dest'], -3) == 'flv' && substr($old_new['dest'], 0, 6) == 'video/') {
9634
                        $old_new['dest'] = str_replace('video/', '../../../../video/', $old_new['dest']);
9635
                    }
9636
                    //Fix to avoid problems with default_course_document
9637
                    if (strpos("main/default_course_document", $old_new['dest'] === false)) {
9638
                        //$newDestination = str_replace('document/', $mult.'document/', $old_new['dest']);
9639
                        $newDestination = $old_new['dest'];
9640
                    } else {
9641
                        $newDestination = str_replace('document/', '', $old_new['dest']);
9642
                    }
9643
                    $string = str_replace($old_new['orig'], $newDestination, $string);
9644
9645
                    //Add files inside the HTMLs
9646
                    $new_path = str_replace('/courses/', '', $old_new['orig']);
9647
                    $destinationFile = $archive_path.$temp_dir_short.'/'.$old_new['dest'];
9648
                    if (file_exists($sys_course_path.$new_path)) {
9649
                        copy($sys_course_path.$new_path, $destinationFile);
9650
                    }
9651
                }
9652
                file_put_contents($dest_file, $string);
9653
            }
9654
        }
9655
9656
        foreach ($zip_files_abs as $file_path) {
9657
            if (empty($file_path)) {
9658
                continue;
9659
            }
9660
            if (!is_file($main_path.$file_path) || !is_readable($main_path.$file_path)) {
9661
                continue;
9662
            }
9663
9664
            $dest_file = $archive_path.$temp_dir_short.'/document/'.$file_path;
9665
            $this->create_path($dest_file);
9666
            copy($main_path.$file_path, $dest_file);
9667
            // Check if the file needs a link update.
9668
            if (in_array($file_path, array_keys($link_updates))) {
9669
                $string = file_get_contents($dest_file);
9670
                unlink($dest_file);
9671
                foreach ($link_updates[$file_path] as $old_new) {
9672
                    // This is an ugly hack that allows .flv files to be found by the flv player that
9673
                    // will be added in document/main/inc/lib/flv_player/flv_player.swf and that needs
9674
                    // to find the flv to play in document/main/, so we replace main/ in the flv path by
9675
                    // ../../.. to return from inc/lib/flv_player to the document/main path.
9676 View Code Duplication
                    if (substr($old_new['dest'], -3) == 'flv' && substr($old_new['dest'], 0, 5) == 'main/') {
9677
                        $old_new['dest'] = str_replace('main/', '../../../', $old_new['dest']);
9678
                    }
9679
                    $string = str_replace($old_new['orig'], $old_new['dest'], $string);
9680
                }
9681
                file_put_contents($dest_file, $string);
9682
            }
9683
        }
9684
9685
        if (is_array($links_to_create)) {
9686
            foreach ($links_to_create as $file => $link) {
9687
                $file_content = '<!DOCTYPE html><head>
9688
                                <meta charset="'.api_get_language_isocode().'" />
9689
                                <title>'.$link['title'].'</title>
9690
                                </head>
9691
                                <body dir="'.api_get_text_direction().'">
9692
                                <div style="text-align:center">
9693
                                <a href="'.$link['url'].'">'.$link['title'].'</a></div>
9694
                                </body>
9695
                                </html>';
9696
                file_put_contents($archive_path.$temp_dir_short.'/'.$file, $file_content);
9697
            }
9698
        }
9699
9700
        // Add non exportable message explanation.
9701
        $lang_not_exportable = get_lang('ThisItemIsNotExportable');
9702
        $file_content = '<!DOCTYPE html><head>
9703
                        <meta charset="'.api_get_language_isocode().'" />
9704
                        <title>'.$lang_not_exportable.'</title>
9705
                        <meta http-equiv="Content-Type" content="text/html; charset='.api_get_system_encoding().'" />
9706
                        </head>
9707
                        <body dir="'.api_get_text_direction().'">';
9708
        $file_content .=
9709
            <<<EOD
9710
                    <style>
9711
            .error-message {
9712
                font-family: arial, verdana, helvetica, sans-serif;
9713
                border-width: 1px;
9714
                border-style: solid;
9715
                left: 50%;
9716
                margin: 10px auto;
9717
                min-height: 30px;
9718
                padding: 5px;
9719
                right: 50%;
9720
                width: 500px;
9721
                background-color: #FFD1D1;
9722
                border-color: #FF0000;
9723
                color: #000;
9724
            }
9725
        </style>
9726
    <body>
9727
        <div class="error-message">
9728
            $lang_not_exportable
9729
        </div>
9730
    </body>
9731
</html>
9732
EOD;
9733
        if (!is_dir($archive_path.$temp_dir_short.'/document')) {
9734
            @mkdir($archive_path.$temp_dir_short.'/document', api_get_permissions_for_new_directories());
9735
        }
9736
        file_put_contents($archive_path.$temp_dir_short.'/document/non_exportable.html', $file_content);
9737
9738
        // Add the extra files that go along with a SCORM package.
9739
        $main_code_path = api_get_path(SYS_CODE_PATH).'newscorm/packaging/';
9740
        $extra_files = scandir($main_code_path);
9741
        foreach ($extra_files as $extra_file) {
9742
            if (strpos($extra_file, '.') === 0)
9743
                continue;
9744
            else {
9745
                $dest_file = $archive_path . $temp_dir_short . '/' . $extra_file;
9746
                $this->create_path($dest_file);
9747
                copy($main_code_path.$extra_file, $dest_file);
9748
            }
9749
        }
9750
9751
        // Finalize the imsmanifest structure, add to the zip, then return the zip.
9752
9753
        $manifest = @$xmldoc->saveXML();
9754
        $manifest = api_utf8_decode_xml($manifest); // The manifest gets the system encoding now.
9755
        file_put_contents($archive_path.'/'.$temp_dir_short.'/imsmanifest.xml', $manifest);
9756
        $zip_folder->add($archive_path.'/'.$temp_dir_short, PCLZIP_OPT_REMOVE_PATH, $archive_path.'/'.$temp_dir_short.'/');
9757
9758
        // Clean possible temporary files.
9759
        foreach ($files_cleanup as $file) {
9760
            $res = unlink($file);
9761
            if ($res === false) {
9762
                error_log(
9763
                    'Could not delete temp file '.$file.' '.__FILE__.' '.__LINE__,
9764
                    0
9765
                );
9766
            }
9767
        }
9768
        $name = api_replace_dangerous_char($this->get_name()).'.zip';
9769
        DocumentManager::file_send_for_download($temp_zip_file, true, $name);
9770
    }
9771
9772
    /**
9773
     * @param int $lp_id
9774
     * @return bool
9775
     */
9776
    public function scorm_export_to_pdf($lp_id)
9777
    {
9778
        $lp_id = intval($lp_id);
9779
        $files_to_export = array();
9780
        $course_data = api_get_course_info($this->cc);
9781
        if (!empty($course_data)) {
9782
            $scorm_path = api_get_path(SYS_COURSE_PATH).$course_data['path'].'/scorm/'.$this->path;
9783
9784
            $list = self::get_flat_ordered_items_list($lp_id);
9785
            if (!empty($list)) {
9786
                foreach ($list as $item_id) {
9787
                    $item = $this->items[$item_id];
9788
                    switch ($item->type) {
9789
                        case 'document':
9790
                            //Getting documents from a LP with chamilo documents
9791
                            $file_data = DocumentManager::get_document_data_by_id($item->path, $this->cc);
9792
                            // Try loading document from the base course.
9793
                            if (empty($file_data) && !empty($sessionId)) {
9794
                                $file_data = DocumentManager::get_document_data_by_id($item->path, $this->cc, false, 0);
9795
                            }
9796
                            $file_path = api_get_path(SYS_COURSE_PATH).$course_data['path'].'/document'.$file_data['path'];
9797
                            if (file_exists($file_path)) {
9798
                                $files_to_export[] = array('title'=>$item->get_title(),'path'=>$file_path);
9799
                            }
9800
                            break;
9801
                        case 'asset': //commes from a scorm package generated by chamilo
9802
                        case 'sco':
9803
                            $file_path = $scorm_path.'/'.$item->path;
9804
                            if (file_exists($file_path)) {
9805
                                $files_to_export[] = array('title'=>$item->get_title(), 'path' => $file_path);
9806
                            }
9807
                            break;
9808
                        case 'dokeos_chapter':
9809
                        case 'dir':
9810
                        case 'chapter':
9811
                            $files_to_export[] = array('title'=> $item->get_title(), 'path'=>null);
9812
                            break;
9813
                    }
9814
                }
9815
            }
9816
            $pdf = new PDF();
9817
            $result = $pdf->html_to_pdf($files_to_export, $this->name, $this->cc, true);
9818
            return $result;
9819
        }
9820
9821
        return false;
9822
    }
9823
9824
    /**
9825
     * Temp function to be moved in main_api or the best place around for this.
9826
     * Creates a file path if it doesn't exist
9827
     * @param string $path
9828
     */
9829
    public function create_path($path)
9830
    {
9831
        $path_bits = explode('/', dirname($path));
9832
9833
        // IS_WINDOWS_OS has been defined in main_api.lib.php
9834
        $path_built = IS_WINDOWS_OS ? '' : '/';
9835
9836
        foreach ($path_bits as $bit) {
9837
            if (!empty ($bit)) {
9838
                $new_path = $path_built . $bit;
9839
                if (is_dir($new_path)) {
9840
                    $path_built = $new_path . '/';
9841
                } else {
9842
                    mkdir($new_path, api_get_permissions_for_new_directories());
9843
                    $path_built = $new_path . '/';
9844
                }
9845
            }
9846
        }
9847
    }
9848
9849
    /**
9850
     * Delete the image relative to this learning path. No parameter. Only works on instanciated object.
9851
     * @return	boolean	The results of the unlink function, or false if there was no image to start with
9852
     */
9853
    public function delete_lp_image()
9854
    {
9855
        $img = $this->get_preview_image();
9856
        if ($img != '') {
9857
            $del_file = $this->get_preview_image_path(null, 'sys');
9858
            if (isset($del_file) && file_exists($del_file)) {
9859
                $del_file_2 = $this->get_preview_image_path(64, 'sys');
9860
                if (file_exists($del_file_2)) {
9861
                    unlink($del_file_2);
9862
                }
9863
                $this->set_preview_image('');
9864
                return @unlink($del_file);
9865
            }
9866
        }
9867
        return false;
9868
    }
9869
9870
    /**
9871
     * Uploads an author image to the upload/learning_path/images directory
9872
     * @param	array	The image array, coming from the $_FILES superglobal
9873
     * @return	boolean	True on success, false on error
9874
     */
9875
    public function upload_image($image_array)
9876
    {
9877
        $image_moved = false;
9878
        if (!empty ($image_array['name'])) {
9879
            $upload_ok = process_uploaded_file($image_array);
9880
            $has_attachment = true;
9881
        } else {
9882
            $image_moved = true;
9883
        }
9884
9885
        if ($upload_ok) {
9886
            if ($has_attachment) {
9887
                $courseDir = api_get_course_path() . '/upload/learning_path/images';
9888
                $sys_course_path = api_get_path(SYS_COURSE_PATH);
9889
                $updir = $sys_course_path . $courseDir;
9890
                // Try to add an extension to the file if it hasn't one.
9891
                $new_file_name = add_ext_on_mime(stripslashes($image_array['name']), $image_array['type']);
9892
9893
                if (!filter_extension($new_file_name)) {
9894
                    //Display :: display_error_message(get_lang('UplUnableToSaveFileFilteredExtension'));
9895
                    $image_moved = false;
9896
                } else {
9897
                    $file_extension = explode('.', $image_array['name']);
9898
                    $file_extension = strtolower($file_extension[sizeof($file_extension) - 1]);
9899
                    $filename = uniqid('');
9900
                    $new_file_name = $filename.'.'.$file_extension;
9901
                    $new_path = $updir.'/'.$new_file_name;
9902
9903
                    // Resize the image.
9904
                    $temp = new Image($image_array['tmp_name']);
9905
                    $temp->resize(104);
9906
                    $result = $temp->send_image($new_path);
9907
9908
                    // Storing the image filename.
9909
                    if ($result) {
9910
                        $image_moved = true;
9911
                        $this->set_preview_image($new_file_name);
9912
9913
                        //Resize to 64px to use on course homepage
9914
                        $temp->resize(64);
9915
                        $temp->send_image($updir.'/'.$filename.'.64.'.$file_extension);
9916
                        return true;
9917
                    }
9918
                }
9919
            }
9920
        }
9921
9922
        return false;
9923
    }
9924
9925
    /**
9926
     * @param int $lp_id
9927
     * @param string $status
9928
     */
9929
    public function set_autolaunch($lp_id, $status)
9930
    {
9931
        $course_id = api_get_course_int_id();
9932
        $lp_id   = intval($lp_id);
9933
        $status  = intval($status);
9934
        $lp_table = Database::get_course_table(TABLE_LP_MAIN);
9935
9936
        // Setting everything to autolaunch = 0
9937
        $attributes['autolaunch'] = 0;
9938
        $where = array('session_id = ? AND c_id = ? '=> array(api_get_session_id(), $course_id));
9939
        Database::update($lp_table, $attributes, $where);
9940
        if ($status == 1) {
9941
            //Setting my lp_id to autolaunch = 1
9942
            $attributes['autolaunch'] = 1;
9943
            $where = array('id = ? AND session_id = ? AND c_id = ?'=> array($lp_id, api_get_session_id(), $course_id));
9944
            Database::update($lp_table, $attributes, $where );
9945
        }
9946
    }
9947
9948
    /**
9949
     * Gets previous_item_id for the next element of the lp_item table
9950
     * @author Isaac flores paz
9951
     * @return	integer	Previous item ID
9952
     */
9953
    public function select_previous_item_id()
9954
    {
9955
        $course_id = api_get_course_int_id();
9956
        if ($this->debug > 0) {
9957
            error_log('New LP - In learnpath::select_previous_item_id()', 0);
9958
        }
9959
        $table_lp_item = Database::get_course_table(TABLE_LP_ITEM);
9960
9961
        // Get the max order of the items
9962
        $sql_max_order = "SELECT max(display_order) AS display_order FROM $table_lp_item
9963
    	                  WHERE c_id = $course_id AND lp_id = '" . $this->lp_id . "'";
9964
        $rs_max_order = Database::query($sql_max_order);
9965
        $row_max_order = Database::fetch_object($rs_max_order);
9966
        $max_order = $row_max_order->display_order;
9967
        // Get the previous item ID
9968
        $sql = "SELECT id as previous FROM $table_lp_item
9969
                WHERE c_id = $course_id AND lp_id = '" . $this->lp_id . "' AND display_order = '".$max_order."' ";
9970
        $rs_max = Database::query($sql);
9971
        $row_max = Database::fetch_object($rs_max);
9972
9973
        // Return the previous item ID
9974
        return $row_max->previous;
9975
    }
9976
9977
    /**
9978
     * Copies an LP
9979
     */
9980
    public function copy()
9981
    {
9982
        $main_path = api_get_path(SYS_CODE_PATH);
9983
        require_once $main_path.'coursecopy/classes/CourseBuilder.class.php';
9984
        require_once $main_path.'coursecopy/classes/CourseArchiver.class.php';
9985
        require_once $main_path.'coursecopy/classes/CourseRestorer.class.php';
9986
        require_once $main_path.'coursecopy/classes/CourseSelectForm.class.php';
9987
9988
        //Course builder
9989
        $cb = new CourseBuilder();
9990
9991
        //Setting tools that will be copied
9992
        $cb->set_tools_to_build(array('learnpaths'));
9993
9994
        //Setting elements that will be copied
9995
        $cb->set_tools_specific_id_list(
9996
            array('learnpaths' => array($this->lp_id))
9997
        );
9998
9999
        $course = $cb->build();
10000
10001
        //Course restorer
10002
        $course_restorer = new CourseRestorer($course);
10003
        $course_restorer->set_add_text_in_items(true);
10004
        $course_restorer->set_tool_copy_settings(array('learnpaths' => array('reset_dates' => true)));
10005
        $course_restorer->restore(api_get_course_id(), api_get_session_id(), false, false);
10006
    }
10007
10008
    public function verify_document_size($s)
10009
    {
10010
        $post_max = ini_get('post_max_size');
10011 View Code Duplication
        if (substr($post_max, -1, 1) == 'M') {
10012
            $post_max = intval(substr($post_max, 0, -1)) * 1024 * 1024;
10013
        } elseif (substr($post_max, -1, 1) == 'G') {
10014
            $post_max = intval(substr($post_max, 0, -1)) * 1024 * 1024 * 1024;
10015
        }
10016
        $upl_max = ini_get('upload_max_filesize');
10017 View Code Duplication
        if (substr($upl_max, -1, 1) == 'M') {
10018
            $upl_max = intval(substr($upl_max, 0, -1)) * 1024 * 1024;
10019
        } elseif (substr($upl_max, -1, 1) == 'G') {
10020
            $upl_max = intval(substr($upl_max, 0, -1)) * 1024 * 1024 * 1024;
10021
        }
10022
        $documents_total_space = DocumentManager::documents_total_space();
10023
        $course_max_space = DocumentManager::get_course_quota();
10024
        $total_size = filesize($s) + $documents_total_space;
10025
        if (filesize($s)>$post_max || filesize($s)>$upl_max  || $total_size>$course_max_space ){
10026
            return true;
10027
        } else{
10028
            return false;
10029
        }
10030
    }
10031
10032
    /**
10033
     * Clear LP prerequisites
10034
     */
10035
    public function clear_prerequisites()
10036
    {
10037
        $course_id = $this->get_course_int_id();
10038
        if ($this->debug > 0) {
10039
            error_log('New LP - In learnpath::clear_prerequisites()', 0);
10040
        }
10041
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
10042
        $lp_id = $this->get_id();
10043
        //Cleaning prerequisites
10044
        $sql = "UPDATE $tbl_lp_item SET prerequisite = ''
10045
                WHERE c_id = ".$course_id." AND lp_id = '$lp_id'";
10046
        Database::query($sql);
10047
10048
        //Cleaning mastery score for exercises
10049
        $sql = "UPDATE $tbl_lp_item SET mastery_score = ''
10050
                WHERE c_id = ".$course_id." AND lp_id = '$lp_id' AND item_type = 'quiz'";
10051
        Database::query($sql);
10052
    }
10053
10054
    public function set_previous_step_as_prerequisite_for_all_items()
10055
    {
10056
        $tbl_lp_item = Database :: get_course_table(TABLE_LP_ITEM);
10057
        $course_id = $this->get_course_int_id();
10058
        $lp_id = $this->get_id();
10059
10060
        if (!empty($this->items)) {
10061
            $previous_item_id = null;
10062
            $previous_item_max = 0;
10063
            $previous_item_type = null;
10064
            $last_item_not_chapter = null;
10065
            $last_item_not_chapter_type = null;
10066
            $last_item_not_chapter_max = null;
10067
            foreach ($this->items as $item) {
10068
                // if there was a previous item... (otherwise jump to set it)
10069
                if (!empty($previous_item_id)) {
10070
                    $current_item_id = $item->get_id(); //save current id
10071
                    if (!in_array($item->get_type(), array('dokeos_chapter', 'chapter'))) {
10072
                        // Current item is not a folder, so it qualifies to get a prerequisites
10073
                        if ($last_item_not_chapter_type == 'quiz') {
10074
                            // if previous is quiz, mark its max score as default score to be achieved
10075
                            $sql = "UPDATE $tbl_lp_item SET mastery_score = '$last_item_not_chapter_max'
10076
                                    WHERE c_id = ".$course_id." AND lp_id = '$lp_id' AND id = '$last_item_not_chapter'";
10077
                            Database::query($sql);
10078
                        }
10079
                        // now simply update the prerequisite to set it to the last non-chapter item
10080
                        $sql = "UPDATE $tbl_lp_item SET prerequisite = '$last_item_not_chapter'
10081
                                WHERE c_id = ".$course_id." AND lp_id = '$lp_id' AND id = '$current_item_id'";
10082
                        Database::query($sql);
10083
                        // record item as 'non-chapter' reference
10084
                        $last_item_not_chapter = $item->get_id();
10085
                        $last_item_not_chapter_type = $item->get_type();
10086
                        $last_item_not_chapter_max = $item->get_max();
10087
                    }
10088
                } else {
10089
                    if (!in_array($item->get_type(), array('dokeos_chapter', 'chapter'))) {
10090
                        // Current item is not a folder (but it is the first item) so record as last "non-chapter" item
10091
                        $last_item_not_chapter = $item->get_id();
10092
                        $last_item_not_chapter_type = $item->get_type();
10093
                        $last_item_not_chapter_max = $item->get_max();
10094
                    }
10095
                }
10096
                // Saving the item as "previous item" for the next loop
10097
                $previous_item_id = $item->get_id();
10098
                $previous_item_max = $item->get_max();
10099
                $previous_item_type = $item->get_type();
10100
            }
10101
        }
10102
    }
10103
10104
    /**
10105
     * @param array $params
10106
     */
10107
    public static function createCategory($params)
10108
    {
10109
        $em = Database::getManager();
10110
        $item = new CLpCategory();
10111
        $item->setName($params['name']);
10112
        $item->setCId($params['c_id']);
10113
        $em->persist($item);
10114
        $em->flush();
10115
    }
10116
    /**
10117
     * @param array $params
10118
     */
10119
    public static function updateCategory($params)
10120
    {
10121
        $em = Database::getManager();
10122
        /** @var CLpCategory $item */
10123
        $item = $em->find('ChamiloCourseBundle:CLpCategory', $params['id']);
10124
        if ($item) {
10125
            $item->setName($params['name']);
10126
            $em->merge($item);
10127
            $em->flush();
10128
        }
10129
    }
10130
10131
    /**
10132
     * @param int $id
10133
     */
10134 View Code Duplication
    public static function moveUpCategory($id)
10135
    {
10136
        $em = Database::getManager();
10137
        /** @var CLpCategory $item */
10138
        $item = $em->find('ChamiloCourseBundle:CLpCategory', $id);
10139
        if ($item) {
10140
            $position = $item->getPosition() - 1;
10141
            $item->setPosition($position);
10142
            $em->persist($item);
10143
            $em->flush();
10144
        }
10145
    }
10146
10147
    /**
10148
     * @param int $id
10149
     */
10150 View Code Duplication
    public static function moveDownCategory($id)
10151
    {
10152
        $em = Database::getManager();
10153
        /** @var CLpCategory $item */
10154
        $item = $em->find('ChamiloCourseBundle:CLpCategory', $id);
10155
        if ($item) {
10156
            $position = $item->getPosition() + 1;
10157
            $item->setPosition($position);
10158
            $em->persist($item);
10159
            $em->flush();
10160
        }
10161
    }
10162
10163
    /**
10164
     * @param int $courseId
10165
     * @return int|mixed
10166
     */
10167
    public static function getCountCategories($courseId)
10168
    {
10169
        if (empty($course_id)) {
0 ignored issues
show
Bug introduced by
The variable $course_id seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
10170
            return 0;
10171
        }
10172
        $em = Database::getManager();
10173
        $query = $em->createQuery('SELECT COUNT(u.id) FROM ChamiloCourseBundle:CLpCategory u WHERE u.cId = :id');
10174
        $query->setParameter('id', $courseId);
10175
10176
        return $query->getSingleScalarResult();
10177
    }
10178
10179
    /**
10180
     * @param int $courseId
10181
     *
10182
     * @return mixed
10183
     */
10184 View Code Duplication
    public static function getCategories($courseId)
10185
    {
10186
        $em = Database::getManager();
10187
        //Default behaviour
10188
        /*$items = $em->getRepository('ChamiloCourseBundle:CLpCategory')->findBy(
10189
            array('cId' => $course_id),
10190
            array('name' => 'ASC')
10191
        );*/
10192
10193
        // Using doctrine extensions
10194
        $items = $em->getRepository('ChamiloCourseBundle:CLpCategory')->getBySortableGroupsQuery(
10195
            array('cId' => $courseId)
10196
        )->getResult();
10197
10198
        return $items;
10199
    }
10200
10201
    /**
10202
     * @param int $id
10203
     *
10204
     * @return mixed
10205
     */
10206
    public static function getCategory($id)
10207
    {
10208
        $em = Database::getManager();
10209
        $item = $em->find('ChamiloCourseBundle:CLpCategory', $id);
10210
10211
        return $item;
10212
    }
10213
10214
    /**
10215
     * @param int $courseId
10216
     * @return array
10217
     */
10218 View Code Duplication
    public static function getCategoryByCourse($courseId)
10219
    {
10220
        $em = Database::getManager();
10221
        $items = $em->getRepository('ChamiloCourseBundle:CLpCategory')->findBy(array('cId' => $courseId));
10222
10223
        return $items;
10224
    }
10225
10226
    /**
10227
     * @param int $id
10228
     *
10229
     * @return mixed
10230
     */
10231
    public static function deleteCategory($id)
10232
    {
10233
        $em = Database::getManager();
10234
        $item = $em->find('ChamiloCourseBundle:CLpCategory', $id);
10235
        if ($item) {
10236
10237
            $courseId = $item->getCId();
10238
            $query = $em->createQuery('SELECT u FROM ChamiloCourseBundle:CLp u WHERE u.cId = :id AND u.categoryId = :catId');
10239
            $query->setParameter('id', $courseId);
10240
            $query->setParameter('catId', $item->getId());
10241
            $lps = $query->getResult();
10242
10243
            // Setting category = 0.
10244
            if ($lps) {
10245
                foreach ($lps as $lpItem) {
10246
                    $lpItem->setCategoryId(0);
10247
                }
10248
            }
10249
10250
            // Removing category.
10251
            $em->remove($item);
10252
            $em->flush();
10253
        }
10254
    }
10255
10256
    /**
10257
     * @param int $courseId
10258
     * @param bool $addSelectOption
10259
     *
10260
     * @return mixed
10261
     */
10262
    static function getCategoryFromCourseIntoSelect($courseId, $addSelectOption = false)
10263
    {
10264
        $items = self::getCategoryByCourse($courseId);
10265
        $cats = array();
10266
        if ($addSelectOption) {
10267
            $cats = array(get_lang('SelectACategory'));
10268
        }
10269
10270
        if (!empty($items)) {
10271
            foreach ($items as $cat) {
10272
                $cats[$cat->getId()] = $cat->getName();
10273
            }
10274
        }
10275
10276
        return $cats;
10277
    }
10278
10279
    /**
10280
     * Return the scorm item type object with spaces replaced with _
10281
     * The return result is use to build a css classname like scorm_type_$return
10282
     * @param $in_type
10283
     * @return mixed
10284
     */
10285
    private static function format_scorm_type_item($in_type)
10286
    {
10287
        return str_replace(' ', '_', $in_type);
10288
    }
10289
10290
    /**
10291
     * @return \learnpath
10292
     */
10293
    public static function getLpFromSession($courseCode, $lp_id, $user_id)
10294
    {
10295
        $lpObject = Session::read('lpobject');
10296
        $learnPath = null;
10297
        if (isset($lpObject)) {
10298
            $learnPath = unserialize($lpObject);
10299
        }
10300
10301
        if (!is_object($learnPath)) {
10302
            $learnPath = new learnpath($courseCode, $lp_id, $user_id);
10303
        }
10304
10305
        return $learnPath;
10306
    }
10307
10308
    /**
10309
     * @param int $itemId
10310
     * @return learnpathItem|false
10311
     */
10312
    public function getItem($itemId)
10313
    {
10314
        if (isset($this->items[$itemId]) && is_object($this->items[$itemId])) {
10315
            return $this->items[$itemId];
10316
        }
10317
10318
        return false;
10319
    }
10320
10321
    /**
10322
     * @return int
10323
     */
10324
    public function getCategoryId()
10325
    {
10326
        return $this->categoryId;
10327
    }
10328
10329
    /**
10330
     * @param int $categoryId
10331
     * @return bool
10332
     */
10333
    public function setCategoryId($categoryId)
10334
    {
10335
        $this->categoryId = intval($categoryId);
10336
10337
        $courseId = api_get_course_int_id();
10338
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
10339
        $lp_id = $this->get_id();
10340
        $sql = "UPDATE $lp_table SET category_id = ".$this->categoryId."
10341
                WHERE c_id = $courseId AND id = $lp_id";
10342
        Database::query($sql);
10343
10344
        return true;
10345
    }
10346
10347
    /**
10348
     * Get whether this is a learning path with the possibility to subscribe
10349
     * users or not
10350
     * @return int
10351
     */
10352
    public function getSubscribeUsers()
10353
    {
10354
        return $this->subscribeUsers;
10355
    }
10356
10357
    /**
10358
     * Set whether this is a learning path with the possibility to subscribe
10359
     * users or not
10360
     * @param int $subscribeUsers (0 = false, 1 = true)
0 ignored issues
show
Bug introduced by
There is no parameter named $subscribeUsers. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
10361
     */
10362
    public function setSubscribeUsers($value)
10363
    {
10364
        if ($this->debug > 0) {
10365
            error_log('New LP - In learnpath::set_subscribe_users()', 0);
10366
        }
10367
        $this->subscribeUsers = intval($value);;
10368
        $lp_table = Database :: get_course_table(TABLE_LP_MAIN);
10369
        $lp_id = $this->get_id();
10370
        $sql = "UPDATE $lp_table SET subscribe_users = ".$this->subscribeUsers."
10371
                WHERE c_id = ".$this->course_int_id." AND id = $lp_id";
10372
        Database::query($sql);
10373
10374
        return true;
10375
    }
10376
10377
    /**
10378
     * Calculate the count of stars for a user in this LP
10379
     * This calculation is based on the following rules:
10380
     * - the student gets one star when he gets to 50% of the learning path
10381
     * - the student gets a second star when the average score of all tests inside the learning path >= 50%
10382
     * - the student gets a third star when the average score of all tests inside the learning path >= 80%
10383
     * - the student gets the final star when the score for the *last* test is >= 80%
10384
     * @param int $sessionId Optional. The session ID
10385
     * @return int The count of stars
10386
     */
10387
    public function getCalculateStars($sessionId = 0)
10388
    {
10389
        $stars = 0;
10390
10391
        $progress = self::getProgress($this->lp_id, $this->user_id, $this->course_int_id, $sessionId);
10392
10393
        if ($progress >= 50) {
10394
            $stars++;
10395
        }
10396
10397
        // Calculate stars chapters evaluation
10398
        $exercisesItems = $this->getExercisesItems();
10399
10400
        if (!empty($exercisesItems)) {
10401
            $totalResult = 0;
10402
10403
            foreach ($exercisesItems as $exerciseItem) {
10404
                $exerciseResultInfo = Event::getExerciseResultsByUser(
10405
                    $this->user_id,
10406
                    $exerciseItem->path,
10407
                    $this->course_int_id,
10408
                    $sessionId,
10409
                    $this->lp_id,
10410
                    $exerciseItem->db_id
10411
                );
10412
10413
                $exerciseResultInfo = end($exerciseResultInfo);
10414
10415
                if (!$exerciseResultInfo) {
10416
                    continue;
10417
                }
10418
10419
                $exerciseResult = $exerciseResultInfo['exe_result'] * 100 / $exerciseResultInfo['exe_weighting'];
10420
10421
                $totalResult += $exerciseResult;
10422
            }
10423
10424
            $totalExerciseAverage = $totalResult / (count($exercisesItems) > 0 ? count($exercisesItems) : 1);
10425
10426
            if ($totalExerciseAverage >= 50) {
10427
                $stars++;
10428
            }
10429
10430
            if ($totalExerciseAverage >= 80) {
10431
                $stars++;
10432
            }
10433
        }
10434
10435
        // Calculate star for final evaluation
10436
        $finalEvaluationItem = $this->getFinalEvaluationItem();
10437
10438
        if (!empty($finalEvaluationItem)) {
10439
            $evaluationResultInfo = Event::getExerciseResultsByUser(
10440
                $this->user_id,
10441
                $finalEvaluationItem->path,
10442
                $this->course_int_id,
10443
                $sessionId,
10444
                $this->lp_id,
10445
                $finalEvaluationItem->db_id
10446
            );
10447
10448
            $evaluationResultInfo = end($evaluationResultInfo);
10449
10450
            if ($evaluationResultInfo) {
10451
                $evaluationResult = $evaluationResultInfo['exe_result'] * 100 / $evaluationResultInfo['exe_weighting'];
10452
10453
                if ($evaluationResult >= 80) {
10454
                    $stars++;
10455
                }
10456
            }
10457
        }
10458
10459
        return $stars;
10460
    }
10461
10462
    /**
10463
     * Get the items of exercise type
10464
     * @return array The items. Otherwise return false
10465
     */
10466 View Code Duplication
    public function getExercisesItems()
10467
    {
10468
        $exercises = [];
10469
10470
        foreach ($this->items as $item) {
10471
            if ($item->type != 'quiz') {
10472
                continue;
10473
            }
10474
10475
            $exercises[] = $item;
10476
        }
10477
10478
        array_pop($exercises);
10479
10480
        return $exercises;
10481
    }
10482
10483
    /**
10484
     * Get the item of exercise type (evaluation type)
10485
     * @return array The final evaluation. Otherwise return false
10486
     */
10487 View Code Duplication
    public function getFinalEvaluationItem()
10488
    {
10489
        $exercises = [];
10490
10491
        foreach ($this->items as $item) {
10492
            if ($item->type != 'quiz') {
10493
                continue;
10494
            }
10495
10496
            $exercises[] = $item;
10497
        }
10498
10499
        return array_pop($exercises);
10500
    }
10501
10502
    /**
10503
     * Calculate the total points achieved for the current user in this learning path
10504
     * @param int $sessionId Optional. The session Id
10505
     * @return int
10506
     */
10507
    public function getCalculateScore($sessionId = 0)
10508
    {
10509
        // Calculate stars chapters evaluation
10510
        $exercisesItems = $this->getExercisesItems();
10511
        $finalEvaluationItem = $this->getFinalEvaluationItem();
10512
10513
        $totalExercisesResult = 0;
10514
        $totalEvaluationResult = 0;
10515
10516
        if ($exercisesItems !== false) {
10517
            foreach ($exercisesItems as $exerciseItem) {
10518
                $exerciseResultInfo = Event::getExerciseResultsByUser(
10519
                    $this->user_id,
10520
                    $exerciseItem->path,
10521
                    $this->course_int_id,
10522
                    $sessionId,
10523
                    $this->lp_id,
10524
                    $exerciseItem->db_id
10525
                );
10526
10527
                $exerciseResultInfo = end($exerciseResultInfo);
10528
10529
                if (!$exerciseResultInfo) {
10530
                    continue;
10531
                }
10532
10533
                $totalExercisesResult += $exerciseResultInfo['exe_result'];
10534
            }
10535
        }
10536
10537
        if (!empty($finalEvaluationItem)) {
10538
            $evaluationResultInfo = Event::getExerciseResultsByUser(
10539
                $this->user_id,
10540
                $finalEvaluationItem->path,
10541
                $this->course_int_id,
10542
                $sessionId,
10543
                $this->lp_id,
10544
                $finalEvaluationItem->db_id
10545
            );
10546
10547
            $evaluationResultInfo = end($evaluationResultInfo);
10548
10549
            if ($evaluationResultInfo) {
10550
                $totalEvaluationResult += $evaluationResultInfo['exe_result'];
10551
            }
10552
        }
10553
10554
        return $totalExercisesResult + $totalEvaluationResult;
10555
    }
10556
10557
    /**
10558
     * Check if URL is not allowed to be show in a iframe
10559
     * @param string $src
10560
     *
10561
     * @return string
10562
     */
10563
    public function fixBlockedLinks($src)
10564
    {
10565
        $urlInfo = parse_url($src);
10566
        //$platformProtocol = api_get_protocol();
10567
10568
        $platformProtocol = 'https';
10569
        if (strpos(api_get_path(WEB_CODE_PATH), 'https') === false) {
10570
            $platformProtocol = 'http';
10571
        }
10572
10573
        $protocolFixApplied = false;
10574
        //Scheme validation to avoid "Notices" when the lesson doesn't contain a valid scheme
10575
        $scheme = isset($urlInfo['scheme']) ? $urlInfo['scheme'] : null;
10576
        if ($platformProtocol != $scheme) {
10577
            $_SESSION['x_frame_source'] = $src;
10578
            $src = 'blank.php?error=x_frames_options';
10579
            $protocolFixApplied = true;
10580
        }
10581
10582
        if ($protocolFixApplied == false) {
10583
            if (strpos($src, api_get_path(WEB_CODE_PATH)) === false) {
10584
                // Check X-Frame-Options
10585
                $ch = curl_init();
10586
10587
                $options = array(
10588
                    CURLOPT_URL => $src,
10589
                    CURLOPT_RETURNTRANSFER => true,
10590
                    CURLOPT_HEADER => true,
10591
                    CURLOPT_FOLLOWLOCATION => true,
10592
                    CURLOPT_ENCODING => "",
10593
                    CURLOPT_AUTOREFERER => true,
10594
                    CURLOPT_CONNECTTIMEOUT => 120,
10595
                    CURLOPT_TIMEOUT => 120,
10596
                    CURLOPT_MAXREDIRS => 10,
10597
                );
10598
                curl_setopt_array($ch, $options);
10599
                $response = curl_exec($ch);
10600
                $httpCode = curl_getinfo($ch);
10601
                $headers = substr($response, 0, $httpCode['header_size']);
10602
10603
                $error = false;
10604
                if (stripos($headers, 'X-Frame-Options: DENY') > -1 ||
10605
                    stripos($headers, 'X-Frame-Options: SAMEORIGIN') > -1
10606
                ) {
10607
                    $error = true;
10608
                }
10609
10610
                if ($error) {
10611
                    $_SESSION['x_frame_source'] = $src;
10612
                    $src = 'blank.php?error=x_frames_options';
10613
                }
10614
            }
10615
        }
10616
10617
        return $src;
10618
    }
10619
10620
    /**
10621
     * Check if this LP has a created forum in the basis course
10622
     * @return boolean
10623
     */
10624
    public function lpHasForum()
10625
    {
10626
        $forumTable = Database::get_course_table(TABLE_FORUM);
10627
        $itemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
10628
10629
        $fakeFrom = "
10630
            $forumTable f
10631
            INNER JOIN $itemProperty ip
10632
            ON (f.forum_id = ip.ref AND f.c_id = ip.c_id)
10633
        ";
10634
10635
        $resultData = Database::select(
10636
            'COUNT(f.iid) AS qty',
10637
            $fakeFrom,
10638
            [
10639
                'where' => [
10640
                    'ip.visibility != ? AND ' => 2,
10641
                    'ip.tool = ? AND ' => TOOL_FORUM,
10642
                    'f.c_id = ? AND ' => intval($this->course_int_id),
10643
                    'f.lp_id = ?' => intval($this->lp_id)
10644
                ]
10645
            ],
10646
            'first'
10647
        );
10648
10649
        if ($resultData['qty'] > 0) {
10650
            return true;
10651
        }
10652
10653
        return false;
10654
    }
10655
10656
    /**
10657
     * Get the forum for this learning path
10658
     * @return boolean
10659
     */
10660
    public function getForum($sessionId = 0)
10661
    {
10662
        $forumTable = Database::get_course_table(TABLE_FORUM);
10663
        $itemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
10664
10665
        $fakeFrom = "$forumTable f
10666
            INNER JOIN $itemProperty ip ";
10667
10668
        if ($this->lp_session_id == 0) {
10669
            $fakeFrom .= "
10670
                ON (
10671
                    f.forum_id = ip.ref AND f.c_id = ip.c_id AND (
10672
                        f.session_id = ip.session_id OR ip.session_id IS NULL
10673
                    )
10674
                )
10675
            ";
10676
        } else {
10677
            $fakeFrom .= "
10678
                ON (
10679
                    f.forum_id = ip.ref AND f.c_id = ip.c_id AND f.session_id = ip.session_id
10680
                )
10681
            ";
10682
        }
10683
10684
        $resultData = Database::select(
10685
            'f.*',
10686
            $fakeFrom,
10687
            [
10688
                'where' => [
10689
                    'ip.visibility != ? AND ' => 2,
10690
                    'ip.tool = ? AND ' => TOOL_FORUM,
10691
                    'f.session_id = ? AND ' => $sessionId,
10692
                    'f.c_id = ? AND ' => intval($this->course_int_id),
10693
                    'f.lp_id = ?' => intval($this->lp_id)
10694
                ]
10695
            ],
10696
            'first'
10697
        );
10698
10699
        if (empty($resultData)) {
10700
            return false;
10701
        }
10702
10703
        return $resultData;
10704
    }
10705
10706
    /**
10707
     * Create a forum for this learning path
10708
     * @param type $forumCategoryId
10709
     * @return int The forum ID if was created. Otherwise return false
10710
     */
10711
    public function createForum($forumCategoryId)
10712
    {
10713
        require_once api_get_path(SYS_CODE_PATH) . '/forum/forumfunction.inc.php';
10714
10715
        $forumId = store_forum(
10716
            [
10717
                'lp_id' => $this->lp_id,
10718
                'forum_title' => $this->name,
10719
                'forum_comment' => null,
10720
                'forum_category' => intval($forumCategoryId),
10721
                'students_can_edit_group' => ['students_can_edit' => 0],
10722
                'allow_new_threads_group' => ['allow_new_threads' => 0],
10723
                'default_view_type_group' => ['default_view_type' => 'flat'],
10724
                'group_forum' => 0,
10725
                'public_private_group_forum_group' => ['public_private_group_forum' => 'public']
10726
            ],
10727
            [],
10728
            true
10729
        );
10730
10731
        return $forumId;
10732
    }
10733
10734
    private function getFinalItem()
10735
    {
10736
10737
        if (empty($this->items)) {
10738
            return null;
10739
        }
10740
10741
        foreach ($this->items as $item) {
10742
            if ($item->type !== 'final_item') {
10743
                continue;
10744
            }
10745
10746
            return $item;
10747
        }
10748
    }
10749
10750
    private function getFinalItemTemplate()
10751
    {
10752
        return file_get_contents(api_get_path(SYS_CODE_PATH) . 'newscorm/final_item_template/template.html');
10753
    }
10754
10755
    private function getSavedFinalItem()
10756
    {
10757
        $finalItem = $this->getFinalItem();
10758
        $doc = DocumentManager::get_document_data_by_id($finalItem->path, $this->cc);
10759
10760
        return file_get_contents($doc['absolute_path']);
10761
    }
10762
10763
    /**
10764
     * 
10765
     * @return html
10766
     */
10767
    public function getFinalItemForm()
10768
    {
10769
        $finalItem = $this->getFinalItem();
10770
        $title = '';
10771
        $content = '';
10772
10773
        if ($finalItem) {
10774
            $title = $finalItem->title;
10775
            $buttonText = get_lang('Save');
10776
            $content = $this->getSavedFinalItem();
10777
        } else {
10778
            $buttonText = get_lang('LPCreateDocument');
10779
            $content = $this->getFinalItemTemplate();
10780
        }
10781
10782
        $courseInfo = api_get_course_info();
10783
        $result = $this->generate_lp_folder($courseInfo);
10784
        $relative_path = api_substr($result['dir'], 1, strlen($result['dir']));
10785
        $relative_prefix = '../../';
10786
10787
        $editorConfig = [
10788
            'ToolbarSet' => 'LearningPathDocuments',
10789
            'Width' => '100%',
10790
            'Height' => '500',
10791
            'FullPage' => true,
10792
            'CreateDocumentDir' => $relative_prefix,
10793
            'CreateDocumentWebDir' => api_get_path(WEB_COURSE_PATH) . api_get_course_path() . '/document/',
10794
            'BaseHref' => api_get_path(WEB_COURSE_PATH) . api_get_course_path() . '/document/' . $relative_path
10795
        ];
10796
10797
        $url = api_get_self() . '?' . api_get_cidreq() . '&' . http_build_query([
10798
            'type' => 'document',
10799
            'lp_id' => $this->lp_id
10800
        ]);
10801
10802
        $form = new FormValidator('final_item', 'POST', $url);
10803
        $form->addText('title', get_lang('Title'));
10804
        $form->addButtonSave($buttonText);
10805
        $renderer = $form->defaultRenderer();
10806
        $renderer->setElementTemplate('<div class="editor-lp">&nbsp;{label}{element}</div>', 'content_lp');
10807
        $form->addHtmlEditor('content_lp', null, null, true, $editorConfig, true);
10808
        $form->addHidden('action', 'add_final_item');
10809
        $form->addHidden('path', isset($_SESSION['pathItem']) ? $_SESSION['pathItem'] : '');
10810
        $form->addHidden('previous', $this->get_last());
10811
10812
        $form->setDefaults(['title' => $title, 'content_lp' => $content]);
10813
10814
        if ($form->validate()) {
10815
            $values = $form->exportValues();
10816
10817
            $lastItemId = $this->get_last();
10818
10819
            if (!$finalItem) {
10820
                $documentId = $this->create_document($this->course_info, $values['content_lp'], $values['title']);
10821
                $this->add_item(
10822
                    0,
10823
                    $lastItemId,
10824
                    'final_item',
10825
                    $documentId,
10826
                    $values['title'],
10827
                    ''
10828
                );
10829
            } else {
10830
                $this->edit_document($this->course_info);
10831
            }
10832
        }
10833
10834
        return $form->returnForm();
10835
    }
10836
}
10837
10838
if (!function_exists('trim_value')) {
10839
    function trim_value(& $value) {
0 ignored issues
show
Best Practice introduced by
The function trim_value() has been defined more than once; this definition is ignored, only the first definition in main/inc/lib/search/ChamiloIndexer.class.php (L90-92) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
10840
        $value = trim($value);
10841
    }
10842
}
10843