Passed
Push — master ( 7a7af2...fe97dd )
by Julito
08:17
created

CourseBuilder::build_learnpaths()   C

Complexity

Conditions 14
Paths 60

Size

Total Lines 136
Code Lines 94

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 94
c 0
b 0
f 0
nc 60
nop 5
dl 0
loc 136
rs 5.1442

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
3
/* For licensing terms, see /license.txt */
4
5
namespace Chamilo\CourseBundle\Component\CourseCopy;
6
7
use Category;
8
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Announcement;
9
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Asset;
10
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Attendance;
11
use Chamilo\CourseBundle\Component\CourseCopy\Resources\CalendarEvent;
12
use Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyLearnpath;
13
use Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyTestCategory;
14
use Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseDescription;
15
use Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseSession;
16
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Document;
17
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Forum;
18
use Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumCategory;
19
use Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumPost;
20
use Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumTopic;
21
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Glossary;
22
use Chamilo\CourseBundle\Component\CourseCopy\Resources\GradeBookBackup;
23
use Chamilo\CourseBundle\Component\CourseCopy\Resources\LearnPathCategory;
24
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Link;
25
use Chamilo\CourseBundle\Component\CourseCopy\Resources\LinkCategory;
26
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Quiz;
27
use Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestion;
28
use Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestionOption;
29
use Chamilo\CourseBundle\Component\CourseCopy\Resources\ScormDocument;
30
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Survey;
31
use Chamilo\CourseBundle\Component\CourseCopy\Resources\SurveyQuestion;
32
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Thematic;
33
use Chamilo\CourseBundle\Component\CourseCopy\Resources\ToolIntro;
34
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Wiki;
35
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Work;
36
use Chamilo\CourseBundle\Entity\CLpCategory;
37
use CourseManager;
38
use Database;
39
use Link as LinkManager;
40
use TestCategory;
41
42
/**
43
 * Class CourseBuilder
44
 * Builds a course-object from a Chamilo-course.
45
 *
46
 * @author Bart Mollet <[email protected]>
47
 */
48
class CourseBuilder
49
{
50
    /** @var Course */
51
    public $course;
52
53
    /* With this array you can filter the tools you want to be parsed by
54
    default all tools are included */
55
    public $tools_to_build = [
56
        'announcements',
57
        'attendance',
58
        'course_descriptions',
59
        'documents',
60
        'events',
61
        'forum_category',
62
        'forums',
63
        'forum_topics',
64
        'glossary',
65
        'quizzes',
66
        'test_category',
67
        'learnpath_category',
68
        'learnpaths',
69
        'links',
70
        'surveys',
71
        'tool_intro',
72
        'thematic',
73
        'wiki',
74
        'works',
75
        'gradebook',
76
    ];
77
78
    public $toolToName = [
79
        'announcements' => RESOURCE_ANNOUNCEMENT,
80
        'attendance' => RESOURCE_ATTENDANCE,
81
        'course_descriptions' => RESOURCE_COURSEDESCRIPTION,
82
        'documents' => RESOURCE_DOCUMENT,
83
        'events' => RESOURCE_EVENT,
84
        'forum_category' => RESOURCE_FORUMCATEGORY,
85
        'forums' => RESOURCE_FORUM,
86
        'forum_topics' => RESOURCE_FORUMTOPIC,
87
        'glossary' => RESOURCE_GLOSSARY,
88
        'quizzes' => RESOURCE_QUIZ,
89
        'test_category' => RESOURCE_TEST_CATEGORY,
90
        'learnpath_category' => RESOURCE_LEARNPATH_CATEGORY,
91
        'learnpaths' => RESOURCE_LEARNPATH,
92
        'links' => RESOURCE_LINK,
93
        'surveys' => RESOURCE_SURVEY,
94
        'tool_intro' => RESOURCE_TOOL_INTRO,
95
        'thematic' => RESOURCE_THEMATIC,
96
        'wiki' => RESOURCE_WIKI,
97
        'works' => RESOURCE_WORK,
98
        'gradebook' => RESOURCE_GRADEBOOK,
99
    ];
100
101
    /* With this array you can filter wich elements of the tools are going
102
    to be added in the course obj (only works with LPs) */
103
    public $specific_id_list = [];
104
    public $documentsAddedInText = [];
105
106
    /**
107
     * Create a new CourseBuilder.
108
     *
109
     * @param string $type
110
     * @param null   $course
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $course is correct as it would always require null to be passed?
Loading history...
111
     */
112
    public function __construct($type = '', $course = null)
113
    {
114
        $_course = api_get_course_info();
115
116
        if (!empty($course['official_code'])) {
117
            $_course = $course;
118
        }
119
120
        $this->course = new Course();
121
        $this->course->code = $_course['code'];
122
        $this->course->type = $type;
0 ignored issues
show
Bug introduced by
The property type does not seem to exist on Chamilo\CourseBundle\Component\CourseCopy\Course.
Loading history...
123
        //   $this->course->path = api_get_path(SYS_COURSE_PATH).$_course['path'].'/';
124
//        $this->course->backup_path = api_get_path(SYS_COURSE_PATH).$_course['path'];
125
        $this->course->encoding = api_get_system_encoding();
126
        $this->course->info = $_course;
0 ignored issues
show
Bug introduced by
The property info does not seem to exist on Chamilo\CourseBundle\Component\CourseCopy\Course.
Loading history...
127
    }
128
129
    /**
130
     * @param array $list
131
     */
132
    public function addDocumentList($list)
133
    {
134
        foreach ($list as $item) {
135
            if (!in_array($item[0], $this->documentsAddedInText)) {
136
                $this->documentsAddedInText[$item[0]] = $item;
137
            }
138
        }
139
    }
140
141
    /**
142
     * @param string $text
143
     */
144
    public function findAndSetDocumentsInText($text)
145
    {
146
        $documentList = \DocumentManager::get_resources_from_source_html($text);
147
        $this->addDocumentList($documentList);
148
    }
149
150
    /**
151
     * Parse documents added in the documentsAddedInText variable.
152
     */
153
    public function restoreDocumentsFromList()
154
    {
155
        if (!empty($this->documentsAddedInText)) {
156
            $list = [];
157
            $courseInfo = api_get_course_info();
158
            foreach ($this->documentsAddedInText as $item) {
159
                // Get information about source url
160
                $url = $item[0]; // url
161
                $scope = $item[1]; // scope (local, remote)
162
                $type = $item[2]; // type (rel, abs, url)
163
164
                $origParseUrl = parse_url($url);
165
                $realOrigPath = isset($origParseUrl['path']) ? $origParseUrl['path'] : null;
166
167
                if ('local' == $scope) {
168
                    if ('abs' == $type || 'rel' == $type) {
169
                        $documentFile = strstr($realOrigPath, 'document');
170
                        if (false !== strpos($realOrigPath, $documentFile)) {
171
                            $documentFile = str_replace('document', '', $documentFile);
172
                            $itemDocumentId = \DocumentManager::get_document_id($courseInfo, $documentFile);
173
                            // Document found! Add it to the list
174
                            if ($itemDocumentId) {
175
                                $list[] = $itemDocumentId;
176
                            }
177
                        }
178
                    }
179
                }
180
            }
181
182
            $this->build_documents(
183
                api_get_session_id(),
184
                api_get_course_int_id(),
185
                true,
186
                $list
187
            );
188
        }
189
    }
190
191
    /**
192
     * @param array $array
193
     */
194
    public function set_tools_to_build($array)
195
    {
196
        $this->tools_to_build = $array;
197
    }
198
199
    /**
200
     * @param array $array
201
     */
202
    public function set_tools_specific_id_list($array)
203
    {
204
        $this->specific_id_list = $array;
205
    }
206
207
    /**
208
     * Get the created course.
209
     *
210
     * @return course The course
211
     */
212
    public function get_course()
213
    {
214
        return $this->course;
215
    }
216
217
    /**
218
     * Build the course-object.
219
     *
220
     * @param int    $session_id
221
     * @param string $courseCode
222
     * @param bool   $withBaseContent   true if you want to get the elements that exists in the course and
223
     *                                  in the session, (session_id = 0 or session_id = X)
224
     * @param array  $parseOnlyToolList
225
     * @param array  $toolsFromPost
226
     *
227
     * @return Course The course object structure
228
     */
229
    public function build(
230
        $session_id = 0,
231
        $courseCode = '',
232
        $withBaseContent = false,
233
        $parseOnlyToolList = [],
234
        $toolsFromPost = []
235
    ) {
236
        $course = api_get_course_info($courseCode);
237
        $courseId = $course['real_id'];
238
        foreach ($this->tools_to_build as $tool) {
239
            if (!empty($parseOnlyToolList) && !in_array($this->toolToName[$tool], $parseOnlyToolList)) {
240
                continue;
241
            }
242
            $function_build = 'build_'.$tool;
243
            $specificIdList = isset($this->specific_id_list[$tool]) ? $this->specific_id_list[$tool] : null;
244
            $buildOrphanQuestions = true;
245
            if ('quizzes' === $tool) {
246
                if (!isset($toolsFromPost[RESOURCE_QUIZ][-1])) {
247
                    $buildOrphanQuestions = false;
248
                }
249
250
                // Force orphan load
251
                if ('complete' === $this->course->type) {
0 ignored issues
show
Bug introduced by
The property type does not seem to exist on Chamilo\CourseBundle\Component\CourseCopy\Course.
Loading history...
252
                    $buildOrphanQuestions = true;
253
                }
254
255
                $this->build_quizzes(
256
                    $session_id,
257
                    $courseId,
258
                    $withBaseContent,
259
                    $specificIdList,
260
                    $buildOrphanQuestions
261
                );
262
            } else {
263
                $this->$function_build(
264
                    $session_id,
265
                    $courseId,
266
                    $withBaseContent,
267
                    $specificIdList
268
                );
269
            }
270
        }
271
272
        // Add asset
273
        /*if ($course['course_image_source'] && basename($course['course_image_source']) !== 'course.png') {
274
            // Add course image courses/XXX/course-pic85x85.png
275
            $asset = new Asset(
276
                $course['course_image_source'],
277
                basename($course['course_image_source']),
278
                basename($course['course_image_source'])
279
            );
280
            $this->course->add_resource($asset);
281
282
            $asset = new Asset(
283
                $course['course_image_large_source'],
284
                basename($course['course_image_large_source']),
285
                basename($course['course_image_large_source'])
286
            );
287
            $this->course->add_resource($asset);
288
        }*/
289
290
        // Once we've built the resources array a bit more, try to get items
291
        // from the item_property table and order them in the "resources" array
292
        $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
293
        foreach ($this->course->resources as $type => $resources) {
294
            if (!empty($parseOnlyToolList) && !in_array($this->toolToName[$tool], $parseOnlyToolList)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tool does not seem to be defined for all execution paths leading up to this point.
Loading history...
295
                continue;
296
            }
297
            foreach ($resources as $id => $resource) {
298
                if ($resource) {
299
                    $tool = $resource->get_tool();
300
                    if (null != $tool) {
301
                        $sql = "SELECT * FROM $table
302
                                WHERE
303
                                    c_id = $courseId AND
304
                                    tool = '".$tool."' AND
305
                                    ref = '".$resource->get_id()."'";
306
                        $res = Database::query($sql);
307
                        $properties = [];
308
                        while ($property = Database::fetch_array($res)) {
309
                            $properties[] = $property;
310
                        }
311
                        $this->course->resources[$type][$id]->item_properties = $properties;
312
                    }
313
                }
314
            }
315
        }
316
317
        return $this->course;
318
    }
319
320
    /**
321
     * Build the documents.
322
     *
323
     * @param int   $session_id
324
     * @param int   $courseId
325
     * @param bool  $withBaseContent
326
     * @param array $idList
327
     */
328
    public function build_documents(
329
        $session_id = 0,
330
        $courseId = 0,
331
        $withBaseContent = false,
332
        $idList = []
333
    ) {
334
        $table_doc = Database::get_course_table(TABLE_DOCUMENT);
335
        $table_prop = Database::get_course_table(TABLE_ITEM_PROPERTY);
336
337
        // Remove chat_files and shared_folder files
338
        $avoid_paths = "
339
                         path NOT LIKE '/shared_folder%' AND
340
                         path NOT LIKE '/chat_files%' AND
341
                         path NOT LIKE '/../exercises/%'
342
                         ";
343
        $documentCondition = '';
344
        if (!empty($idList)) {
345
            $idList = array_unique($idList);
346
            $idList = array_map('intval', $idList);
347
            $documentCondition = ' d.iid IN ("'.implode('","', $idList).'") AND ';
348
        }
349
350
        if (!empty($courseId) && !empty($session_id)) {
351
            $session_id = (int) $session_id;
352
            if ($withBaseContent) {
353
                $session_condition = api_get_session_condition(
354
                    $session_id,
355
                    true,
356
                    true,
357
                    'd.session_id'
358
                );
359
            } else {
360
                $session_condition = api_get_session_condition(
361
                    $session_id,
362
                    true,
363
                    false,
364
                    'd.session_id'
365
                );
366
            }
367
368
            if (!empty($this->course->type) && 'partial' == $this->course->type) {
0 ignored issues
show
Bug introduced by
The property type does not seem to exist on Chamilo\CourseBundle\Component\CourseCopy\Course.
Loading history...
369
                $sql = "SELECT d.iid, d.path, d.comment, d.title, d.filetype, d.size
370
                        FROM $table_doc d
371
                        INNER JOIN $table_prop p
372
                        ON (p.ref = d.id AND d.c_id = p.c_id)
373
                        WHERE
374
                            d.c_id = $courseId AND
375
                            p.c_id = $courseId AND
376
                            tool = '".TOOL_DOCUMENT."' AND
377
                            $documentCondition
378
                            p.visibility != 2 AND
379
                            path NOT LIKE '/images/gallery%' AND
380
                            $avoid_paths
381
                            $session_condition
382
                        ORDER BY path";
383
            } else {
384
                $sql = "SELECT d.iid, d.path, d.comment, d.title, d.filetype, d.size
385
                        FROM $table_doc d
386
                        INNER JOIN $table_prop p
387
                        ON (p.ref = d.id AND d.c_id = p.c_id)
388
                        WHERE
389
                            d.c_id = $courseId AND
390
                            p.c_id = $courseId AND
391
                            tool = '".TOOL_DOCUMENT."' AND
392
                            $documentCondition
393
                            $avoid_paths AND
394
                            p.visibility != 2 $session_condition
395
                        ORDER BY path";
396
            }
397
398
            $db_result = Database::query($sql);
399
            while ($obj = Database::fetch_object($db_result)) {
400
                $doc = new Document(
401
                    $obj->iid,
402
                    $obj->path,
403
                    $obj->comment,
404
                    $obj->title,
405
                    $obj->filetype,
406
                    $obj->size
407
                );
408
                $this->course->add_resource($doc);
409
            }
410
        } else {
411
            if (!empty($this->course->type) && 'partial' == $this->course->type) {
412
                $sql = "SELECT d.iid, d.path, d.comment, d.title, d.filetype, d.size
413
                        FROM $table_doc d
414
                        INNER JOIN $table_prop p
415
                        ON (p.ref = d.id AND d.c_id = p.c_id)
416
                        WHERE
417
                            d.c_id = $courseId AND
418
                            p.c_id = $courseId AND
419
                            tool = '".TOOL_DOCUMENT."' AND
420
                            $documentCondition
421
                            p.visibility != 2 AND
422
                            path NOT LIKE '/images/gallery%' AND
423
                            $avoid_paths AND
424
                            (d.session_id = 0 OR d.session_id IS NULL)
425
                        ORDER BY path";
426
            } else {
427
                $sql = "SELECT d.iid, d.path, d.comment, d.title, d.filetype, d.size
428
                        FROM $table_doc d
429
                        INNER JOIN $table_prop p
430
                        ON (p.ref = d.id AND d.c_id = p.c_id)
431
                        WHERE
432
                            d.c_id = $courseId AND
433
                            p.c_id = $courseId AND
434
                            tool = '".TOOL_DOCUMENT."' AND
435
                            $documentCondition
436
                            p.visibility != 2 AND
437
                            $avoid_paths AND
438
                            (d.session_id = 0 OR d.session_id IS NULL)
439
                        ORDER BY path";
440
            }
441
442
            $result = Database::query($sql);
443
            while ($obj = Database::fetch_object($result)) {
444
                $doc = new Document(
445
                    $obj->iid,
446
                    $obj->path,
447
                    $obj->comment,
448
                    $obj->title,
449
                    $obj->filetype,
450
                    $obj->size
451
                );
452
                $this->course->add_resource($doc);
453
            }
454
        }
455
    }
456
457
    /**
458
     * Build the forums.
459
     *
460
     * @param int   $session_id      Internal session ID
461
     * @param int   $courseId        Internal course ID
462
     * @param bool  $withBaseContent Whether to include content from the course without session or not
463
     * @param array $idList          If you want to restrict the structure to only the given IDs
464
     */
465
    public function build_forums(
466
        $session_id = 0,
467
        $courseId = 0,
468
        $withBaseContent = false,
469
        $idList = []
470
    ) {
471
        $table = Database::get_course_table(TABLE_FORUM);
472
        $sessionCondition = api_get_session_condition(
473
            $session_id,
474
            true,
475
            $withBaseContent
476
        );
477
478
        $idCondition = '';
479
        if (!empty($idList)) {
480
            $idList = array_unique($idList);
481
            $idList = array_map('intval', $idList);
482
            $idCondition = ' AND iid IN ("'.implode('","', $idList).'") ';
483
        }
484
485
        $sql = "SELECT * FROM $table WHERE c_id = $courseId $sessionCondition $idCondition";
486
        $sql .= ' ORDER BY forum_title, forum_category';
487
        $db_result = Database::query($sql);
488
        while ($obj = Database::fetch_object($db_result)) {
489
            $forum = new Forum($obj);
490
            $this->course->add_resource($forum);
491
        }
492
    }
493
494
    /**
495
     * Build a forum-category.
496
     *
497
     * @param int   $session_id      Internal session ID
498
     * @param int   $courseId        Internal course ID
499
     * @param bool  $withBaseContent Whether to include content from the course without session or not
500
     * @param array $idList          If you want to restrict the structure to only the given IDs
501
     */
502
    public function build_forum_category(
503
        $session_id = 0,
504
        $courseId = 0,
505
        $withBaseContent = false,
506
        $idList = []
507
    ) {
508
        $table = Database::get_course_table(TABLE_FORUM_CATEGORY);
509
510
        $sessionCondition = api_get_session_condition(
511
            $session_id,
512
            true,
513
            $withBaseContent
514
        );
515
516
        $idCondition = '';
517
        if (!empty($idList)) {
518
            $idList = array_unique($idList);
519
            $idList = array_map('intval', $idList);
520
            $idCondition = ' AND iid IN ("'.implode('","', $idList).'") ';
521
        }
522
523
        $sql = "SELECT * FROM $table
524
                WHERE c_id = $courseId $sessionCondition $idCondition
525
                ORDER BY cat_title";
526
527
        $result = Database::query($sql);
528
        while ($obj = Database::fetch_object($result)) {
529
            $forumCategory = new ForumCategory($obj);
530
            $this->course->add_resource($forumCategory);
531
        }
532
    }
533
534
    /**
535
     * Build the forum-topics.
536
     *
537
     * @param int   $session_id      Internal session ID
538
     * @param int   $courseId        Internal course ID
539
     * @param bool  $withBaseContent Whether to include content from the course without session or not
540
     * @param array $idList          If you want to restrict the structure to only the given IDs
541
     */
542
    public function build_forum_topics(
543
        $session_id = 0,
544
        $courseId = 0,
545
        $withBaseContent = false,
546
        $idList = []
547
    ) {
548
        $table = Database::get_course_table(TABLE_FORUM_THREAD);
549
550
        $sessionCondition = api_get_session_condition(
551
            $session_id,
552
            true,
553
            $withBaseContent
554
        );
555
556
        $idCondition = '';
557
        if (!empty($idList)) {
558
            $idList = array_map('intval', $idList);
559
            $idCondition = ' AND iid IN ("'.implode('","', $idList).'") ';
560
        }
561
562
        $sql = "SELECT * FROM $table WHERE c_id = $courseId
563
                $sessionCondition
564
                $idCondition
565
                ORDER BY thread_title ";
566
        $result = Database::query($sql);
567
568
        while ($obj = Database::fetch_object($result)) {
569
            $forumTopic = new ForumTopic($obj);
570
            $this->course->add_resource($forumTopic);
571
            $this->build_forum_posts($courseId, $obj->thread_id, $obj->forum_id);
572
        }
573
    }
574
575
    /**
576
     * Build the forum-posts
577
     * TODO: All tree structure of posts should be built, attachments for example.
578
     *
579
     * @param int   $courseId  Internal course ID
580
     * @param int   $thread_id Internal thread ID
581
     * @param int   $forum_id  Internal forum ID
582
     * @param array $idList
583
     */
584
    public function build_forum_posts(
585
        $courseId = 0,
586
        $thread_id = null,
587
        $forum_id = null,
588
        $idList = []
589
    ) {
590
        $table = Database::get_course_table(TABLE_FORUM_POST);
591
        $courseId = (int) $courseId;
592
        $sql = "SELECT * FROM $table WHERE c_id = $courseId ";
593
        if (!empty($thread_id) && !empty($forum_id)) {
594
            $forum_id = (int) $forum_id;
595
            $thread_id = (int) $thread_id;
596
            $sql .= " AND thread_id = $thread_id AND forum_id = $forum_id ";
597
        }
598
599
        if (!empty($idList)) {
600
            $idList = array_map('intval', $idList);
601
            $sql .= ' AND iid IN ("'.implode('","', $idList).'") ';
602
        }
603
604
        $sql .= ' ORDER BY post_id ASC LIMIT 1';
605
        $db_result = Database::query($sql);
606
        while ($obj = Database::fetch_object($db_result)) {
607
            $forum_post = new ForumPost($obj);
608
            $this->course->add_resource($forum_post);
609
        }
610
    }
611
612
    /**
613
     * Build the links.
614
     *
615
     * @param int   $session_id      Internal session ID
616
     * @param int   $courseId        Internal course ID
617
     * @param bool  $withBaseContent Whether to include content from the course without session or not
618
     * @param array $idList          If you want to restrict the structure to only the given IDs
619
     */
620
    public function build_links(
621
        $session_id = 0,
622
        $courseId = 0,
623
        $withBaseContent = false,
624
        $idList = []
625
    ) {
626
        $categories = LinkManager::getLinkCategories(
627
            $courseId,
628
            $session_id,
629
            $withBaseContent
630
        );
631
632
        // Adding empty category
633
        $categories[] = ['id' => 0];
634
635
        foreach ($categories as $category) {
636
            $this->build_link_category($category);
637
638
            $links = LinkManager::getLinksPerCategory(
639
                $category['id'],
640
                $courseId,
641
                $session_id,
642
                $withBaseContent
643
            );
644
645
            foreach ($links as $item) {
646
                if (!empty($idList)) {
647
                    if (!in_array($item['id'], $idList)) {
648
                        continue;
649
                    }
650
                }
651
652
                $link = new Link(
653
                    $item['id'],
654
                    $item['title'],
655
                    $item['url'],
656
                    $item['description'],
657
                    $item['category_id'],
658
                    $item['on_homepage']
659
                );
660
                $link->target = $item['target'];
661
                $this->course->add_resource($link);
662
                $this->course->resources[RESOURCE_LINK][$item['id']]->add_linked_resource(
663
                    RESOURCE_LINKCATEGORY,
664
                    $item['category_id']
665
                );
666
            }
667
        }
668
    }
669
670
    /**
671
     * Build tool intro.
672
     *
673
     * @param int   $session_id      Internal session ID
674
     * @param int   $courseId        Internal course ID
675
     * @param bool  $withBaseContent Whether to include content from the course without session or not
676
     * @param array $idList          If you want to restrict the structure to only the given IDs
677
     */
678
    public function build_tool_intro(
679
        $session_id = 0,
680
        $courseId = 0,
681
        $withBaseContent = false,
682
        $idList = []
683
    ) {
684
        $table = Database::get_course_table(TABLE_TOOL_INTRO);
685
686
        $sessionCondition = api_get_session_condition(
687
            $session_id,
688
            true,
689
            $withBaseContent
690
        );
691
692
        $courseId = (int) $courseId;
693
694
        $sql = "SELECT * FROM $table
695
                WHERE c_id = $courseId $sessionCondition";
696
697
        $db_result = Database::query($sql);
698
        while ($obj = Database::fetch_object($db_result)) {
699
            $tool_intro = new ToolIntro($obj->id, $obj->intro_text);
700
            $this->course->add_resource($tool_intro);
701
        }
702
    }
703
704
    /**
705
     * Build a link category.
706
     *
707
     * @param int $category Internal link ID
708
     *
709
     * @return int
710
     */
711
    public function build_link_category($category)
712
    {
713
        if (empty($category) || empty($category['category_title'])) {
714
            return 0;
715
        }
716
717
        $linkCategory = new LinkCategory(
718
            $category['id'],
719
            $category['category_title'],
720
            $category['description'],
721
            $category['display_order']
722
        );
723
        $this->course->add_resource($linkCategory);
724
725
        return $category['id'];
726
    }
727
728
    /**
729
     * Build the Quizzes.
730
     *
731
     * @param int   $session_id           Internal session ID
732
     * @param int   $courseId             Internal course ID
733
     * @param bool  $withBaseContent      Whether to include content from the course without session or not
734
     * @param array $idList               If you want to restrict the structure to only the given IDs
735
     * @param bool  $buildOrphanQuestions
736
     */
737
    public function build_quizzes(
738
        $session_id = 0,
739
        $courseId = 0,
740
        $withBaseContent = false,
741
        $idList = [],
742
        $buildOrphanQuestions = true
743
    ) {
744
        $table_qui = Database::get_course_table(TABLE_QUIZ_TEST);
745
        $table_rel = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
746
        $table_doc = Database::get_course_table(TABLE_DOCUMENT);
747
748
        $courseId = (int) $courseId;
749
        $idCondition = '';
750
        if (!empty($idList)) {
751
            $idList = array_map('intval', $idList);
752
            $idCondition = ' iid IN ("'.implode('","', $idList).'") AND ';
753
        }
754
755
        if (!empty($courseId) && !empty($session_id)) {
756
            $session_id = (int) $session_id;
757
            if ($withBaseContent) {
758
                $sessionCondition = api_get_session_condition(
759
                    $session_id,
760
                    true,
761
                    true
762
                );
763
            } else {
764
                $sessionCondition = api_get_session_condition(
765
                    $session_id,
766
                    true
767
                );
768
            }
769
770
            // Select only quizzes with active = 0 or 1 (not -1 which is for deleted quizzes)
771
            $sql = "SELECT * FROM $table_qui
772
                    WHERE
773
                      c_id = $courseId AND
774
                      $idCondition
775
                      active >=0
776
                      $sessionCondition ";
777
        } else {
778
            // Select only quizzes with active = 0 or 1 (not -1 which is for deleted quizzes)
779
            $sql = "SELECT * FROM $table_qui
780
                    WHERE
781
                      c_id = $courseId AND
782
                      $idCondition
783
                      active >=0 AND
784
                      (session_id = 0 OR session_id IS NULL)";
785
        }
786
787
        $sql .= ' ORDER BY title';
788
        $db_result = Database::query($sql);
789
        $questionList = [];
790
        while ($obj = Database::fetch_object($db_result)) {
791
            if (strlen($obj->sound) > 0) {
792
                $sql = "SELECT id FROM $table_doc
793
                        WHERE c_id = $courseId AND path = '/audio/".$obj->sound."'";
794
                $res = Database::query($sql);
795
                $doc = Database::fetch_object($res);
796
                $obj->sound = $doc->id;
797
            }
798
            $this->findAndSetDocumentsInText($obj->description);
799
800
            $quiz = new Quiz($obj);
801
            $sql = 'SELECT * FROM '.$table_rel.'
802
                    WHERE c_id = '.$courseId.' AND exercice_id = '.$obj->id;
803
            $db_result2 = Database::query($sql);
804
            while ($obj2 = Database::fetch_object($db_result2)) {
805
                $quiz->add_question($obj2->question_id, $obj2->question_order);
806
                $questionList[] = $obj2->question_id;
807
            }
808
            $this->course->add_resource($quiz);
809
        }
810
811
        if (!empty($courseId)) {
812
            $this->build_quiz_questions($courseId, $questionList, $buildOrphanQuestions);
813
        } else {
814
            $this->build_quiz_questions(0, $questionList, $buildOrphanQuestions);
815
        }
816
    }
817
818
    /**
819
     * Build the Quiz-Questions.
820
     *
821
     * @param int   $courseId             Internal course ID
822
     * @param array $questionList
823
     * @param bool  $buildOrphanQuestions
824
     */
825
    public function build_quiz_questions($courseId = 0, $questionList = [], $buildOrphanQuestions = true)
826
    {
827
        $table_qui = Database::get_course_table(TABLE_QUIZ_TEST);
828
        $table_rel = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
829
        $table_que = Database::get_course_table(TABLE_QUIZ_QUESTION);
830
        $table_ans = Database::get_course_table(TABLE_QUIZ_ANSWER);
831
        $courseId = (int) $courseId;
832
        $questionListToString = implode("','", $questionList);
833
834
        // Building normal tests (many queries)
835
        $sql = "SELECT * FROM $table_que
836
                WHERE c_id = $courseId AND id IN ('$questionListToString')";
837
        $result = Database::query($sql);
838
839
        while ($obj = Database::fetch_object($result)) {
840
            // find the question category
841
            // @todo : need to be adapted for multi category questions in 1.10
842
            $question_category_id = TestCategory::getCategoryForQuestion(
843
                $obj->id,
844
                $courseId
845
            );
846
847
            $this->findAndSetDocumentsInText($obj->description);
848
849
            // build the backup resource question object
850
            $question = new QuizQuestion(
851
                $obj->id,
852
                $obj->question,
853
                $obj->description,
854
                $obj->ponderation,
855
                $obj->type,
856
                $obj->position,
857
                $obj->picture,
858
                $obj->level,
859
                $obj->extra,
860
                $question_category_id
861
            );
862
            $question->addPicture($this);
863
864
            $sql = 'SELECT * FROM '.$table_ans.'
865
                    WHERE c_id = '.$courseId.' AND question_id = '.$obj->id;
866
            $db_result2 = Database::query($sql);
867
            while ($obj2 = Database::fetch_object($db_result2)) {
868
                $question->add_answer(
869
                    $obj2->id,
870
                    $obj2->answer,
871
                    $obj2->correct,
872
                    $obj2->comment,
873
                    $obj2->ponderation,
874
                    $obj2->position,
875
                    $obj2->hotspot_coordinates,
876
                    $obj2->hotspot_type
877
                );
878
879
                $this->findAndSetDocumentsInText($obj2->answer);
880
                $this->findAndSetDocumentsInText($obj2->comment);
881
882
                if (MULTIPLE_ANSWER_TRUE_FALSE == $obj->type) {
883
                    $table_options = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION);
884
                    $sql = 'SELECT * FROM '.$table_options.'
885
                            WHERE c_id = '.$courseId.' AND question_id = '.$obj->id;
886
                    $db_result3 = Database::query($sql);
887
                    while ($obj3 = Database::fetch_object($db_result3)) {
888
                        $question_option = new QuizQuestionOption($obj3);
889
                        $question->add_option($question_option);
890
                    }
891
                }
892
            }
893
            $this->course->add_resource($question);
894
        }
895
896
        if ($buildOrphanQuestions) {
897
            // Building a fictional test for collecting orphan questions.
898
            // When a course is emptied this option should be activated (true).
899
            //$build_orphan_questions = !empty($_POST['recycle_option']);
900
901
            // 1st union gets the orphan questions from deleted exercises
902
            // 2nd union gets the orphan questions from question that were deleted in a exercise.
903
            $sql = " (
904
                        SELECT question_id, q.* FROM $table_que q
905
                        INNER JOIN $table_rel r
906
                        ON (q.c_id = r.c_id AND q.id = r.question_id)
907
                        INNER JOIN $table_qui ex
908
                        ON (ex.id = r.exercice_id AND ex.c_id = r.c_id)
909
                        WHERE ex.c_id = $courseId AND ex.active = '-1'
910
                    )
911
                    UNION
912
                     (
913
                        SELECT question_id, q.* FROM $table_que q
914
                        left OUTER JOIN $table_rel r
915
                        ON (q.c_id = r.c_id AND q.id = r.question_id)
916
                        WHERE q.c_id = $courseId AND r.question_id is null
917
                     )
918
                     UNION
919
                     (
920
                        SELECT question_id, q.* FROM $table_que q
921
                        INNER JOIN $table_rel r
922
                        ON (q.c_id = r.c_id AND q.id = r.question_id)
923
                        WHERE r.c_id = $courseId AND (r.exercice_id = '-1' OR r.exercice_id = '0')
924
                     )
925
                 ";
926
927
            $result = Database::query($sql);
928
            if (Database::num_rows($result) > 0) {
929
                $orphanQuestionIds = [];
930
                while ($obj = Database::fetch_object($result)) {
931
                    // Orphan questions
932
                    if (!empty($obj->question_id)) {
933
                        $obj->id = $obj->question_id;
934
                    }
935
936
                    // Avoid adding the same question twice
937
                    if (!isset($this->course->resources[$obj->id])) {
938
                        // find the question category
939
                        // @todo : need to be adapted for multi category questions in 1.10
940
                        $question_category_id = TestCategory::getCategoryForQuestion($obj->id, $courseId);
941
                        $question = new QuizQuestion(
942
                            $obj->id,
943
                            $obj->question,
944
                            $obj->description,
945
                            $obj->ponderation,
946
                            $obj->type,
947
                            $obj->position,
948
                            $obj->picture,
949
                            $obj->level,
950
                            $obj->extra,
951
                            $question_category_id
952
                        );
953
                        $question->addPicture($this);
954
                        $sql = "SELECT * FROM $table_ans
955
                                WHERE c_id = $courseId AND question_id = ".$obj->id;
956
                        $db_result2 = Database::query($sql);
957
                        if (Database::num_rows($db_result2)) {
958
                            while ($obj2 = Database::fetch_object($db_result2)) {
959
                                $question->add_answer(
960
                                    $obj2->id,
961
                                    $obj2->answer,
962
                                    $obj2->correct,
963
                                    $obj2->comment,
964
                                    $obj2->ponderation,
965
                                    $obj2->position,
966
                                    $obj2->hotspot_coordinates,
967
                                    $obj2->hotspot_type
968
                                );
969
                            }
970
                            $orphanQuestionIds[] = $obj->id;
971
                        }
972
                        $this->course->add_resource($question);
973
                    }
974
                }
975
            }
976
        }
977
978
        $obj = [
979
            'id' => -1,
980
            'title' => get_lang('Orphan questions'),
981
            'type' => 2,
982
        ];
983
        $newQuiz = new Quiz((object) $obj);
984
        if (!empty($orphanQuestionIds)) {
985
            foreach ($orphanQuestionIds as $index => $orphanId) {
986
                $order = $index + 1;
987
                $newQuiz->add_question($orphanId, $order);
988
            }
989
        }
990
        $this->course->add_resource($newQuiz);
991
    }
992
993
    /**
994
     * @deprecated
995
     * Build the orphan questions
996
     */
997
    public function build_quiz_orphan_questions()
998
    {
999
        $table_qui = Database::get_course_table(TABLE_QUIZ_TEST);
1000
        $table_rel = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
1001
        $table_que = Database::get_course_table(TABLE_QUIZ_QUESTION);
1002
        $table_ans = Database::get_course_table(TABLE_QUIZ_ANSWER);
1003
1004
        $courseId = api_get_course_int_id();
1005
1006
        $sql = 'SELECT *
1007
                FROM '.$table_que.' as questions
1008
                LEFT JOIN '.$table_rel.' as quizz_questions
1009
                ON questions.id=quizz_questions.question_id
1010
                LEFT JOIN '.$table_qui.' as exercises
1011
                ON quizz_questions.exercice_id = exercises.id
1012
                WHERE
1013
                    questions.c_id = quizz_questions.c_id AND
1014
                    questions.c_id = exercises.c_id AND
1015
                    exercises.c_id = '.$courseId.' AND
1016
                    (quizz_questions.exercice_id IS NULL OR
1017
                    exercises.active = -1)';
1018
1019
        $db_result = Database::query($sql);
1020
        if (Database::num_rows($db_result) > 0) {
1021
            // This is the fictional test for collecting orphan questions.
1022
            $orphan_questions = new Quiz(
1023
                -1,
1024
                get_lang('Orphan questions'),
1025
                '',
1026
                0,
1027
                0,
1028
                1,
1029
                '',
1030
                0
1031
            );
1032
1033
            $this->course->add_resource($orphan_questions);
1034
            while ($obj = Database::fetch_object($db_result)) {
1035
                $question = new QuizQuestion(
1036
                    $obj->id,
1037
                    $obj->question,
1038
                    $obj->description,
1039
                    $obj->ponderation,
1040
                    $obj->type,
1041
                    $obj->position,
1042
                    $obj->picture,
1043
                    $obj->level,
1044
                    $obj->extra
1045
                );
1046
                $question->addPicture($this);
1047
1048
                $sql = 'SELECT * FROM '.$table_ans.' WHERE question_id = '.$obj->id;
1049
                $db_result2 = Database::query($sql);
1050
                while ($obj2 = Database::fetch_object($db_result2)) {
1051
                    $question->add_answer(
1052
                        $obj2->id,
1053
                        $obj2->answer,
1054
                        $obj2->correct,
1055
                        $obj2->comment,
1056
                        $obj2->ponderation,
1057
                        $obj2->position,
1058
                        $obj2->hotspot_coordinates,
1059
                        $obj2->hotspot_type
1060
                    );
1061
                }
1062
                $this->course->add_resource($question);
1063
            }
1064
        }
1065
    }
1066
1067
    /**
1068
     * Build the test category.
1069
     *
1070
     * @param int   $sessionId       Internal session ID
1071
     * @param int   $courseId        Internal course ID
1072
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1073
     * @param array $idList          If you want to restrict the structure to only the given IDs
1074
     *
1075
     * @todo add course session
1076
     */
1077
    public function build_test_category(
1078
        $sessionId = 0,
1079
        $courseId = 0,
1080
        $withBaseContent = false,
1081
        $idList = []
1082
    ) {
1083
        // get all test category in course
1084
        $category = new TestCategory();
1085
        $categories = $category->getCategories();
0 ignored issues
show
Bug introduced by
The call to TestCategory::getCategories() has too few arguments starting with courseId. ( Ignorable by Annotation )

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

1085
        /** @scrutinizer ignore-call */ 
1086
        $categories = $category->getCategories();

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
1086
        foreach ($categories as $category) {
1087
            $this->findAndSetDocumentsInText($category->description);
1088
1089
            /** @var TestCategory $category */
1090
            $courseCopyTestCategory = new CourseCopyTestCategory(
1091
                $category->id,
1092
                $category->name,
1093
                $category->description
1094
            );
1095
            $this->course->add_resource($courseCopyTestCategory);
1096
        }
1097
    }
1098
1099
    /**
1100
     * Build the Surveys.
1101
     *
1102
     * @param int   $session_id      Internal session ID
1103
     * @param int   $courseId        Internal course ID
1104
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1105
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1106
     */
1107
    public function build_surveys(
1108
        $session_id = 0,
1109
        $courseId = 0,
1110
        $withBaseContent = false,
1111
        $id_list = []
1112
    ) {
1113
        $table_survey = Database::get_course_table(TABLE_SURVEY);
1114
        $table_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1115
1116
        $courseId = (int) $courseId;
1117
1118
        $sessionCondition = api_get_session_condition(
1119
            $session_id,
1120
            true,
1121
            $withBaseContent
1122
        );
1123
1124
        $sql = 'SELECT * FROM '.$table_survey.'
1125
                WHERE c_id = '.$courseId.' '.$sessionCondition;
1126
        if ($id_list) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id_list of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1127
            $sql .= ' AND iid IN ('.implode(', ', $id_list).')';
1128
        }
1129
        $db_result = Database::query($sql);
1130
        while ($obj = Database::fetch_object($db_result)) {
1131
            $survey = new Survey(
1132
                $obj->survey_id,
1133
                $obj->code,
1134
                $obj->title,
1135
                $obj->subtitle,
1136
                $obj->author,
1137
                $obj->lang,
1138
                $obj->avail_from,
1139
                $obj->avail_till,
1140
                $obj->is_shared,
1141
                $obj->template,
1142
                $obj->intro,
1143
                $obj->surveythanks,
1144
                $obj->creation_date,
1145
                $obj->invited,
1146
                $obj->answered,
1147
                $obj->invite_mail,
1148
                $obj->reminder_mail,
1149
                $obj->one_question_per_page,
1150
                $obj->shuffle
1151
            );
1152
            $sql = 'SELECT * FROM '.$table_question.'
1153
                    WHERE c_id = '.$courseId.' AND survey_id = '.$obj->survey_id;
1154
            $db_result2 = Database::query($sql);
1155
            while ($obj2 = Database::fetch_object($db_result2)) {
1156
                $survey->add_question($obj2->question_id);
1157
            }
1158
            $this->course->add_resource($survey);
1159
        }
1160
        $this->build_survey_questions($courseId);
1161
    }
1162
1163
    /**
1164
     * Build the Survey Questions.
1165
     *
1166
     * @param int $courseId Internal course ID
1167
     */
1168
    public function build_survey_questions($courseId)
1169
    {
1170
        $table_que = Database::get_course_table(TABLE_SURVEY_QUESTION);
1171
        $table_opt = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1172
1173
        $courseId = (int) $courseId;
1174
        $idList = isset($this->specific_id_list['surveys']) ? $this->specific_id_list['surveys'] : [];
1175
1176
        $sql = 'SELECT * FROM '.$table_que.' WHERE c_id = '.$courseId.'  ';
1177
1178
        if (!empty($idList)) {
1179
            $sql .= ' AND survey_id IN ('.implode(', ', $idList).')';
1180
        }
1181
1182
        $db_result = Database::query($sql);
1183
        $is_required = 0;
1184
        while ($obj = Database::fetch_object($db_result)) {
1185
            if (api_get_configuration_value('allow_required_survey_questions')) {
1186
                if (isset($obj->is_required)) {
1187
                    $is_required = $obj->is_required;
1188
                }
1189
            }
1190
            $question = new SurveyQuestion(
1191
                $obj->question_id,
1192
                $obj->survey_id,
1193
                $obj->survey_question,
1194
                $obj->survey_question_comment,
1195
                $obj->type,
1196
                $obj->display,
1197
                $obj->sort,
1198
                $obj->shared_question_id,
1199
                $obj->max_value,
1200
                $is_required
1201
            );
1202
            $sql = 'SELECT * FROM '.$table_opt.'
1203
                    WHERE c_id = '.$courseId.' AND question_id = '.$obj->question_id;
1204
            $db_result2 = Database::query($sql);
1205
            while ($obj2 = Database::fetch_object($db_result2)) {
1206
                $question->add_answer($obj2->option_text, $obj2->sort);
1207
            }
1208
            $this->course->add_resource($question);
1209
        }
1210
    }
1211
1212
    /**
1213
     * Build the announcements.
1214
     *
1215
     * @param int   $session_id      Internal session ID
1216
     * @param int   $courseId        Internal course ID
1217
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1218
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1219
     */
1220
    public function build_announcements(
1221
        $session_id = 0,
1222
        $courseId = 0,
1223
        $withBaseContent = false,
1224
        $id_list = []
1225
    ) {
1226
        $table = Database::get_course_table(TABLE_ANNOUNCEMENT);
1227
1228
        $sessionCondition = api_get_session_condition(
1229
            $session_id,
1230
            true,
1231
            $withBaseContent
1232
        );
1233
1234
        $courseId = (int) $courseId;
1235
1236
        $sql = 'SELECT * FROM '.$table.'
1237
                WHERE c_id = '.$courseId.' '.$sessionCondition;
1238
        $db_result = Database::query($sql);
1239
        $table_attachment = Database::get_course_table(
1240
            TABLE_ANNOUNCEMENT_ATTACHMENT
1241
        );
1242
        while ($obj = Database::fetch_object($db_result)) {
1243
            if (empty($obj->id)) {
1244
                continue;
1245
            }
1246
            $sql = 'SELECT path, comment, filename, size
1247
                    FROM '.$table_attachment.'
1248
                    WHERE c_id = '.$courseId.' AND announcement_id = '.$obj->id.'';
1249
            $result = Database::query($sql);
1250
            $attachment_obj = Database::fetch_object($result);
1251
            $att_path = $att_filename = $att_size = $atth_comment = '';
1252
1253
            if (!empty($attachment_obj)) {
1254
                $att_path = $attachment_obj->path;
1255
                $att_filename = $attachment_obj->filename;
1256
                $att_size = $attachment_obj->size;
1257
                $atth_comment = $attachment_obj->comment;
1258
            }
1259
1260
            $announcement = new Announcement(
1261
                $obj->id,
1262
                $obj->title,
1263
                $obj->content,
1264
                $obj->end_date,
1265
                $obj->display_order,
1266
                $obj->email_sent,
1267
                $att_path,
1268
                $att_filename,
1269
                $att_size,
1270
                $atth_comment
1271
            );
1272
            $this->course->add_resource($announcement);
1273
        }
1274
    }
1275
1276
    /**
1277
     * Build the events.
1278
     *
1279
     * @param int   $session_id      Internal session ID
1280
     * @param int   $courseId        Internal course ID
1281
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1282
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1283
     */
1284
    public function build_events(
1285
        $session_id = 0,
1286
        $courseId = 0,
1287
        $withBaseContent = false,
1288
        $id_list = []
1289
    ) {
1290
        $table = Database::get_course_table(TABLE_AGENDA);
1291
1292
        $sessionCondition = api_get_session_condition(
1293
            $session_id,
1294
            true,
1295
            $withBaseContent
1296
        );
1297
1298
        $courseId = (int) $courseId;
1299
1300
        $sql = 'SELECT * FROM '.$table.'
1301
                WHERE c_id = '.$courseId.' '.$sessionCondition;
1302
        $db_result = Database::query($sql);
1303
        while ($obj = Database::fetch_object($db_result)) {
1304
            $table_attachment = Database::get_course_table(
1305
                TABLE_AGENDA_ATTACHMENT
1306
            );
1307
            $sql = 'SELECT path, comment, filename, size
1308
                    FROM '.$table_attachment.'
1309
                    WHERE c_id = '.$courseId.' AND agenda_id = '.$obj->id.'';
1310
            $result = Database::query($sql);
1311
1312
            $attachment_obj = Database::fetch_object($result);
1313
            $att_path = $att_filename = $att_size = $atth_comment = '';
1314
            if (!empty($attachment_obj)) {
1315
                $att_path = $attachment_obj->path;
1316
                $att_filename = $attachment_obj->filename;
1317
                $att_size = $attachment_obj->size;
1318
                $atth_comment = $attachment_obj->comment;
1319
            }
1320
            $event = new CalendarEvent(
1321
                $obj->id,
1322
                $obj->title,
1323
                $obj->content,
1324
                $obj->start_date,
1325
                $obj->end_date,
1326
                $att_path,
1327
                $att_filename,
1328
                $att_size,
1329
                $atth_comment,
1330
                $obj->all_day
1331
            );
1332
            $this->course->add_resource($event);
1333
        }
1334
    }
1335
1336
    /**
1337
     * Build the course-descriptions.
1338
     *
1339
     * @param int   $session_id      Internal session ID
1340
     * @param int   $courseId        Internal course ID
1341
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1342
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1343
     */
1344
    public function build_course_descriptions(
1345
        $session_id = 0,
1346
        $courseId = 0,
1347
        $withBaseContent = false,
1348
        $id_list = []
1349
    ) {
1350
        $table = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
1351
        $courseId = (int) $courseId;
1352
1353
        if (!empty($session_id) && !empty($courseId)) {
1354
            $session_id = (int) $session_id;
1355
            if ($withBaseContent) {
1356
                $sessionCondition = api_get_session_condition(
1357
                    $session_id,
1358
                    true,
1359
                    true
1360
                );
1361
            } else {
1362
                $sessionCondition = api_get_session_condition(
1363
                    $session_id,
1364
                    true
1365
                );
1366
            }
1367
            $sql = 'SELECT * FROM '.$table.'
1368
                    WHERE c_id = '.$courseId.' '.$sessionCondition;
1369
        } else {
1370
            $table = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
1371
            $sql = 'SELECT * FROM '.$table.'
1372
                    WHERE c_id = '.$courseId.'  AND session_id = 0';
1373
        }
1374
1375
        $db_result = Database::query($sql);
1376
        while ($obj = Database::fetch_object($db_result)) {
1377
            $cd = new CourseDescription(
1378
                $obj->id,
1379
                $obj->title,
1380
                $obj->content,
1381
                $obj->description_type
1382
            );
1383
            $this->course->add_resource($cd);
1384
        }
1385
    }
1386
1387
    /**
1388
     * @param int   $session_id
1389
     * @param int   $courseId
1390
     * @param bool  $withBaseContent
1391
     * @param array $idList
1392
     */
1393
    public function build_learnpath_category($session_id = 0, $courseId = 0, $withBaseContent = false, $idList = [])
1394
    {
1395
        $categories = \learnpath::getCategories($courseId);
1396
1397
        /** @var CLpCategory $item */
1398
        foreach ($categories as $item) {
1399
            $categoryId = $item->getId();
0 ignored issues
show
Bug introduced by
The method getId() does not exist on Chamilo\CourseBundle\Entity\CLpCategory. Did you maybe mean getIid()? ( Ignorable by Annotation )

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

1399
            /** @scrutinizer ignore-call */ 
1400
            $categoryId = $item->getId();

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

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

Loading history...
1400
            if (!empty($idList)) {
1401
                if (!in_array($categoryId, $idList)) {
1402
                    continue;
1403
                }
1404
            }
1405
            $category = new LearnPathCategory($categoryId, $item);
1406
            $this->course->add_resource($category);
1407
        }
1408
    }
1409
1410
    /**
1411
     * Build the learnpaths.
1412
     *
1413
     * @param int   $session_id      Internal session ID
1414
     * @param int   $courseId        Internal course ID
1415
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1416
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1417
     * @param bool  $addScormFolder
1418
     */
1419
    public function build_learnpaths(
1420
        $session_id = 0,
1421
        $courseId = 0,
1422
        $withBaseContent = false,
1423
        $id_list = [],
1424
        $addScormFolder = true
1425
    ) {
1426
        $table_main = Database::get_course_table(TABLE_LP_MAIN);
1427
        $table_item = Database::get_course_table(TABLE_LP_ITEM);
1428
        $table_tool = Database::get_course_table(TABLE_TOOL_LIST);
1429
1430
        $courseId = (int) $courseId;
1431
1432
        if (!empty($session_id) && !empty($courseId)) {
1433
            $session_id = (int) $session_id;
1434
            if ($withBaseContent) {
1435
                $sessionCondition = api_get_session_condition(
1436
                    $session_id,
1437
                    true,
1438
                    true
1439
                );
1440
            } else {
1441
                $sessionCondition = api_get_session_condition(
1442
                    $session_id,
1443
                    true
1444
                );
1445
            }
1446
            $sql = 'SELECT * FROM '.$table_main.'
1447
                    WHERE c_id = '.$courseId.'  '.$sessionCondition;
1448
        } else {
1449
            $sql = 'SELECT * FROM '.$table_main.'
1450
                    WHERE c_id = '.$courseId.' AND (session_id = 0 OR session_id IS NULL)';
1451
        }
1452
1453
        if (!empty($id_list)) {
1454
            $id_list = array_map('intval', $id_list);
1455
            $sql .= ' AND id IN ('.implode(', ', $id_list).') ';
1456
        }
1457
1458
        $result = Database::query($sql);
1459
        if ($result) {
0 ignored issues
show
introduced by
$result is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
1460
            while ($obj = Database::fetch_object($result)) {
1461
                $items = [];
1462
                $sql = "SELECT * FROM $table_item
1463
                        WHERE c_id = '$courseId' AND lp_id = ".$obj->id;
1464
                $resultItem = Database::query($sql);
1465
                while ($obj_item = Database::fetch_object($resultItem)) {
1466
                    $item['id'] = $obj_item->iid;
1467
                    $item['item_type'] = $obj_item->item_type;
1468
                    $item['ref'] = $obj_item->ref;
1469
                    $item['title'] = $obj_item->title;
1470
                    $item['description'] = $obj_item->description;
1471
                    $item['path'] = $obj_item->path;
1472
                    $item['min_score'] = $obj_item->min_score;
1473
                    $item['max_score'] = $obj_item->max_score;
1474
                    $item['mastery_score'] = $obj_item->mastery_score;
1475
                    $item['parent_item_id'] = $obj_item->parent_item_id;
1476
                    $item['previous_item_id'] = $obj_item->previous_item_id;
1477
                    $item['next_item_id'] = $obj_item->next_item_id;
1478
                    $item['display_order'] = $obj_item->display_order;
1479
                    $item['prerequisite'] = $obj_item->prerequisite;
1480
                    $item['parameters'] = $obj_item->parameters;
1481
                    $item['launch_data'] = $obj_item->launch_data;
1482
                    $item['audio'] = $obj_item->audio;
1483
                    $items[] = $item;
1484
                }
1485
1486
                $sql = "SELECT id FROM $table_tool
1487
                        WHERE
1488
                            c_id = $courseId AND
1489
                            (link LIKE '%lp_controller.php%lp_id=".$obj->id."%' AND image='scormbuilder.gif') AND
1490
                            visibility = '1' ";
1491
                $db_tool = Database::query($sql);
1492
                $visibility = '0';
1493
                if (Database::num_rows($db_tool)) {
1494
                    $visibility = '1';
1495
                }
1496
1497
                $lp = new CourseCopyLearnpath(
1498
                    $obj->id,
1499
                    $obj->lp_type,
1500
                    $obj->name,
1501
                    $obj->path,
1502
                    $obj->ref,
1503
                    $obj->description,
1504
                    $obj->content_local,
1505
                    $obj->default_encoding,
1506
                    $obj->default_view_mod,
1507
                    $obj->prevent_reinit,
1508
                    $obj->force_commit,
1509
                    $obj->content_maker,
1510
                    $obj->display_order,
1511
                    $obj->js_lib,
1512
                    $obj->content_license,
1513
                    $obj->debug,
1514
                    $visibility,
1515
                    $obj->author,
1516
                    //$obj->preview_image,
1517
                    $obj->use_max_score,
1518
                    $obj->autolaunch,
1519
                    $obj->created_on,
1520
                    $obj->modified_on,
1521
                    $obj->publicated_on,
1522
                    $obj->expired_on,
1523
                    $obj->session_id,
1524
                    $obj->category_id,
1525
                    $items
1526
                );
1527
1528
                $this->course->add_resource($lp);
1529
1530
                /*if (!empty($obj->preview_image)) {
1531
                    // Add LP teacher image
1532
                    $asset = new Asset(
1533
                        $obj->preview_image,
1534
                        '/upload/learning_path/images/'.$obj->preview_image,
1535
                        '/upload/learning_path/images/'.$obj->preview_image
1536
                    );
1537
                    $this->course->add_resource($asset);
1538
                }*/
1539
            }
1540
        }
1541
1542
        // Save scorm directory (previously build_scorm_documents())
1543
        if ($addScormFolder) {
1544
            $i = 1;
1545
            if ($dir = @opendir($this->course->backup_path.'/scorm')) {
1546
                while ($file = readdir($dir)) {
1547
                    if (is_dir($this->course->backup_path.'/scorm/'.$file) &&
1548
                        !in_array($file, ['.', '..'])
1549
                    ) {
1550
                        $doc = new ScormDocument($i++, '/'.$file, $file);
1551
                        $this->course->add_resource($doc);
1552
                    }
1553
                }
1554
                closedir($dir);
1555
            }
1556
        }
1557
    }
1558
1559
    /**
1560
     * Build the glossaries.
1561
     *
1562
     * @param int   $session_id      Internal session ID
1563
     * @param int   $courseId        Internal course ID
1564
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1565
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1566
     */
1567
    public function build_glossary(
1568
        $session_id = 0,
1569
        $courseId = 0,
1570
        $withBaseContent = false,
1571
        $id_list = []
1572
    ) {
1573
        $table_glossary = Database::get_course_table(TABLE_GLOSSARY);
1574
1575
        $courseId = (int) $courseId;
1576
1577
        if (!empty($session_id) && !empty($courseId)) {
1578
            $session_id = (int) $session_id;
1579
            if ($withBaseContent) {
1580
                $sessionCondition = api_get_session_condition(
1581
                    $session_id,
1582
                    true,
1583
                    true
1584
                );
1585
            } else {
1586
                $sessionCondition = api_get_session_condition(
1587
                    $session_id,
1588
                    true
1589
                );
1590
            }
1591
1592
            //@todo check this queries are the same ...
1593
            if (!empty($this->course->type) && 'partial' == $this->course->type) {
0 ignored issues
show
Bug introduced by
The property type does not seem to exist on Chamilo\CourseBundle\Component\CourseCopy\Course.
Loading history...
1594
                $sql = 'SELECT * FROM '.$table_glossary.' g
1595
                        WHERE g.c_id = '.$courseId.' '.$sessionCondition;
1596
            } else {
1597
                $sql = 'SELECT * FROM '.$table_glossary.' g
1598
                        WHERE g.c_id = '.$courseId.' '.$sessionCondition;
1599
            }
1600
        } else {
1601
            $table_glossary = Database::get_course_table(TABLE_GLOSSARY);
1602
            //@todo check this queries are the same ... ayayay
1603
            if (!empty($this->course->type) && 'partial' == $this->course->type) {
1604
                $sql = 'SELECT * FROM '.$table_glossary.' g
1605
                        WHERE g.c_id = '.$courseId.' AND (session_id = 0 OR session_id IS NULL)';
1606
            } else {
1607
                $sql = 'SELECT * FROM '.$table_glossary.' g
1608
                        WHERE g.c_id = '.$courseId.' AND (session_id = 0 OR session_id IS NULL)';
1609
            }
1610
        }
1611
        $db_result = Database::query($sql);
1612
        while ($obj = Database::fetch_object($db_result)) {
1613
            $doc = new Glossary(
1614
                $obj->glossary_id,
1615
                $obj->name,
1616
                $obj->description,
1617
                $obj->display_order
1618
            );
1619
            $this->course->add_resource($doc);
1620
        }
1621
    }
1622
1623
    /*
1624
     * Build session course by jhon
1625
     */
1626
    public function build_session_course()
1627
    {
1628
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
1629
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
1630
        $list_course = CourseManager::get_course_list();
1631
        $list = [];
1632
        foreach ($list_course as $_course) {
1633
            $this->course = new Course();
1634
            $this->course->code = $_course['code'];
1635
            $this->course->type = 'partial';
0 ignored issues
show
Bug introduced by
The property type does not seem to exist on Chamilo\CourseBundle\Component\CourseCopy\Course.
Loading history...
1636
            $this->course->path = api_get_path(SYS_COURSE_PATH).$_course['directory'].'/';
0 ignored issues
show
Bug introduced by
The constant Chamilo\CourseBundle\Com...rseCopy\SYS_COURSE_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1637
            $this->course->backup_path = api_get_path(SYS_COURSE_PATH).$_course['directory'];
1638
            $this->course->encoding = api_get_system_encoding(); //current platform encoding
1639
            $courseId = $_course['real_id'];
1640
            $sql = "SELECT s.id, name, c_id
1641
                    FROM $tbl_session_course sc
1642
                    INNER JOIN $tbl_session s
1643
                    ON sc.session_id = s.id
1644
                    WHERE sc.c_id = '$courseId' ";
1645
            $query_session = Database::query($sql);
1646
            while ($rows_session = Database::fetch_assoc($query_session)) {
1647
                $session = new CourseSession(
1648
                    $rows_session['id'],
1649
                    $rows_session['name']
1650
                );
1651
                $this->course->add_resource($session);
1652
            }
1653
            $list[] = $this->course;
1654
        }
1655
1656
        return $list;
1657
    }
1658
1659
    /**
1660
     * @param int   $session_id      Internal session ID
1661
     * @param int   $courseId        Internal course ID
1662
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1663
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1664
     */
1665
    public function build_wiki(
1666
        $session_id = 0,
1667
        $courseId = 0,
1668
        $withBaseContent = false,
1669
        $id_list = []
1670
    ) {
1671
        $tbl_wiki = Database::get_course_table(TABLE_WIKI);
1672
        $courseId = (int) $courseId;
1673
1674
        if (!empty($session_id) && !empty($courseId)) {
1675
            $session_id = (int) $session_id;
1676
            if ($withBaseContent) {
1677
                $sessionCondition = api_get_session_condition(
1678
                    $session_id,
1679
                    true,
1680
                    true
1681
                );
1682
            } else {
1683
                $sessionCondition = api_get_session_condition(
1684
                    $session_id,
1685
                    true
1686
                );
1687
            }
1688
            $sql = 'SELECT * FROM '.$tbl_wiki.'
1689
                    WHERE c_id = '.$courseId.' '.$sessionCondition;
1690
        } else {
1691
            $tbl_wiki = Database::get_course_table(TABLE_WIKI);
1692
            $sql = 'SELECT * FROM '.$tbl_wiki.'
1693
                    WHERE c_id = '.$courseId.' AND (session_id = 0 OR session_id IS NULL)';
1694
        }
1695
        $db_result = Database::query($sql);
1696
        while ($obj = Database::fetch_object($db_result)) {
1697
            $wiki = new Wiki(
1698
                $obj->id,
1699
                $obj->page_id,
1700
                $obj->reflink,
1701
                $obj->title,
1702
                $obj->content,
1703
                $obj->user_id,
1704
                $obj->group_id,
1705
                $obj->dtime,
1706
                $obj->progress,
1707
                $obj->version
1708
            );
1709
            $this->course->add_resource($wiki);
1710
        }
1711
    }
1712
1713
    /**
1714
     * Build the Surveys.
1715
     *
1716
     * @param int   $session_id      Internal session ID
1717
     * @param int   $courseId        Internal course ID
1718
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1719
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1720
     */
1721
    public function build_thematic(
1722
        $session_id = 0,
1723
        $courseId = 0,
1724
        $withBaseContent = false,
1725
        $id_list = []
1726
    ) {
1727
        $table_thematic = Database::get_course_table(TABLE_THEMATIC);
1728
        $table_thematic_advance = Database::get_course_table(TABLE_THEMATIC_ADVANCE);
1729
        $table_thematic_plan = Database::get_course_table(TABLE_THEMATIC_PLAN);
1730
        $courseId = (int) $courseId;
1731
1732
        $courseInfo = api_get_course_info_by_id($courseId);
1733
        $session_id = (int) $session_id;
1734
        if ($withBaseContent) {
1735
            $sessionCondition = api_get_session_condition(
1736
                $session_id,
1737
                true,
1738
                true
1739
            );
1740
        } else {
1741
            $sessionCondition = api_get_session_condition($session_id, true);
1742
        }
1743
1744
        $sql = "SELECT * FROM $table_thematic
1745
                WHERE c_id = $courseId $sessionCondition ";
1746
        $db_result = Database::query($sql);
1747
        while ($row = Database::fetch_array($db_result, 'ASSOC')) {
1748
            $thematic = new Thematic($row);
1749
            $sql = 'SELECT * FROM '.$table_thematic_advance.'
1750
                    WHERE c_id = '.$courseId.' AND thematic_id = '.$row['id'];
1751
1752
            $result = Database::query($sql);
1753
            while ($sub_row = Database::fetch_array($result, 'ASSOC')) {
1754
                $thematic->addThematicAdvance($sub_row);
1755
            }
1756
1757
            $items = api_get_item_property_by_tool(
0 ignored issues
show
Bug introduced by
The function api_get_item_property_by_tool was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

1757
            $items = /** @scrutinizer ignore-call */ api_get_item_property_by_tool(
Loading history...
1758
                'thematic_plan',
1759
                $courseInfo['code'],
1760
                $session_id
1761
            );
1762
1763
            $thematic_plan_id_list = [];
1764
            if (!empty($items)) {
1765
                foreach ($items as $item) {
1766
                    $thematic_plan_id_list[] = $item['ref'];
1767
                }
1768
            }
1769
            if (count($thematic_plan_id_list) > 0) {
1770
                $sql = "SELECT tp.*
1771
                        FROM $table_thematic_plan tp
1772
                            INNER JOIN $table_thematic t ON (t.id=tp.thematic_id)
1773
                        WHERE
1774
                            t.c_id = $courseId AND
1775
                            tp.c_id = $courseId AND
1776
                            thematic_id = {$row['id']}  AND
1777
                            tp.id IN (".implode(', ', $thematic_plan_id_list).') ';
1778
1779
                $result = Database::query($sql);
1780
                while ($sub_row = Database::fetch_array($result, 'ASSOC')) {
1781
                    $thematic->addThematicPlan($sub_row);
1782
                }
1783
            }
1784
            $this->course->add_resource($thematic);
1785
        }
1786
    }
1787
1788
    /**
1789
     * Build the attendances.
1790
     *
1791
     * @param int   $session_id      Internal session ID
1792
     * @param int   $courseId        Internal course ID
1793
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1794
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1795
     */
1796
    public function build_attendance(
1797
        $session_id = 0,
1798
        $courseId = 0,
1799
        $withBaseContent = false,
1800
        $id_list = []
1801
    ) {
1802
        $table_attendance = Database::get_course_table(TABLE_ATTENDANCE);
1803
        $table_attendance_calendar = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
1804
        $sessionCondition = api_get_session_condition($session_id, true, $withBaseContent);
1805
        $courseId = (int) $courseId;
1806
1807
        $sql = 'SELECT * FROM '.$table_attendance.'
1808
                WHERE c_id = '.$courseId.' '.$sessionCondition;
1809
        $db_result = Database::query($sql);
1810
        while ($row = Database::fetch_array($db_result, 'ASSOC')) {
1811
            $obj = new Attendance($row);
1812
            $sql = 'SELECT * FROM '.$table_attendance_calendar.'
1813
                    WHERE c_id = '.$courseId.' AND attendance_id = '.$row['id'];
1814
1815
            $result = Database::query($sql);
1816
            while ($sub_row = Database::fetch_array($result, 'ASSOC')) {
1817
                $obj->add_attendance_calendar($sub_row);
1818
            }
1819
            $this->course->add_resource($obj);
1820
        }
1821
    }
1822
1823
    /**
1824
     * Build the works (or "student publications", or "assignments").
1825
     *
1826
     * @param int   $session_id      Internal session ID
1827
     * @param int   $courseId        Internal course ID
1828
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1829
     * @param array $idList          If you want to restrict the structure to only the given IDs
1830
     */
1831
    public function build_works(
1832
        $session_id = 0,
1833
        $courseId = 0,
1834
        $withBaseContent = false,
1835
        $idList = []
1836
    ) {
1837
        $table_work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1838
        $sessionCondition = api_get_session_condition(
1839
            $session_id,
1840
            true,
1841
            $withBaseContent
1842
        );
1843
        $courseId = (int) $courseId;
1844
1845
        $idCondition = '';
1846
        if (!empty($idList)) {
1847
            $idList = array_map('intval', $idList);
1848
            $idCondition = ' AND iid IN ("'.implode('","', $idList).'") ';
1849
        }
1850
1851
        $sql = "SELECT * FROM $table_work
1852
                WHERE
1853
                    c_id = $courseId
1854
                    $sessionCondition AND
1855
                    filetype = 'folder' AND
1856
                    parent_id = 0 AND
1857
                    active = 1
1858
                    $idCondition
1859
                ";
1860
        $result = Database::query($sql);
1861
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1862
            $obj = new Work($row);
1863
            $this->course->add_resource($obj);
1864
        }
1865
    }
1866
1867
    /**
1868
     * @param int  $session_id
1869
     * @param int  $courseId
1870
     * @param bool $withBaseContent
1871
     */
1872
    public function build_gradebook(
1873
        $session_id = 0,
1874
        $courseId = 0,
1875
        $withBaseContent = false
1876
    ) {
1877
        $courseInfo = api_get_course_info_by_id($courseId);
1878
        $courseCode = $courseInfo['code'];
1879
        $cats = Category:: load(
1880
            null,
1881
            null,
1882
            $courseCode,
1883
            null,
1884
            null,
1885
            $session_id
1886
        );
1887
1888
        if (!empty($cats)) {
1889
            /** @var Category $cat */
1890
            foreach ($cats as $cat) {
1891
                $cat->evaluations = $cat->get_evaluations(null, false);
1892
                $cat->links = $cat->get_links(null, false);
1893
                $cat->subCategories = $cat->get_subcategories(
1894
                    null,
1895
                    $courseCode,
1896
                    $session_id
1897
                );
1898
            }
1899
            $obj = new GradeBookBackup($cats);
1900
            $this->course->add_resource($obj);
1901
        }
1902
    }
1903
}
1904