CourseBuilder   F
last analyzed

Complexity

Total Complexity 229

Size/Duplication

Total Lines 2156
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 229
eloc 1197
c 0
b 0
f 0
dl 0
loc 2156
rs 0.812

37 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 15 2
B build_glossary() 0 53 9
A build_forums() 0 26 3
A build_forum_category() 0 29 3
A set_tools_to_build() 0 3 1
A build_forum_posts() 0 25 5
F build_learnpaths() 0 162 19
F exportToCourseBuildFormat() 0 161 32
C build_documents() 0 125 11
A build_learnpath_category() 0 14 4
B build_quizzes() 0 78 9
B restoreDocumentsFromList() 0 34 9
F build_quiz_questions() 0 187 18
A build_events() 0 49 3
A build_forum_topics() 0 30 3
A get_course() 0 3 1
A addDocumentList() 0 5 3
A build_tool_intro() 0 23 2
A build_course_descriptions() 0 40 5
A build_announcements() 0 53 4
B build_survey_questions() 0 41 7
A set_tools_specific_id_list() 0 3 1
F build() 0 110 22
A build_test_category() 0 18 2
A findAndSetDocumentsInText() 0 4 1
A build_wiki() 0 45 5
A build_link_category() 0 15 3
A build_surveys() 0 54 4
A build_session_course() 0 31 3
A build_quiz_orphan_questions() 0 64 4
A build_xapi_tool() 0 33 5
A build_links() 0 45 5
A build_works() 0 34 3
B build_thematic() 0 64 8
A build_gradebook() 0 29 3
A build_attendance() 0 24 3
A buildH5pTool() 0 25 4

How to fix   Complexity   

Complex Class

Complex classes like CourseBuilder often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CourseBuilder, and based on these observations, apply Extract Interface, too.

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
namespace Chamilo\CourseBundle\Component\CourseCopy;
5
6
use Category;
7
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Announcement;
8
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Asset;
9
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Attendance;
10
use Chamilo\CourseBundle\Component\CourseCopy\Resources\CalendarEvent;
11
use Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyLearnpath;
12
use Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyTestCategory;
13
use Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseDescription;
14
use Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseSession;
15
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Document;
16
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Forum;
17
use Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumCategory;
18
use Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumPost;
19
use Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumTopic;
20
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Glossary;
21
use Chamilo\CourseBundle\Component\CourseCopy\Resources\GradeBookBackup;
22
use Chamilo\CourseBundle\Component\CourseCopy\Resources\H5pTool;
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\Component\CourseCopy\Resources\XapiTool;
37
use Chamilo\CourseBundle\Entity\CLpCategory;
38
use CourseManager;
39
use Database;
40
use Link as LinkManager;
41
use TestCategory;
42
43
/**
44
 * Class CourseBuilder
45
 * Builds a course-object from a Chamilo-course.
46
 *
47
 * @author Bart Mollet <[email protected]>
48
 *
49
 * @package chamilo.backup
50
 */
51
class CourseBuilder
52
{
53
    /** @var Course */
54
    public $course;
55
56
    /* With this array you can filter the tools you want to be parsed by
57
    default all tools are included */
58
    public $tools_to_build = [
59
        'announcements',
60
        'attendance',
61
        'course_descriptions',
62
        'documents',
63
        'events',
64
        'forum_category',
65
        'forums',
66
        'forum_topics',
67
        'glossary',
68
        'quizzes',
69
        'test_category',
70
        'learnpath_category',
71
        'learnpaths',
72
        'links',
73
        'surveys',
74
        'tool_intro',
75
        'thematic',
76
        'wiki',
77
        'works',
78
        'gradebook',
79
    ];
80
81
    public $toolToName = [
82
        'announcements' => RESOURCE_ANNOUNCEMENT,
83
        'attendance' => RESOURCE_ATTENDANCE,
84
        'course_descriptions' => RESOURCE_COURSEDESCRIPTION,
85
        'documents' => RESOURCE_DOCUMENT,
86
        'events' => RESOURCE_EVENT,
87
        'forum_category' => RESOURCE_FORUMCATEGORY,
88
        'forums' => RESOURCE_FORUM,
89
        'forum_topics' => RESOURCE_FORUMTOPIC,
90
        'glossary' => RESOURCE_GLOSSARY,
91
        'quizzes' => RESOURCE_QUIZ,
92
        'test_category' => RESOURCE_TEST_CATEGORY,
93
        'learnpath_category' => RESOURCE_LEARNPATH_CATEGORY,
94
        'learnpaths' => RESOURCE_LEARNPATH,
95
        'links' => RESOURCE_LINK,
96
        'surveys' => RESOURCE_SURVEY,
97
        'tool_intro' => RESOURCE_TOOL_INTRO,
98
        'thematic' => RESOURCE_THEMATIC,
99
        'wiki' => RESOURCE_WIKI,
100
        'works' => RESOURCE_WORK,
101
        'gradebook' => RESOURCE_GRADEBOOK,
102
    ];
103
104
    /* With this array you can filter wich elements of the tools are going
105
    to be added in the course obj (only works with LPs) */
106
    public $specific_id_list = [];
107
    public $documentsAddedInText = [];
108
    public $itemListToAdd = [];
109
110
    public $isXapiEnabled = false;
111
    public $isH5pEnabled = false;
112
113
    /**
114
     * Create a new CourseBuilder.
115
     *
116
     * @param string $type
117
     * @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...
118
     */
119
    public function __construct($type = '', $course = null)
120
    {
121
        $_course = api_get_course_info();
122
123
        if (!empty($course['official_code'])) {
124
            $_course = $course;
125
        }
126
127
        $this->course = new Course();
128
        $this->course->code = $_course['code'];
129
        $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...
130
        $this->course->path = api_get_path(SYS_COURSE_PATH).$_course['path'].'/';
131
        $this->course->backup_path = api_get_path(SYS_COURSE_PATH).$_course['path'];
132
        $this->course->encoding = api_get_system_encoding();
133
        $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...
134
    }
135
136
    /**
137
     * @param array $list
138
     */
139
    public function addDocumentList($list)
140
    {
141
        foreach ($list as $item) {
142
            if (!in_array($item[0], $this->documentsAddedInText)) {
143
                $this->documentsAddedInText[$item[0]] = $item;
144
            }
145
        }
146
    }
147
148
    /**
149
     * @param string $text
150
     */
151
    public function findAndSetDocumentsInText($text)
152
    {
153
        $documentList = \DocumentManager::get_resources_from_source_html($text);
154
        $this->addDocumentList($documentList);
155
    }
156
157
    /**
158
     * Parse documents added in the documentsAddedInText variable.
159
     */
160
    public function restoreDocumentsFromList()
161
    {
162
        if (!empty($this->documentsAddedInText)) {
163
            $list = [];
164
            $courseInfo = api_get_course_info();
165
            foreach ($this->documentsAddedInText as $item) {
166
                // Get information about source url
167
                $url = $item[0]; // url
168
                $scope = $item[1]; // scope (local, remote)
169
                $type = $item[2]; // type (rel, abs, url)
170
171
                $origParseUrl = parse_url($url);
172
                $realOrigPath = isset($origParseUrl['path']) ? $origParseUrl['path'] : null;
173
174
                if ($scope == 'local') {
175
                    if ($type == 'abs' || $type == 'rel') {
176
                        $documentFile = strstr($realOrigPath, 'document');
177
                        if (strpos($realOrigPath, $documentFile) !== false) {
178
                            $documentFile = str_replace('document', '', $documentFile);
179
                            $itemDocumentId = \DocumentManager::get_document_id($courseInfo, $documentFile);
180
                            // Document found! Add it to the list
181
                            if ($itemDocumentId) {
182
                                $list[] = $itemDocumentId;
183
                            }
184
                        }
185
                    }
186
                }
187
            }
188
189
            $this->build_documents(
190
                api_get_session_id(),
191
                api_get_course_int_id(),
192
                true,
193
                $list
194
            );
195
        }
196
    }
197
198
    /**
199
     * @param array $array
200
     */
201
    public function set_tools_to_build($array)
202
    {
203
        $this->tools_to_build = $array;
204
    }
205
206
    /**
207
     * @param array $array
208
     */
209
    public function set_tools_specific_id_list($array)
210
    {
211
        $this->specific_id_list = $array;
212
    }
213
214
    /**
215
     * Get the created course.
216
     *
217
     * @return course The course
218
     */
219
    public function get_course()
220
    {
221
        return $this->course;
222
    }
223
224
    /**
225
     * Build the course-object.
226
     *
227
     * @param int    $session_id
228
     * @param string $courseCode
229
     * @param bool   $withBaseContent   true if you want to get the elements that exists in the course and
230
     *                                  in the session, (session_id = 0 or session_id = X)
231
     * @param array  $parseOnlyToolList
232
     * @param array  $toolsFromPost
233
     *
234
     * @return Course The course object structure
235
     */
236
    public function build(
237
        $session_id = 0,
238
        $courseCode = '',
239
        $withBaseContent = false,
240
        $parseOnlyToolList = [],
241
        $toolsFromPost = []
242
    ) {
243
        $course = api_get_course_info($courseCode);
244
        $courseId = $course['real_id'];
245
246
        $xapiEnabled = \XApiPlugin::create()->isEnabled();
247
        if ($xapiEnabled) {
248
            $this->tools_to_build[] = 'xapi_tool';
249
            $this->toolToName['xapi_tool'] = RESOURCE_XAPI_TOOL;
250
            $this->isXapiEnabled = $xapiEnabled;
251
        }
252
253
        $h5pEnabled = false; // \H5pImportPlugin::create()->isEnabled();
254
        if ($h5pEnabled) {
255
            $this->tools_to_build[] = 'h5p_tool';
256
            $this->toolToName['h5p_tool'] = RESOURCE_H5P_TOOL;
257
            $this->isH5pEnabled = $h5pEnabled;
258
        }
259
260
        foreach ($this->tools_to_build as $tool) {
261
            if (!empty($parseOnlyToolList) && !in_array($this->toolToName[$tool], $parseOnlyToolList)) {
262
                continue;
263
            }
264
            $function_build = 'build_'.$tool;
265
            $specificIdList = isset($this->specific_id_list[$tool]) ? $this->specific_id_list[$tool] : null;
266
            $buildOrphanQuestions = true;
267
            if ($tool === 'quizzes') {
268
                if (!empty($toolsFromPost['quiz'])) {
269
                    $specificIdList = array_keys($toolsFromPost['quiz']);
270
                }
271
                if (!isset($toolsFromPost[RESOURCE_QUIZ][-1])) {
272
                    $buildOrphanQuestions = false;
273
                }
274
275
                // Force orphan load
276
                if ($this->course->type === 'complete') {
0 ignored issues
show
Bug introduced by
The property type does not seem to exist on Chamilo\CourseBundle\Component\CourseCopy\Course.
Loading history...
277
                    $buildOrphanQuestions = true;
278
                }
279
280
                $this->build_quizzes(
281
                    $session_id,
282
                    $courseId,
283
                    $withBaseContent,
284
                    $specificIdList,
285
                    $buildOrphanQuestions
286
                );
287
            } else {
288
                if (!empty($toolsFromPost[RESOURCE_LEARNPATH]) && 'learnpaths' === $tool) {
289
                    $specificIdList = array_keys($toolsFromPost[RESOURCE_LEARNPATH]);
290
                }
291
                $this->$function_build(
292
                    $session_id,
293
                    $courseId,
294
                    $withBaseContent,
295
                    $specificIdList
296
                );
297
            }
298
        }
299
300
        // Add asset
301
        if ($course['course_image_source'] && basename($course['course_image_source']) !== 'course.png') {
302
            // Add course image courses/XXX/course-pic85x85.png
303
            $asset = new Asset(
304
                $course['course_image_source'],
305
                basename($course['course_image_source']),
306
                basename($course['course_image_source'])
307
            );
308
            $this->course->add_resource($asset);
309
310
            $asset = new Asset(
311
                $course['course_image_large_source'],
312
                basename($course['course_image_large_source']),
313
                basename($course['course_image_large_source'])
314
            );
315
            $this->course->add_resource($asset);
316
        }
317
318
        // Once we've built the resources array a bit more, try to get items
319
        // from the item_property table and order them in the "resources" array
320
        $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
321
        foreach ($this->course->resources as $type => $resources) {
322
            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...
323
                continue;
324
            }
325
            foreach ($resources as $id => $resource) {
326
                if ($resource) {
327
                    $tool = $resource->get_tool();
328
                    if ($tool != null) {
329
                        $sql = "SELECT * FROM $table
330
                                WHERE
331
                                    c_id = $courseId AND
332
                                    tool = '".$tool."' AND
333
                                    ref = '".$resource->get_id()."'";
334
                        $res = Database::query($sql);
335
                        $properties = [];
336
                        while ($property = Database::fetch_array($res)) {
337
                            $properties[] = $property;
338
                        }
339
                        $this->course->resources[$type][$id]->item_properties = $properties;
340
                    }
341
                }
342
            }
343
        }
344
345
        return $this->course;
346
    }
347
348
    /**
349
     * Build the documents.
350
     *
351
     * @param int   $session_id
352
     * @param int   $courseId
353
     * @param bool  $withBaseContent
354
     * @param array $idList
355
     */
356
    public function build_documents(
357
        $session_id = 0,
358
        $courseId = 0,
359
        $withBaseContent = false,
360
        $idList = []
361
    ) {
362
        $table_doc = Database::get_course_table(TABLE_DOCUMENT);
363
        $table_prop = Database::get_course_table(TABLE_ITEM_PROPERTY);
364
365
        // Remove chat_files, shared_folder, exercises files
366
        $avoid_paths = "
367
                         path NOT LIKE '/shared_folder%' AND
368
                         path NOT LIKE '/chat_files%' AND
369
                         path NOT LIKE '/../exercises/%'
370
                         ";
371
        $documentCondition = '';
372
        if (!empty($idList)) {
373
            $idList = array_unique($idList);
374
            $idList = array_map('intval', $idList);
375
            $documentCondition = ' d.iid IN ("'.implode('","', $idList).'") AND ';
376
        }
377
378
        if (!empty($courseId) && !empty($session_id)) {
379
            $session_id = (int) $session_id;
380
            if ($withBaseContent) {
381
                $session_condition = api_get_session_condition(
382
                    $session_id,
383
                    true,
384
                    true,
385
                    'd.session_id'
386
                );
387
            } else {
388
                $session_condition = api_get_session_condition(
389
                    $session_id,
390
                    true,
391
                    false,
392
                    'd.session_id'
393
                );
394
            }
395
396
            if (!empty($this->course->type) && $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...
397
                $sql = "SELECT d.iid, d.path, d.comment, d.title, d.filetype, d.size
398
                        FROM $table_doc d
399
                        INNER JOIN $table_prop p
400
                        ON (p.ref = d.id AND d.c_id = p.c_id)
401
                        WHERE
402
                            d.c_id = $courseId AND
403
                            p.c_id = $courseId AND
404
                            tool = '".TOOL_DOCUMENT."' AND
405
                            $documentCondition
406
                            p.visibility != 2 AND
407
                            path NOT LIKE '/images/gallery%' AND
408
                            $avoid_paths
409
                            $session_condition
410
                        ORDER BY path";
411
            } else {
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
                            $avoid_paths AND
422
                            p.visibility != 2 $session_condition
423
                        ORDER BY path";
424
            }
425
426
            $db_result = Database::query($sql);
427
            while ($obj = Database::fetch_object($db_result)) {
428
                $doc = new Document(
429
                    $obj->iid,
430
                    $obj->path,
431
                    $obj->comment,
432
                    $obj->title,
433
                    $obj->filetype,
434
                    $obj->size
435
                );
436
                $this->course->add_resource($doc);
437
            }
438
        } else {
439
            if (!empty($this->course->type) && $this->course->type == 'partial') {
440
                $sql = "SELECT d.iid, d.path, d.comment, d.title, d.filetype, d.size
441
                        FROM $table_doc d
442
                        INNER JOIN $table_prop p
443
                        ON (p.ref = d.id AND d.c_id = p.c_id)
444
                        WHERE
445
                            d.c_id = $courseId AND
446
                            p.c_id = $courseId AND
447
                            tool = '".TOOL_DOCUMENT."' AND
448
                            $documentCondition
449
                            p.visibility != 2 AND
450
                            path NOT LIKE '/images/gallery%' AND
451
                            $avoid_paths AND
452
                            (d.session_id = 0 OR d.session_id IS NULL)
453
                        ORDER BY path";
454
            } else {
455
                $sql = "SELECT d.iid, d.path, d.comment, d.title, d.filetype, d.size
456
                        FROM $table_doc d
457
                        INNER JOIN $table_prop p
458
                        ON (p.ref = d.id AND d.c_id = p.c_id)
459
                        WHERE
460
                            d.c_id = $courseId AND
461
                            p.c_id = $courseId AND
462
                            tool = '".TOOL_DOCUMENT."' AND
463
                            $documentCondition
464
                            p.visibility != 2 AND
465
                            $avoid_paths AND
466
                            (d.session_id = 0 OR d.session_id IS NULL)
467
                        ORDER BY path";
468
            }
469
470
            $result = Database::query($sql);
471
            while ($obj = Database::fetch_object($result)) {
472
                $doc = new Document(
473
                    $obj->iid,
474
                    $obj->path,
475
                    $obj->comment,
476
                    $obj->title,
477
                    $obj->filetype,
478
                    $obj->size
479
                );
480
                $this->course->add_resource($doc);
481
            }
482
        }
483
    }
484
485
    /**
486
     * Build the forums.
487
     *
488
     * @param int   $session_id      Internal session ID
489
     * @param int   $courseId        Internal course ID
490
     * @param bool  $withBaseContent Whether to include content from the course without session or not
491
     * @param array $idList          If you want to restrict the structure to only the given IDs
492
     */
493
    public function build_forums(
494
        $session_id = 0,
495
        $courseId = 0,
496
        $withBaseContent = false,
497
        $idList = []
498
    ) {
499
        $table = Database::get_course_table(TABLE_FORUM);
500
        $sessionCondition = api_get_session_condition(
501
            $session_id,
502
            true,
503
            $withBaseContent
504
        );
505
506
        $idCondition = '';
507
        if (!empty($idList)) {
508
            $idList = array_unique($idList);
509
            $idList = array_map('intval', $idList);
510
            $idCondition = ' AND iid IN ("'.implode('","', $idList).'") ';
511
        }
512
513
        $sql = "SELECT * FROM $table WHERE c_id = $courseId $sessionCondition $idCondition";
514
        $sql .= " ORDER BY forum_title, forum_category";
515
        $db_result = Database::query($sql);
516
        while ($obj = Database::fetch_object($db_result)) {
517
            $forum = new Forum($obj);
518
            $this->course->add_resource($forum);
519
        }
520
    }
521
522
    /**
523
     * Build a forum-category.
524
     *
525
     * @param int   $session_id      Internal session ID
526
     * @param int   $courseId        Internal course ID
527
     * @param bool  $withBaseContent Whether to include content from the course without session or not
528
     * @param array $idList          If you want to restrict the structure to only the given IDs
529
     */
530
    public function build_forum_category(
531
        $session_id = 0,
532
        $courseId = 0,
533
        $withBaseContent = false,
534
        $idList = []
535
    ) {
536
        $table = Database::get_course_table(TABLE_FORUM_CATEGORY);
537
538
        $sessionCondition = api_get_session_condition(
539
            $session_id,
540
            true,
541
            $withBaseContent
542
        );
543
544
        $idCondition = '';
545
        if (!empty($idList)) {
546
            $idList = array_unique($idList);
547
            $idList = array_map('intval', $idList);
548
            $idCondition = ' AND iid IN ("'.implode('","', $idList).'") ';
549
        }
550
551
        $sql = "SELECT * FROM $table
552
                WHERE c_id = $courseId $sessionCondition $idCondition
553
                ORDER BY cat_title";
554
555
        $result = Database::query($sql);
556
        while ($obj = Database::fetch_object($result)) {
557
            $forumCategory = new ForumCategory($obj);
558
            $this->course->add_resource($forumCategory);
559
        }
560
    }
561
562
    /**
563
     * Build the forum-topics.
564
     *
565
     * @param int   $session_id      Internal session ID
566
     * @param int   $courseId        Internal course ID
567
     * @param bool  $withBaseContent Whether to include content from the course without session or not
568
     * @param array $idList          If you want to restrict the structure to only the given IDs
569
     */
570
    public function build_forum_topics(
571
        $session_id = 0,
572
        $courseId = 0,
573
        $withBaseContent = false,
574
        $idList = []
575
    ) {
576
        $table = Database::get_course_table(TABLE_FORUM_THREAD);
577
578
        $sessionCondition = api_get_session_condition(
579
            $session_id,
580
            true,
581
            $withBaseContent
582
        );
583
584
        $idCondition = '';
585
        if (!empty($idList)) {
586
            $idList = array_map('intval', $idList);
587
            $idCondition = ' AND iid IN ("'.implode('","', $idList).'") ';
588
        }
589
590
        $sql = "SELECT * FROM $table WHERE c_id = $courseId
591
                $sessionCondition
592
                $idCondition
593
                ORDER BY thread_title ";
594
        $result = Database::query($sql);
595
596
        while ($obj = Database::fetch_object($result)) {
597
            $forumTopic = new ForumTopic($obj);
598
            $this->course->add_resource($forumTopic);
599
            $this->build_forum_posts($courseId, $obj->thread_id, $obj->forum_id);
600
        }
601
    }
602
603
    /**
604
     * Build the forum-posts
605
     * TODO: All tree structure of posts should be built, attachments for example.
606
     *
607
     * @param int   $courseId  Internal course ID
608
     * @param int   $thread_id Internal thread ID
609
     * @param int   $forum_id  Internal forum ID
610
     * @param array $idList
611
     */
612
    public function build_forum_posts(
613
        $courseId = 0,
614
        $thread_id = null,
615
        $forum_id = null,
616
        $idList = []
617
    ) {
618
        $table = Database::get_course_table(TABLE_FORUM_POST);
619
        $courseId = (int) $courseId;
620
        $sql = "SELECT * FROM $table WHERE c_id = $courseId ";
621
        if (!empty($thread_id) && !empty($forum_id)) {
622
            $forum_id = intval($forum_id);
623
            $thread_id = intval($thread_id);
624
            $sql .= " AND thread_id = $thread_id AND forum_id = $forum_id ";
625
        }
626
627
        if (!empty($idList)) {
628
            $idList = array_map('intval', $idList);
629
            $sql .= ' AND iid IN ("'.implode('","', $idList).'") ';
630
        }
631
632
        $sql .= " ORDER BY post_id ASC LIMIT 1";
633
        $db_result = Database::query($sql);
634
        while ($obj = Database::fetch_object($db_result)) {
635
            $forum_post = new ForumPost($obj);
636
            $this->course->add_resource($forum_post);
637
        }
638
    }
639
640
    /**
641
     * Build the links.
642
     *
643
     * @param int   $session_id      Internal session ID
644
     * @param int   $courseId        Internal course ID
645
     * @param bool  $withBaseContent Whether to include content from the course without session or not
646
     * @param array $idList          If you want to restrict the structure to only the given IDs
647
     */
648
    public function build_links(
649
        $session_id = 0,
650
        $courseId = 0,
651
        $withBaseContent = false,
652
        $idList = []
653
    ) {
654
        $categories = LinkManager::getLinkCategories(
655
            $courseId,
656
            $session_id,
657
            $withBaseContent
658
        );
659
660
        // Adding empty category
661
        $categories[] = ['id' => 0];
662
663
        foreach ($categories as $category) {
664
            $this->build_link_category($category);
665
666
            $links = LinkManager::getLinksPerCategory(
667
                $category['id'],
668
                $courseId,
669
                $session_id,
670
                $withBaseContent
671
            );
672
673
            foreach ($links as $item) {
674
                if (!empty($idList)) {
675
                    if (!in_array($item['id'], $idList)) {
676
                        continue;
677
                    }
678
                }
679
680
                $link = new Link(
681
                    $item['id'],
682
                    $item['title'],
683
                    $item['url'],
684
                    $item['description'],
685
                    $item['category_id'],
686
                    $item['on_homepage']
687
                );
688
                $link->target = $item['target'];
689
                $this->course->add_resource($link);
690
                $this->course->resources[RESOURCE_LINK][$item['id']]->add_linked_resource(
691
                    RESOURCE_LINKCATEGORY,
692
                    $item['category_id']
693
                );
694
            }
695
        }
696
    }
697
698
    /**
699
     * Build tool intro.
700
     *
701
     * @param int   $session_id      Internal session ID
702
     * @param int   $courseId        Internal course ID
703
     * @param bool  $withBaseContent Whether to include content from the course without session or not
704
     * @param array $idList          If you want to restrict the structure to only the given IDs
705
     */
706
    public function build_tool_intro(
707
        $session_id = 0,
708
        $courseId = 0,
709
        $withBaseContent = false,
710
        $idList = []
711
    ) {
712
        $table = Database::get_course_table(TABLE_TOOL_INTRO);
713
714
        $sessionCondition = api_get_session_condition(
715
            $session_id,
716
            true,
717
            $withBaseContent
718
        );
719
720
        $courseId = (int) $courseId;
721
722
        $sql = "SELECT * FROM $table
723
                WHERE c_id = $courseId $sessionCondition";
724
725
        $db_result = Database::query($sql);
726
        while ($obj = Database::fetch_object($db_result)) {
727
            $tool_intro = new ToolIntro($obj->id, $obj->intro_text);
728
            $this->course->add_resource($tool_intro);
729
        }
730
    }
731
732
    /**
733
     * Build a link category.
734
     *
735
     * @return int
736
     */
737
    public function build_link_category($category)
738
    {
739
        if (empty($category) || empty($category['category_title'])) {
740
            return 0;
741
        }
742
743
        $linkCategory = new LinkCategory(
744
            $category['id'],
745
            $category['category_title'],
746
            $category['description'],
747
            $category['display_order']
748
        );
749
        $this->course->add_resource($linkCategory);
750
751
        return $category['id'];
752
    }
753
754
    /**
755
     * Build the Quizzes.
756
     *
757
     * @param int   $session_id           Internal session ID
758
     * @param int   $courseId             Internal course ID
759
     * @param bool  $withBaseContent      Whether to include content from the course without session or not
760
     * @param array $idList               If you want to restrict the structure to only the given IDs
761
     * @param bool  $buildOrphanQuestions
762
     */
763
    public function build_quizzes(
764
        $session_id = 0,
765
        $courseId = 0,
766
        $withBaseContent = false,
767
        $idList = [],
768
        $buildOrphanQuestions = true
769
    ) {
770
        $table_qui = Database::get_course_table(TABLE_QUIZ_TEST);
771
        $table_rel = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
772
        $table_doc = Database::get_course_table(TABLE_DOCUMENT);
773
774
        $courseId = (int) $courseId;
775
        $idCondition = '';
776
        if (!empty($idList)) {
777
            $idList = array_map('intval', $idList);
778
            $idCondition = ' iid IN ("'.implode('","', $idList).'") AND ';
779
        }
780
781
        if (!empty($courseId) && !empty($session_id)) {
782
            $session_id = (int) $session_id;
783
            if ($withBaseContent) {
784
                $sessionCondition = api_get_session_condition(
785
                    $session_id,
786
                    true,
787
                    true
788
                );
789
            } else {
790
                $sessionCondition = api_get_session_condition(
791
                    $session_id,
792
                    true
793
                );
794
            }
795
796
            // Select only quizzes with active = 0 or 1 (not -1 which is for deleted quizzes)
797
            $sql = "SELECT * FROM $table_qui
798
                    WHERE
799
                      c_id = $courseId AND
800
                      $idCondition
801
                      active >=0
802
                      $sessionCondition ";
803
        } else {
804
            // Select only quizzes with active = 0 or 1 (not -1 which is for deleted quizzes)
805
            $sql = "SELECT * FROM $table_qui
806
                    WHERE
807
                      c_id = $courseId AND
808
                      $idCondition
809
                      active >=0 AND
810
                      (session_id = 0 OR session_id IS NULL)";
811
        }
812
813
        $sql .= ' ORDER BY title';
814
        $db_result = Database::query($sql);
815
        $questionList = [];
816
        while ($obj = Database::fetch_object($db_result)) {
817
            if (strlen($obj->sound) > 0) {
818
                $sql = "SELECT iid FROM $table_doc
819
                        WHERE c_id = $courseId AND path = '/audio/".$obj->sound."'";
820
                $res = Database::query($sql);
821
                $doc = Database::fetch_object($res);
822
                $obj->sound = $doc->iid;
823
            }
824
            $this->findAndSetDocumentsInText($obj->description);
825
826
            $quiz = new Quiz($obj);
827
            $sql = "SELECT * FROM $table_rel
828
                WHERE c_id = $courseId AND exercice_id = {$obj->iid}";
829
            $db_result2 = Database::query($sql);
830
            while ($obj2 = Database::fetch_object($db_result2)) {
831
                $quiz->add_question($obj2->question_id, $obj2->question_order);
832
                $questionList[] = $obj2->question_id;
833
            }
834
            $this->course->add_resource($quiz);
835
        }
836
837
        if (!empty($courseId)) {
838
            $this->build_quiz_questions($courseId, $questionList, $buildOrphanQuestions);
839
        } else {
840
            $this->build_quiz_questions(0, $questionList, $buildOrphanQuestions);
841
        }
842
    }
843
844
    /**
845
     * Build the Quiz-Questions.
846
     *
847
     * @param int   $courseId             Internal course ID
848
     * @param array $questionList
849
     * @param bool  $buildOrphanQuestions
850
     */
851
    public function build_quiz_questions($courseId = 0, $questionList = [], $buildOrphanQuestions = true)
852
    {
853
        $table_qui = Database::get_course_table(TABLE_QUIZ_TEST);
854
        $table_rel = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
855
        $table_que = Database::get_course_table(TABLE_QUIZ_QUESTION);
856
        $table_ans = Database::get_course_table(TABLE_QUIZ_ANSWER);
857
        $courseId = (int) $courseId;
858
        $questionListToString = implode("','", $questionList);
859
860
        // Building normal tests (many queries)
861
        $sql = "SELECT * FROM $table_que
862
                WHERE iid IN ('$questionListToString')";
863
        $result = Database::query($sql);
864
865
        while ($obj = Database::fetch_object($result)) {
866
            // find the question category
867
            // @todo : need to be adapted for multi category questions in 1.10
868
            $question_category_id = TestCategory::getCategoryForQuestion(
869
                $obj->iid,
870
                $courseId
871
            );
872
873
            $this->findAndSetDocumentsInText($obj->description);
874
            // It searches images from hotspot to build
875
            if (HOT_SPOT == $obj->type) {
876
                if (is_numeric($obj->picture)) {
877
                    $itemDocumentId = (int) $obj->picture;
878
                    $document = \DocumentManager::get_document_data_by_id($itemDocumentId, api_get_course_id());
879
                    if (file_exists($document['absolute_path'])) {
880
                        $directUrl = $document['direct_url'];
881
                        $path = str_replace(api_get_path(WEB_PATH), '/', $directUrl);
882
                        $this->documentsAddedInText[] = [
883
                            0 => $path,
884
                            1 => 'local',
885
                            2 => 'rel',
886
                        ];
887
                    }
888
                }
889
            }
890
891
            // build the backup resource question object
892
            $question = new QuizQuestion(
893
                $obj->iid,
894
                $obj->question,
895
                $obj->description,
896
                $obj->ponderation,
897
                $obj->type,
898
                $obj->position,
899
                $obj->picture,
900
                $obj->level,
901
                $obj->extra,
902
                $question_category_id
903
            );
904
            $question->addPicture($this);
905
906
            $sql = "SELECT * FROM $table_ans
907
                WHERE question_id = {$obj->iid}";
908
            $db_result2 = Database::query($sql);
909
            while ($obj2 = Database::fetch_object($db_result2)) {
910
                $question->add_answer(
911
                    $obj2->iid,
912
                    $obj2->answer,
913
                    $obj2->correct,
914
                    $obj2->comment,
915
                    $obj2->ponderation,
916
                    $obj2->position,
917
                    $obj2->hotspot_coordinates,
918
                    $obj2->hotspot_type
919
                );
920
921
                $this->findAndSetDocumentsInText($obj2->answer);
922
                $this->findAndSetDocumentsInText($obj2->comment);
923
924
                if ($obj->type == MULTIPLE_ANSWER_TRUE_FALSE) {
925
                    $table_options = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION);
926
                    $sql = "SELECT * FROM $table_options
927
                        WHERE question_id = {$obj->iid}";
928
                    $db_result3 = Database::query($sql);
929
                    while ($obj3 = Database::fetch_object($db_result3)) {
930
                        $question_option = new QuizQuestionOption($obj3);
931
                        $question->add_option($question_option);
932
                    }
933
                }
934
            }
935
            $this->course->add_resource($question);
936
        }
937
938
        // Check if a global setting has been set to avoid copying orphan questions
939
        if (true === api_get_configuration_value('quiz_discard_orphan_in_course_export')) {
940
            $buildOrphanQuestions = false;
941
        }
942
943
        if ($buildOrphanQuestions) {
944
            // Building a fictional test for collecting orphan questions.
945
            // When a course is emptied this option should be activated (true).
946
            //$build_orphan_questions = !empty($_POST['recycle_option']);
947
948
            // 1st union gets the orphan questions from deleted exercises
949
            // 2nd union gets the orphan questions from question that were deleted in a exercise.
950
            $sql = " (
951
                        SELECT question_id, q.* FROM $table_que q
952
                        INNER JOIN $table_rel r
953
                        ON q.iid = r.question_id
954
                        INNER JOIN $table_qui ex
955
                        ON (ex.iid = r.exercice_id AND ex.c_id = r.c_id)
956
                        WHERE ex.c_id = $courseId AND ex.active = '-1'
957
                    )
958
                    UNION
959
                     (
960
                        SELECT question_id, q.* FROM $table_que q
961
                        left OUTER JOIN $table_rel r
962
                        ON q.iid = r.question_id
963
                        WHERE q.c_id = $courseId AND r.question_id is null
964
                     )
965
                     UNION
966
                     (
967
                        SELECT question_id, q.* FROM $table_que q
968
                        INNER JOIN $table_rel r
969
                        ON q.iid = r.question_id
970
                        WHERE r.c_id = $courseId AND (r.exercice_id = '-1' OR r.exercice_id = '0')
971
                     )
972
                 ";
973
974
            $result = Database::query($sql);
975
            if (Database::num_rows($result) > 0) {
976
                $orphanQuestionIds = [];
977
                while ($obj = Database::fetch_object($result)) {
978
                    // Orphan questions
979
                    if (!empty($obj->question_id)) {
980
                        $obj->iid = $obj->question_id;
981
                    }
982
983
                    // Avoid adding the same question twice
984
                    if (!isset($this->course->resources[$obj->iid])) {
985
                        // find the question category
986
                        // @todo : need to be adapted for multi category questions in 1.10
987
                        $question_category_id = TestCategory::getCategoryForQuestion($obj->iid, $courseId);
988
                        $question = new QuizQuestion(
989
                            $obj->iid,
990
                            $obj->question,
991
                            $obj->description,
992
                            $obj->ponderation,
993
                            $obj->type,
994
                            $obj->position,
995
                            $obj->picture,
996
                            $obj->level,
997
                            $obj->extra,
998
                            $question_category_id
999
                        );
1000
                        $question->addPicture($this);
1001
                        $sql = "SELECT * FROM $table_ans
1002
                                WHERE question_id = {$obj->iid}";
1003
                        $db_result2 = Database::query($sql);
1004
                        if (Database::num_rows($db_result2)) {
1005
                            while ($obj2 = Database::fetch_object($db_result2)) {
1006
                                $question->add_answer(
1007
                                    $obj2->iid,
1008
                                    $obj2->answer,
1009
                                    $obj2->correct,
1010
                                    $obj2->comment,
1011
                                    $obj2->ponderation,
1012
                                    $obj2->position,
1013
                                    $obj2->hotspot_coordinates,
1014
                                    $obj2->hotspot_type
1015
                                );
1016
                            }
1017
                            $orphanQuestionIds[] = $obj->iid;
1018
                        }
1019
                        $this->course->add_resource($question);
1020
                    }
1021
                }
1022
            }
1023
        }
1024
1025
        $obj = [
1026
            'iid' => -1,
1027
            'title' => get_lang('OrphanQuestions'),
1028
            'type' => 2,
1029
        ];
1030
        $newQuiz = new Quiz((object) $obj);
1031
        if (!empty($orphanQuestionIds)) {
1032
            foreach ($orphanQuestionIds as $index => $orphanId) {
1033
                $order = $index + 1;
1034
                $newQuiz->add_question($orphanId, $order);
1035
            }
1036
        }
1037
        $this->course->add_resource($newQuiz);
1038
    }
1039
1040
    /**
1041
     * @deprecated
1042
     * Build the orphan questions
1043
     */
1044
    public function build_quiz_orphan_questions()
1045
    {
1046
        $table_qui = Database::get_course_table(TABLE_QUIZ_TEST);
1047
        $table_rel = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
1048
        $table_que = Database::get_course_table(TABLE_QUIZ_QUESTION);
1049
        $table_ans = Database::get_course_table(TABLE_QUIZ_ANSWER);
1050
1051
        $courseId = api_get_course_int_id();
1052
1053
        $sql = 'SELECT *
1054
                FROM '.$table_que.' as questions
1055
                LEFT JOIN '.$table_rel.' as quizz_questions
1056
                ON questions.iid=quizz_questions.question_id
1057
                LEFT JOIN '.$table_qui.' as exercises
1058
                ON quizz_questions.exercice_id = exercises.iid
1059
                WHERE
1060
                    exercises.c_id = '.$courseId.' AND
1061
                    (quizz_questions.exercice_id IS NULL OR
1062
                    exercises.active = -1)';
1063
1064
        $db_result = Database::query($sql);
1065
        if (Database::num_rows($db_result) > 0) {
1066
            // This is the fictional test for collecting orphan questions.
1067
            $orphan_questions = new Quiz(
1068
                -1,
1069
                get_lang('OrphanQuestions', ''),
1070
                '',
1071
                0,
1072
                0,
1073
                1,
1074
                '',
1075
                0
1076
            );
1077
1078
            $this->course->add_resource($orphan_questions);
1079
            while ($obj = Database::fetch_object($db_result)) {
1080
                $question = new QuizQuestion(
1081
                    $obj->iid,
1082
                    $obj->question,
1083
                    $obj->description,
1084
                    $obj->ponderation,
1085
                    $obj->type,
1086
                    $obj->position,
1087
                    $obj->picture,
1088
                    $obj->level,
1089
                    $obj->extra
1090
                );
1091
                $question->addPicture($this);
1092
1093
                $sql = 'SELECT * FROM '.$table_ans.' WHERE question_id = '.$obj->iid;
1094
                $db_result2 = Database::query($sql);
1095
                while ($obj2 = Database::fetch_object($db_result2)) {
1096
                    $question->add_answer(
1097
                        $obj2->iid,
1098
                        $obj2->answer,
1099
                        $obj2->correct,
1100
                        $obj2->comment,
1101
                        $obj2->ponderation,
1102
                        $obj2->position,
1103
                        $obj2->hotspot_coordinates,
1104
                        $obj2->hotspot_type
1105
                    );
1106
                }
1107
                $this->course->add_resource($question);
1108
            }
1109
        }
1110
    }
1111
1112
    /**
1113
     * Build the test category.
1114
     *
1115
     * @param int   $sessionId       Internal session ID
1116
     * @param int   $courseId        Internal course ID
1117
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1118
     * @param array $idList          If you want to restrict the structure to only the given IDs
1119
     *
1120
     * @todo add course session
1121
     */
1122
    public function build_test_category(
1123
        $sessionId = 0,
1124
        $courseId = 0,
1125
        $withBaseContent = false,
1126
        $idList = []
1127
    ) {
1128
        // get all test category in course
1129
        $categories = TestCategory::getCategoryListInfo('', $courseId);
1130
        foreach ($categories as $category) {
1131
            $this->findAndSetDocumentsInText($category->description);
1132
1133
            /** @var TestCategory $category */
1134
            $courseCopyTestCategory = new CourseCopyTestCategory(
1135
                $category->iid,
1136
                $category->name,
1137
                $category->description
1138
            );
1139
            $this->course->add_resource($courseCopyTestCategory);
1140
        }
1141
    }
1142
1143
    /**
1144
     * Build the Surveys.
1145
     *
1146
     * @param int   $session_id      Internal session ID
1147
     * @param int   $courseId        Internal course ID
1148
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1149
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1150
     */
1151
    public function build_surveys(
1152
        $session_id = 0,
1153
        $courseId = 0,
1154
        $withBaseContent = false,
1155
        $id_list = []
1156
    ) {
1157
        $table_survey = Database::get_course_table(TABLE_SURVEY);
1158
        $table_question = Database::get_course_table(TABLE_SURVEY_QUESTION);
1159
1160
        $courseId = (int) $courseId;
1161
1162
        $sessionCondition = api_get_session_condition(
1163
            $session_id,
1164
            true,
1165
            $withBaseContent
1166
        );
1167
1168
        $sql = 'SELECT * FROM '.$table_survey.'
1169
                WHERE c_id = '.$courseId.' '.$sessionCondition;
1170
        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...
1171
            $sql .= " AND iid IN (".implode(', ', $id_list).")";
1172
        }
1173
        $db_result = Database::query($sql);
1174
        while ($obj = Database::fetch_object($db_result)) {
1175
            $survey = new Survey(
1176
                $obj->survey_id,
1177
                $obj->code,
1178
                $obj->title,
1179
                $obj->subtitle,
1180
                $obj->author,
1181
                $obj->lang,
1182
                $obj->avail_from,
1183
                $obj->avail_till,
1184
                $obj->is_shared,
1185
                $obj->template,
1186
                $obj->intro,
1187
                $obj->surveythanks,
1188
                $obj->creation_date,
1189
                $obj->invited,
1190
                $obj->answered,
1191
                $obj->invite_mail,
1192
                $obj->reminder_mail,
1193
                $obj->one_question_per_page,
1194
                $obj->shuffle
1195
            );
1196
            $sql = 'SELECT * FROM '.$table_question.'
1197
                    WHERE c_id = '.$courseId.' AND survey_id = '.$obj->survey_id;
1198
            $db_result2 = Database::query($sql);
1199
            while ($obj2 = Database::fetch_object($db_result2)) {
1200
                $survey->add_question($obj2->question_id);
1201
            }
1202
            $this->course->add_resource($survey);
1203
        }
1204
        $this->build_survey_questions($courseId);
1205
    }
1206
1207
    /**
1208
     * Build the Survey Questions.
1209
     *
1210
     * @param int $courseId Internal course ID
1211
     */
1212
    public function build_survey_questions($courseId)
1213
    {
1214
        $table_que = Database::get_course_table(TABLE_SURVEY_QUESTION);
1215
        $table_opt = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
1216
1217
        $courseId = (int) $courseId;
1218
        $idList = isset($this->specific_id_list['surveys']) ? $this->specific_id_list['surveys'] : [];
1219
1220
        $sql = 'SELECT * FROM '.$table_que.' WHERE c_id = '.$courseId.'  ';
1221
1222
        if (!empty($idList)) {
1223
            $sql .= " AND survey_id IN (".implode(', ', $idList).")";
1224
        }
1225
1226
        $db_result = Database::query($sql);
1227
        $is_required = 0;
1228
        while ($obj = Database::fetch_object($db_result)) {
1229
            if (api_get_configuration_value('allow_required_survey_questions')) {
1230
                if (isset($obj->is_required)) {
1231
                    $is_required = $obj->is_required;
1232
                }
1233
            }
1234
            $question = new SurveyQuestion(
1235
                $obj->question_id,
1236
                $obj->survey_id,
1237
                $obj->survey_question,
1238
                $obj->survey_question_comment,
1239
                $obj->type,
1240
                $obj->display,
1241
                $obj->sort,
1242
                $obj->shared_question_id,
1243
                $obj->max_value,
1244
                $is_required
1245
            );
1246
            $sql = 'SELECT * FROM '.$table_opt.'
1247
                    WHERE c_id = '.$courseId.' AND question_id = '.$obj->question_id;
1248
            $db_result2 = Database::query($sql);
1249
            while ($obj2 = Database::fetch_object($db_result2)) {
1250
                $question->add_answer($obj2->option_text, $obj2->sort);
1251
            }
1252
            $this->course->add_resource($question);
1253
        }
1254
    }
1255
1256
    /**
1257
     * Build the announcements.
1258
     *
1259
     * @param int   $session_id      Internal session ID
1260
     * @param int   $courseId        Internal course ID
1261
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1262
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1263
     */
1264
    public function build_announcements(
1265
        $session_id = 0,
1266
        $courseId = 0,
1267
        $withBaseContent = false,
1268
        $id_list = []
1269
    ) {
1270
        $table = Database::get_course_table(TABLE_ANNOUNCEMENT);
1271
1272
        $sessionCondition = api_get_session_condition(
1273
            $session_id,
1274
            true,
1275
            $withBaseContent
1276
        );
1277
1278
        $courseId = (int) $courseId;
1279
1280
        $sql = 'SELECT * FROM '.$table.'
1281
                WHERE c_id = '.$courseId.' '.$sessionCondition;
1282
        $db_result = Database::query($sql);
1283
        $table_attachment = Database::get_course_table(
1284
            TABLE_ANNOUNCEMENT_ATTACHMENT
1285
        );
1286
        while ($obj = Database::fetch_object($db_result)) {
1287
            if (empty($obj->id)) {
1288
                continue;
1289
            }
1290
            $sql = 'SELECT path, comment, filename, size
1291
                    FROM '.$table_attachment.'
1292
                    WHERE c_id = '.$courseId.' AND announcement_id = '.$obj->id.'';
1293
            $result = Database::query($sql);
1294
            $attachment_obj = Database::fetch_object($result);
1295
            $att_path = $att_filename = $att_size = $atth_comment = '';
1296
1297
            if (!empty($attachment_obj)) {
1298
                $att_path = $attachment_obj->path;
1299
                $att_filename = $attachment_obj->filename;
1300
                $att_size = $attachment_obj->size;
1301
                $atth_comment = $attachment_obj->comment;
1302
            }
1303
1304
            $announcement = new Announcement(
1305
                $obj->id,
1306
                $obj->title,
1307
                $obj->content,
1308
                $obj->end_date,
1309
                $obj->display_order,
1310
                $obj->email_sent,
1311
                $att_path,
1312
                $att_filename,
1313
                $att_size,
1314
                $atth_comment
1315
            );
1316
            $this->course->add_resource($announcement);
1317
        }
1318
    }
1319
1320
    /**
1321
     * Build the events.
1322
     *
1323
     * @param int   $session_id      Internal session ID
1324
     * @param int   $courseId        Internal course ID
1325
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1326
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1327
     */
1328
    public function build_events(
1329
        $session_id = 0,
1330
        $courseId = 0,
1331
        $withBaseContent = false,
1332
        $id_list = []
1333
    ) {
1334
        $table = Database::get_course_table(TABLE_AGENDA);
1335
1336
        $sessionCondition = api_get_session_condition(
1337
            $session_id,
1338
            true,
1339
            $withBaseContent
1340
        );
1341
1342
        $courseId = (int) $courseId;
1343
1344
        $sql = 'SELECT * FROM '.$table.'
1345
                WHERE c_id = '.$courseId.' '.$sessionCondition;
1346
        $db_result = Database::query($sql);
1347
        while ($obj = Database::fetch_object($db_result)) {
1348
            $table_attachment = Database::get_course_table(
1349
                TABLE_AGENDA_ATTACHMENT
1350
            );
1351
            $sql = 'SELECT path, comment, filename, size
1352
                    FROM '.$table_attachment.'
1353
                    WHERE c_id = '.$courseId.' AND agenda_id = '.$obj->id.'';
1354
            $result = Database::query($sql);
1355
1356
            $attachment_obj = Database::fetch_object($result);
1357
            $att_path = $att_filename = $att_size = $atth_comment = '';
1358
            if (!empty($attachment_obj)) {
1359
                $att_path = $attachment_obj->path;
1360
                $att_filename = $attachment_obj->filename;
1361
                $att_size = $attachment_obj->size;
1362
                $atth_comment = $attachment_obj->comment;
1363
            }
1364
            $event = new CalendarEvent(
1365
                $obj->id,
1366
                $obj->title,
1367
                $obj->content,
1368
                $obj->start_date,
1369
                $obj->end_date,
1370
                $att_path,
1371
                $att_filename,
1372
                $att_size,
1373
                $atth_comment,
1374
                $obj->all_day
1375
            );
1376
            $this->course->add_resource($event);
1377
        }
1378
    }
1379
1380
    /**
1381
     * Build the course-descriptions.
1382
     *
1383
     * @param int   $session_id      Internal session ID
1384
     * @param int   $courseId        Internal course ID
1385
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1386
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1387
     */
1388
    public function build_course_descriptions(
1389
        $session_id = 0,
1390
        $courseId = 0,
1391
        $withBaseContent = false,
1392
        $id_list = []
1393
    ) {
1394
        $table = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
1395
        $courseId = (int) $courseId;
1396
1397
        if (!empty($session_id) && !empty($courseId)) {
1398
            $session_id = intval($session_id);
1399
            if ($withBaseContent) {
1400
                $sessionCondition = api_get_session_condition(
1401
                    $session_id,
1402
                    true,
1403
                    true
1404
                );
1405
            } else {
1406
                $sessionCondition = api_get_session_condition(
1407
                    $session_id,
1408
                    true
1409
                );
1410
            }
1411
            $sql = 'SELECT * FROM '.$table.'
1412
                    WHERE c_id = '.$courseId.' '.$sessionCondition;
1413
        } else {
1414
            $table = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
1415
            $sql = 'SELECT * FROM '.$table.'
1416
                    WHERE c_id = '.$courseId.'  AND session_id = 0';
1417
        }
1418
1419
        $db_result = Database::query($sql);
1420
        while ($obj = Database::fetch_object($db_result)) {
1421
            $cd = new CourseDescription(
1422
                $obj->id,
1423
                $obj->title,
1424
                $obj->content,
1425
                $obj->description_type
1426
            );
1427
            $this->course->add_resource($cd);
1428
        }
1429
    }
1430
1431
    /**
1432
     * @param int   $session_id
1433
     * @param int   $courseId
1434
     * @param bool  $withBaseContent
1435
     * @param array $idList
1436
     */
1437
    public function build_learnpath_category($session_id = 0, $courseId = 0, $withBaseContent = false, $idList = [])
1438
    {
1439
        $categories = \learnpath::getCategories($courseId);
1440
1441
        /** @var CLpCategory $item */
1442
        foreach ($categories as $item) {
1443
            $categoryId = $item->getId();
1444
            if (!empty($idList)) {
1445
                if (!in_array($categoryId, $idList)) {
1446
                    continue;
1447
                }
1448
            }
1449
            $category = new LearnPathCategory($categoryId, $item);
1450
            $this->course->add_resource($category);
1451
        }
1452
    }
1453
1454
    /**
1455
     * Build the learnpaths.
1456
     *
1457
     * @param int   $session_id      Internal session ID
1458
     * @param int   $courseId        Internal course ID
1459
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1460
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1461
     * @param bool  $addScormFolder
1462
     */
1463
    public function build_learnpaths(
1464
        $session_id = 0,
1465
        $courseId = 0,
1466
        $withBaseContent = false,
1467
        $id_list = [],
1468
        $addScormFolder = true
1469
    ) {
1470
        $lpTable = Database::get_course_table(TABLE_LP_MAIN);
1471
        $table_item = Database::get_course_table(TABLE_LP_ITEM);
1472
        $table_tool = Database::get_course_table(TABLE_TOOL_LIST);
1473
1474
        $courseId = (int) $courseId;
1475
1476
        if (!empty($session_id) && !empty($courseId)) {
1477
            $session_id = (int) $session_id;
1478
            if ($withBaseContent) {
1479
                $sessionCondition = api_get_session_condition(
1480
                    $session_id,
1481
                    true,
1482
                    true
1483
                );
1484
            } else {
1485
                $sessionCondition = api_get_session_condition(
1486
                    $session_id,
1487
                    true
1488
                );
1489
            }
1490
            $sql = 'SELECT * FROM '.$lpTable.'
1491
                    WHERE c_id = '.$courseId.'  '.$sessionCondition;
1492
        } else {
1493
            $sql = 'SELECT * FROM '.$lpTable.'
1494
                    WHERE c_id = '.$courseId.' AND (session_id = 0 OR session_id IS NULL)';
1495
        }
1496
1497
        if (!empty($id_list)) {
1498
            $id_list = array_map('intval', $id_list);
1499
            $sql .= " AND id IN (".implode(', ', $id_list).") ";
1500
        }
1501
1502
        $result = Database::query($sql);
1503
        if ($result) {
0 ignored issues
show
introduced by
$result is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
1504
            while ($obj = Database::fetch_object($result)) {
1505
                $items = [];
1506
                $sql = "SELECT * FROM $table_item
1507
                        WHERE c_id = '$courseId' AND lp_id = ".$obj->id;
1508
                $resultItem = Database::query($sql);
1509
                while ($obj_item = Database::fetch_object($resultItem)) {
1510
                    $item['id'] = $obj_item->iid;
1511
                    $item['item_type'] = $obj_item->item_type;
1512
                    $item['ref'] = $obj_item->ref;
1513
                    $item['title'] = $obj_item->title;
1514
                    $item['description'] = $obj_item->description;
1515
                    $item['path'] = $obj_item->path;
1516
                    $item['min_score'] = $obj_item->min_score;
1517
                    $item['max_score'] = $obj_item->max_score;
1518
                    $item['mastery_score'] = $obj_item->mastery_score;
1519
                    $item['parent_item_id'] = $obj_item->parent_item_id;
1520
                    $item['previous_item_id'] = $obj_item->previous_item_id;
1521
                    $item['next_item_id'] = $obj_item->next_item_id;
1522
                    $item['display_order'] = $obj_item->display_order;
1523
                    $item['prerequisite'] = $obj_item->prerequisite;
1524
                    $item['prerequisite_min_score'] = $obj_item->prerequisite_min_score;
1525
                    $item['prerequisite_max_score'] = $obj_item->prerequisite_max_score;
1526
                    $item['parameters'] = $obj_item->parameters;
1527
                    $item['launch_data'] = $obj_item->launch_data;
1528
                    $item['audio'] = $obj_item->audio;
1529
                    $items[] = $item;
1530
                    $this->itemListToAdd[$obj_item->item_type][] = $obj_item->path;
1531
1532
                    if (!empty($obj_item->audio)) {
1533
                        $audioTitle = basename($obj_item->audio);
1534
                        // Add LP item audio
1535
                        $assetAudio = new Asset(
1536
                            $audioTitle,
1537
                            '/document'.$obj_item->audio,
1538
                            '/document'.$obj_item->audio
1539
                        );
1540
                        $this->course->add_resource($assetAudio);
1541
                    }
1542
                }
1543
1544
                $sql = "SELECT id FROM $table_tool
1545
                        WHERE
1546
                            c_id = $courseId AND
1547
                            (link LIKE '%lp_controller.php%lp_id=".$obj->id."%' AND image='scormbuilder.gif') AND
1548
                            visibility = '1' ";
1549
                $db_tool = Database::query($sql);
1550
                $visibility = '0';
1551
                if (Database::num_rows($db_tool)) {
1552
                    $visibility = '1';
1553
                }
1554
1555
                $accumulateWorkTime = 0;
1556
                if (api_get_configuration_value('lp_minimum_time')) {
1557
                    if (isset($obj->accumulate_work_time) && !empty($obj->accumulate_work_time)) {
1558
                        $accumulateWorkTime = $obj->accumulate_work_time;
1559
                    }
1560
                }
1561
1562
                $lp = new CourseCopyLearnpath(
1563
                    $obj->id,
1564
                    $obj->lp_type,
1565
                    $obj->name,
1566
                    $obj->path,
1567
                    $obj->ref,
1568
                    $obj->description,
1569
                    $obj->content_local,
1570
                    $obj->default_encoding,
1571
                    $obj->default_view_mod,
1572
                    $obj->prevent_reinit,
1573
                    $obj->force_commit,
1574
                    $obj->content_maker,
1575
                    $obj->display_order,
1576
                    $obj->js_lib,
1577
                    $obj->content_license,
1578
                    $obj->debug,
1579
                    $visibility,
1580
                    $obj->author,
1581
                    $obj->preview_image,
1582
                    $obj->use_max_score,
1583
                    $obj->autolaunch,
1584
                    $obj->created_on,
1585
                    $obj->modified_on,
1586
                    $obj->publicated_on,
1587
                    $obj->expired_on,
1588
                    $obj->session_id,
1589
                    $obj->category_id,
1590
                    $obj->subscribe_users,
1591
                    $obj->hide_toc_frame,
1592
                    $items,
1593
                    $accumulateWorkTime,
1594
                    $obj->prerequisite
1595
                );
1596
                $extraFieldValue = new \ExtraFieldValue('lp');
1597
                $lp->extraFields = $extraFieldValue->getAllValuesByItem($obj->id);
1598
                $this->course->add_resource($lp);
1599
1600
                if (!empty($obj->preview_image)) {
1601
                    // Add LP image
1602
                    $asset = new Asset(
1603
                        $obj->preview_image,
1604
                        '/upload/learning_path/images/'.$obj->preview_image,
1605
                        '/upload/learning_path/images/'.$obj->preview_image
1606
                    );
1607
                    $this->course->add_resource($asset);
1608
                }
1609
            }
1610
        }
1611
1612
        // Save scorm directory (previously build_scorm_documents())
1613
        if ($addScormFolder) {
1614
            $i = 1;
1615
            if ($dir = @opendir($this->course->backup_path.'/scorm')) {
1616
                while ($file = readdir($dir)) {
1617
                    if (is_dir($this->course->backup_path.'/scorm/'.$file) &&
1618
                        !in_array($file, ['.', '..'])
1619
                    ) {
1620
                        $doc = new ScormDocument($i++, '/'.$file, $file);
1621
                        $this->course->add_resource($doc);
1622
                    }
1623
                }
1624
                closedir($dir);
1625
            }
1626
        }
1627
    }
1628
1629
    /**
1630
     * It builds the resources used in a LP , also it adds the documents related.
1631
     */
1632
    public function exportToCourseBuildFormat()
1633
    {
1634
        if (empty($this->itemListToAdd)) {
1635
            return false;
1636
        }
1637
        $itemList = $this->itemListToAdd;
1638
        $courseId = api_get_course_int_id();
1639
        $sessionId = api_get_session_id();
1640
        $courseInfo = api_get_course_info_by_id($courseId);
1641
        if (isset($itemList['document'])) {
1642
            // Get parents
1643
            foreach ($itemList['document'] as $documentId) {
1644
                $documentInfo = \DocumentManager::get_document_data_by_id($documentId, $courseInfo['code'], true);
1645
                if (!empty($documentInfo['parents'])) {
1646
                    foreach ($documentInfo['parents'] as $parentInfo) {
1647
                        if (in_array($parentInfo['iid'], $itemList['document'])) {
1648
                            continue;
1649
                        }
1650
                        $itemList['document'][] = $parentInfo['iid'];
1651
                    }
1652
                }
1653
            }
1654
1655
            foreach ($itemList['document'] as $documentId) {
1656
                $documentInfo = \DocumentManager::get_document_data_by_id($documentId, $courseInfo['code']);
1657
                $items = \DocumentManager::get_resources_from_source_html(
1658
                    $documentInfo['absolute_path'],
1659
                    true,
1660
                    TOOL_DOCUMENT
1661
                );
1662
1663
                if (!empty($items)) {
1664
                    foreach ($items as $item) {
1665
                        // Get information about source url
1666
                        $url = $item[0]; // url
1667
                        $scope = $item[1]; // scope (local, remote)
1668
                        $type = $item[2]; // type (rel, abs, url)
1669
1670
                        $origParseUrl = parse_url($url);
1671
                        $realOrigPath = isset($origParseUrl['path']) ? $origParseUrl['path'] : null;
1672
1673
                        if ($scope == 'local') {
1674
                            if ($type == 'abs' || $type == 'rel') {
1675
                                $documentFile = strstr($realOrigPath, 'document');
1676
                                $documentFile = (string) $documentFile;
1677
                                $realOrigPath = (string) $realOrigPath;
1678
                                if (!empty($documentFile) && false !== strpos($realOrigPath, $documentFile)) {
1679
                                    $documentFile = str_replace('document', '', $documentFile);
1680
                                    $itemDocumentId = \DocumentManager::get_document_id($courseInfo, $documentFile);
1681
                                    // Document found! Add it to the list
1682
                                    if ($itemDocumentId) {
1683
                                        $itemList['document'][] = $itemDocumentId;
1684
                                    }
1685
                                }
1686
                            }
1687
                        }
1688
                    }
1689
                }
1690
            }
1691
1692
            $this->build_documents(
1693
                $sessionId,
1694
                $courseId,
1695
                true,
1696
                $itemList['document']
1697
            );
1698
        }
1699
1700
        if (isset($itemList['quiz'])) {
1701
            $this->build_quizzes(
1702
                $sessionId,
1703
                $courseId,
1704
                true,
1705
                $itemList['quiz']
1706
            );
1707
        }
1708
1709
        require_once api_get_path(SYS_CODE_PATH).'forum/forumfunction.inc.php';
1710
1711
        if (!empty($itemList['thread'])) {
1712
            $threadList = [];
1713
            $em = Database::getManager();
1714
            $repo = $em->getRepository('ChamiloCourseBundle:CForumThread');
1715
            foreach ($itemList['thread'] as $threadId) {
1716
                /** @var \Chamilo\CourseBundle\Entity\CForumThread $thread */
1717
                $thread = $repo->find($threadId);
1718
                if ($thread) {
1719
                    $itemList['forum'][] = $thread->getForumId();
1720
                    $threadList[] = $thread->getIid();
1721
                }
1722
            }
1723
1724
            if (!empty($threadList)) {
1725
                $this->build_forum_topics(
1726
                    $sessionId,
1727
                    $courseId,
1728
                    null,
1729
                    $threadList
1730
                );
1731
            }
1732
        }
1733
1734
        $forumCategoryList = [];
1735
        if (isset($itemList['forum'])) {
1736
            foreach ($itemList['forum'] as $forumId) {
1737
                $forumInfo = get_forums($forumId);
1738
                $forumCategoryList[] = $forumInfo['forum_category'];
1739
            }
1740
        }
1741
1742
        if (!empty($forumCategoryList)) {
1743
            $this->build_forum_category(
1744
                $sessionId,
1745
                $courseId,
1746
                true,
1747
                $forumCategoryList
1748
            );
1749
        }
1750
1751
        if (!empty($itemList['forum'])) {
1752
            $this->build_forums(
1753
                $sessionId,
1754
                $courseId,
1755
                true,
1756
                $itemList['forum']
1757
            );
1758
        }
1759
1760
        if (isset($itemList['link'])) {
1761
            $this->build_links(
1762
                $sessionId,
1763
                $courseId,
1764
                true,
1765
                $itemList['link']
1766
            );
1767
        }
1768
1769
        if (isset($itemList['xapi']) && $this->isXapiEnabled) {
1770
            $this->build_xapi_tool(
1771
                $sessionId,
1772
                $courseId,
1773
                true,
1774
                $itemList['xapi']
1775
            );
1776
        }
1777
1778
        if (isset($itemList['h5p']) && $this->isH5pEnabled) {
1779
            $this->buildH5pTool(
1780
                $sessionId,
1781
                $courseId,
1782
                true,
1783
                $itemList['h5p']
1784
            );
1785
        }
1786
1787
        if (!empty($itemList['student_publication'])) {
1788
            $this->build_works(
1789
                $sessionId,
1790
                $courseId,
1791
                true,
1792
                $itemList['student_publication']
1793
            );
1794
        }
1795
    }
1796
1797
    /**
1798
     * Build the glossaries.
1799
     *
1800
     * @param int   $session_id      Internal session ID
1801
     * @param int   $courseId        Internal course ID
1802
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1803
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1804
     */
1805
    public function build_glossary(
1806
        $session_id = 0,
1807
        $courseId = 0,
1808
        $withBaseContent = false,
1809
        $id_list = []
1810
    ) {
1811
        $table_glossary = Database::get_course_table(TABLE_GLOSSARY);
1812
1813
        $courseId = (int) $courseId;
1814
1815
        if (!empty($session_id) && !empty($courseId)) {
1816
            $session_id = intval($session_id);
1817
            if ($withBaseContent) {
1818
                $sessionCondition = api_get_session_condition(
1819
                    $session_id,
1820
                    true,
1821
                    true
1822
                );
1823
            } else {
1824
                $sessionCondition = api_get_session_condition(
1825
                    $session_id,
1826
                    true
1827
                );
1828
            }
1829
1830
            //@todo check this queries are the same ...
1831
            if (!empty($this->course->type) && $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...
1832
                $sql = 'SELECT * FROM '.$table_glossary.' g
1833
                        WHERE g.c_id = '.$courseId.' '.$sessionCondition;
1834
            } else {
1835
                $sql = 'SELECT * FROM '.$table_glossary.' g
1836
                        WHERE g.c_id = '.$courseId.' '.$sessionCondition;
1837
            }
1838
        } else {
1839
            $table_glossary = Database::get_course_table(TABLE_GLOSSARY);
1840
            //@todo check this queries are the same ... ayayay
1841
            if (!empty($this->course->type) && $this->course->type == 'partial') {
1842
                $sql = 'SELECT * FROM '.$table_glossary.' g
1843
                        WHERE g.c_id = '.$courseId.' AND (session_id = 0 OR session_id IS NULL)';
1844
            } else {
1845
                $sql = 'SELECT * FROM '.$table_glossary.' g
1846
                        WHERE g.c_id = '.$courseId.' AND (session_id = 0 OR session_id IS NULL)';
1847
            }
1848
        }
1849
        $db_result = Database::query($sql);
1850
        while ($obj = Database::fetch_object($db_result)) {
1851
            $doc = new Glossary(
1852
                $obj->glossary_id,
1853
                $obj->name,
1854
                $obj->description,
1855
                $obj->display_order
1856
            );
1857
            $this->course->add_resource($doc);
1858
        }
1859
    }
1860
1861
    /*
1862
     * Build session course by jhon
1863
     */
1864
    public function build_session_course()
1865
    {
1866
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
1867
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
1868
        $list_course = CourseManager::get_course_list();
1869
        $list = [];
1870
        foreach ($list_course as $_course) {
1871
            $this->course = new Course();
1872
            $this->course->code = $_course['code'];
1873
            $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...
1874
            $this->course->path = api_get_path(SYS_COURSE_PATH).$_course['directory'].'/';
1875
            $this->course->backup_path = api_get_path(SYS_COURSE_PATH).$_course['directory'];
1876
            $this->course->encoding = api_get_system_encoding(); //current platform encoding
1877
            $courseId = $_course['real_id'];
1878
            $sql = "SELECT s.id, name, c_id
1879
                    FROM $tbl_session_course sc
1880
                    INNER JOIN $tbl_session s
1881
                    ON sc.session_id = s.id
1882
                    WHERE sc.c_id = '$courseId' ";
1883
            $query_session = Database::query($sql);
1884
            while ($rows_session = Database::fetch_assoc($query_session)) {
1885
                $session = new CourseSession(
1886
                    $rows_session['id'],
1887
                    $rows_session['name']
1888
                );
1889
                $this->course->add_resource($session);
1890
            }
1891
            $list[] = $this->course;
1892
        }
1893
1894
        return $list;
1895
    }
1896
1897
    /**
1898
     * @param int   $session_id      Internal session ID
1899
     * @param int   $courseId        Internal course ID
1900
     * @param bool  $withBaseContent Whether to include content from the course without session or not
1901
     * @param array $id_list         If you want to restrict the structure to only the given IDs
1902
     */
1903
    public function build_wiki(
1904
        $session_id = 0,
1905
        $courseId = 0,
1906
        $withBaseContent = false,
1907
        $id_list = []
1908
    ) {
1909
        $tbl_wiki = Database::get_course_table(TABLE_WIKI);
1910
        $courseId = (int) $courseId;
1911
1912
        if (!empty($session_id) && !empty($courseId)) {
1913
            $session_id = intval($session_id);
1914
            if ($withBaseContent) {
1915
                $sessionCondition = api_get_session_condition(
1916
                    $session_id,
1917
                    true,
1918
                    true
1919
                );
1920
            } else {
1921
                $sessionCondition = api_get_session_condition(
1922
                    $session_id,
1923
                    true
1924
                );
1925
            }
1926
            $sql = 'SELECT * FROM '.$tbl_wiki.'
1927
                    WHERE c_id = '.$courseId.' '.$sessionCondition;
1928
        } else {
1929
            $tbl_wiki = Database::get_course_table(TABLE_WIKI);
1930
            $sql = 'SELECT * FROM '.$tbl_wiki.'
1931
                    WHERE c_id = '.$courseId.' AND (session_id = 0 OR session_id IS NULL)';
1932
        }
1933
        $db_result = Database::query($sql);
1934
        while ($obj = Database::fetch_object($db_result)) {
1935
            $wiki = new Wiki(
1936
                $obj->id,
1937
                $obj->page_id,
1938
                $obj->reflink,
1939
                $obj->title,
1940
                $obj->content,
1941
                $obj->user_id,
1942
                $obj->group_id,
1943
                $obj->dtime,
1944
                $obj->progress,
1945
                $obj->version
1946
            );
1947
            $this->course->add_resource($wiki);
1948
        }
1949
    }
1950
1951
    /**
1952
     * Build the xapi tool.
1953
     */
1954
    public function build_xapi_tool(
1955
        $sessionId = 0,
1956
        $courseId = 0,
1957
        $withBaseContent = false,
1958
        $idList = []
1959
    ) {
1960
        if (!$this->isXapiEnabled) {
1961
            return false;
1962
        }
1963
1964
        $courseId = (int) $courseId;
1965
        $sessionId = (int) $sessionId;
1966
        if ($withBaseContent) {
1967
            $sessionCondition = api_get_session_condition(
1968
                $sessionId,
1969
                true,
1970
                true
1971
            );
1972
        } else {
1973
            $sessionCondition = api_get_session_condition($sessionId, true);
1974
        }
1975
1976
        $idCondition = '';
1977
        if (!empty($idList)) {
1978
            $idList = array_map('intval', $idList);
1979
            $idCondition = ' AND id IN ("'.implode('","', $idList).'") ';
1980
        }
1981
1982
        $sql = "SELECT * FROM xapi_tool_launch WHERE c_id = $courseId $sessionCondition $idCondition";
1983
        $rs = Database::query($sql);
1984
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
1985
            $xapiTool = new XapiTool($row);
1986
            $this->course->add_resource($xapiTool);
1987
        }
1988
    }
1989
1990
    public function buildH5pTool(
1991
        $sessionId = 0,
1992
        $courseId = 0,
1993
        $withBaseContent = false,
1994
        $idList = []
1995
    ) {
1996
        if (!$this->isH5pEnabled) {
1997
            return false;
1998
        }
1999
2000
        $courseId = (int) $courseId;
2001
        $sessionId = (int) $sessionId;
2002
        $sessionCondition = api_get_session_condition($sessionId, true, $withBaseContent);
2003
2004
        $idCondition = '';
2005
        if (!empty($idList)) {
2006
            $idList = array_map('intval', $idList);
2007
            $idCondition = ' AND iid IN ("'.implode('","', $idList).'") ';
2008
        }
2009
2010
        $sql = "SELECT * FROM plugin_h5p_import WHERE c_id = $courseId $sessionCondition $idCondition";
2011
        $rs = Database::query($sql);
2012
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
2013
            $h5pTool = new H5pTool($row);
2014
            $this->course->add_resource($h5pTool);
2015
        }
2016
    }
2017
2018
    /**
2019
     * Build the Surveys.
2020
     *
2021
     * @param int   $session_id      Internal session ID
2022
     * @param int   $courseId        Internal course ID
2023
     * @param bool  $withBaseContent Whether to include content from the course without session or not
2024
     * @param array $id_list         If you want to restrict the structure to only the given IDs
2025
     */
2026
    public function build_thematic(
2027
        $session_id = 0,
2028
        $courseId = 0,
2029
        $withBaseContent = false,
2030
        $id_list = []
2031
    ) {
2032
        $table_thematic = Database::get_course_table(TABLE_THEMATIC);
2033
        $table_thematic_advance = Database::get_course_table(TABLE_THEMATIC_ADVANCE);
2034
        $table_thematic_plan = Database::get_course_table(TABLE_THEMATIC_PLAN);
2035
        $courseId = (int) $courseId;
2036
2037
        $courseInfo = api_get_course_info_by_id($courseId);
2038
        $session_id = intval($session_id);
2039
        if ($withBaseContent) {
2040
            $sessionCondition = api_get_session_condition(
2041
                $session_id,
2042
                true,
2043
                true
2044
            );
2045
        } else {
2046
            $sessionCondition = api_get_session_condition($session_id, true);
2047
        }
2048
2049
        $sql = "SELECT * FROM $table_thematic
2050
                WHERE c_id = $courseId AND active = 1 $sessionCondition ";
2051
        $db_result = Database::query($sql);
2052
        while ($row = Database::fetch_array($db_result, 'ASSOC')) {
2053
            $thematic = new Thematic($row);
2054
            $sql = 'SELECT * FROM '.$table_thematic_advance.'
2055
                    WHERE c_id = '.$courseId.' AND thematic_id = '.$row['id'];
2056
2057
            $result = Database::query($sql);
2058
            while ($sub_row = Database::fetch_array($result, 'ASSOC')) {
2059
                $thematic->addThematicAdvance($sub_row);
2060
            }
2061
2062
            $items = api_get_item_property_by_tool(
2063
                'thematic_plan',
2064
                $courseInfo['code'],
2065
                $session_id
2066
            );
2067
2068
            $thematic_plan_id_list = [];
2069
            if (!empty($items)) {
2070
                foreach ($items as $item) {
2071
                    $thematic_plan_id_list[] = $item['ref'];
2072
                }
2073
            }
2074
            if (count($thematic_plan_id_list) > 0) {
2075
                $sql = "SELECT tp.*
2076
                        FROM $table_thematic_plan tp
2077
                            INNER JOIN $table_thematic t ON (t.id=tp.thematic_id)
2078
                        WHERE
2079
                            t.c_id = $courseId AND
2080
                            tp.c_id = $courseId AND
2081
                            thematic_id = {$row['id']}  AND
2082
                            tp.id IN (".implode(', ', $thematic_plan_id_list).") ";
2083
2084
                $result = Database::query($sql);
2085
                while ($sub_row = Database::fetch_array($result, 'ASSOC')) {
2086
                    $thematic->addThematicPlan($sub_row);
2087
                }
2088
            }
2089
            $this->course->add_resource($thematic);
2090
        }
2091
    }
2092
2093
    /**
2094
     * Build the attendances.
2095
     *
2096
     * @param int   $session_id      Internal session ID
2097
     * @param int   $courseId        Internal course ID
2098
     * @param bool  $withBaseContent Whether to include content from the course without session or not
2099
     * @param array $id_list         If you want to restrict the structure to only the given IDs
2100
     */
2101
    public function build_attendance(
2102
        $session_id = 0,
2103
        $courseId = 0,
2104
        $withBaseContent = false,
2105
        $id_list = []
2106
    ) {
2107
        $table_attendance = Database::get_course_table(TABLE_ATTENDANCE);
2108
        $table_attendance_calendar = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
2109
        $sessionCondition = api_get_session_condition($session_id, true, $withBaseContent);
2110
        $courseId = (int) $courseId;
2111
2112
        $sql = 'SELECT * FROM '.$table_attendance.'
2113
                WHERE c_id = '.$courseId.' '.$sessionCondition;
2114
        $db_result = Database::query($sql);
2115
        while ($row = Database::fetch_array($db_result, 'ASSOC')) {
2116
            $obj = new Attendance($row);
2117
            $sql = 'SELECT * FROM '.$table_attendance_calendar.'
2118
                    WHERE c_id = '.$courseId.' AND attendance_id = '.$row['id'];
2119
2120
            $result = Database::query($sql);
2121
            while ($sub_row = Database::fetch_array($result, 'ASSOC')) {
2122
                $obj->add_attendance_calendar($sub_row);
2123
            }
2124
            $this->course->add_resource($obj);
2125
        }
2126
    }
2127
2128
    /**
2129
     * Build the works (or "student publications", or "assignments").
2130
     *
2131
     * @param int   $session_id      Internal session ID
2132
     * @param int   $courseId        Internal course ID
2133
     * @param bool  $withBaseContent Whether to include content from the course without session or not
2134
     * @param array $idList          If you want to restrict the structure to only the given IDs
2135
     */
2136
    public function build_works(
2137
        $session_id = 0,
2138
        $courseId = 0,
2139
        $withBaseContent = false,
2140
        $idList = []
2141
    ) {
2142
        $table_work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
2143
        $sessionCondition = api_get_session_condition(
2144
            $session_id,
2145
            true,
2146
            $withBaseContent
2147
        );
2148
        $courseId = (int) $courseId;
2149
2150
        $idCondition = '';
2151
        if (!empty($idList)) {
2152
            $idList = array_map('intval', $idList);
2153
            $idCondition = ' AND iid IN ("'.implode('","', $idList).'") ';
2154
        }
2155
2156
        $sql = "SELECT * FROM $table_work
2157
                WHERE
2158
                    c_id = $courseId
2159
                    $sessionCondition AND
2160
                    filetype = 'folder' AND
2161
                    parent_id = 0 AND
2162
                    active = 1
2163
                    $idCondition
2164
                ";
2165
        $result = Database::query($sql);
2166
        while ($row = Database::fetch_array($result, 'ASSOC')) {
2167
            $obj = new Work($row);
2168
            $this->findAndSetDocumentsInText($row['description']);
2169
            $this->course->add_resource($obj);
2170
        }
2171
    }
2172
2173
    /**
2174
     * @param int  $session_id
2175
     * @param int  $courseId
2176
     * @param bool $withBaseContent
2177
     */
2178
    public function build_gradebook(
2179
        $session_id = 0,
2180
        $courseId = 0,
2181
        $withBaseContent = false
2182
    ) {
2183
        $courseInfo = api_get_course_info_by_id($courseId);
2184
        $courseCode = $courseInfo['code'];
2185
        $cats = Category::load(
2186
            null,
2187
            null,
2188
            $courseCode,
2189
            null,
2190
            null,
2191
            $session_id
2192
        );
2193
2194
        if (!empty($cats)) {
2195
            /** @var Category $cat */
2196
            foreach ($cats as $cat) {
2197
                $cat->evaluations = $cat->get_evaluations(null, false);
2198
                $cat->links = $cat->get_links(null, false);
2199
                $cat->subCategories = $cat->get_subcategories(
2200
                    null,
2201
                    $courseCode,
2202
                    $session_id
2203
                );
2204
            }
2205
            $obj = new GradeBookBackup($cats);
2206
            $this->course->add_resource($obj);
2207
        }
2208
    }
2209
}
2210