Passed
Pull Request — master (#6894)
by
unknown
09:02
created

CourseExport   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 345
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 191
c 1
b 0
f 0
dl 0
loc 345
rs 10
wmc 28

12 Methods

Rating   Name   Duplication   Size   Complexity  
A createContentBankXml() 0 12 2
A createEnrolmentsXml() 0 17 2
A createCommentsXml() 0 16 2
A __construct() 0 10 2
B createCourseXml() 0 66 1
B createInforefXml() 0 41 7
A exportCourse() 0 17 2
A createCompetenciesXml() 0 13 2
A createRolesXml() 0 13 2
A createCalendarXml() 0 18 2
A createCompletionDefaultsXml() 0 13 2
A createFiltersXml() 0 16 2
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CourseBundle\Component\CourseCopy\Moodle\Builder;
8
9
use Chamilo\CourseBundle\Component\CourseCopy\Moodle\Activities\QuizExport;
10
use Exception;
11
12
use const PHP_EOL;
13
14
/**
15
 * Writes the course-level directory and XMLs inside the export root.
16
 */
17
class CourseExport
18
{
19
    /**
20
     * @var object
21
     */
22
    private $course;
23
24
    /**
25
     * @var array<string,mixed>
26
     */
27
    private array $courseInfo;
28
29
    /**
30
     * @var array<int,array<string,mixed>>
31
     */
32
    private array $activities;
33
34
    /**
35
     * @param array<int,array<string,mixed>>|null $activities
36
     *
37
     * @throws Exception
38
     */
39
    public function __construct(object $course, ?array $activities = [])
40
    {
41
        $this->course = $course;
42
        $this->courseInfo = (array) (api_get_course_info($course->code) ?? []);
43
44
        if (empty($this->courseInfo)) {
45
            throw new Exception('Course not found.');
46
        }
47
48
        $this->activities = $activities ?? [];
49
    }
50
51
    /**
52
     * Export the course-related files to the appropriate directory.
53
     */
54
    public function exportCourse(string $exportDir): void
55
    {
56
        $courseDir = $exportDir.'/course';
57
        if (!is_dir($courseDir)) {
58
            mkdir($courseDir, api_get_permissions_for_new_directories(), true);
59
        }
60
61
        $this->createCourseXml($courseDir);
62
        $this->createEnrolmentsXml($this->courseInfo['enrolments'] ?? [], $courseDir);
63
        $this->createInforefXml($courseDir);
64
        $this->createRolesXml($this->courseInfo['roles'] ?? [], $courseDir);
65
        $this->createCalendarXml($this->courseInfo['calendar'] ?? [], $courseDir);
66
        $this->createCommentsXml($this->courseInfo['comments'] ?? [], $courseDir);
67
        $this->createCompetenciesXml($this->courseInfo['competencies'] ?? [], $courseDir);
68
        $this->createCompletionDefaultsXml($this->courseInfo['completiondefaults'] ?? [], $courseDir);
69
        $this->createContentBankXml($this->courseInfo['contentbank'] ?? [], $courseDir);
70
        $this->createFiltersXml($this->courseInfo['filters'] ?? [], $courseDir);
71
    }
72
73
    /**
74
     * Create course.xml based on the course data.
75
     */
76
    private function createCourseXml(string $destinationDir): void
77
    {
78
        $courseId = (int) ($this->courseInfo['real_id'] ?? 0);
79
        $contextId = (int) ($this->courseInfo['real_id'] ?? 1);
80
        $shortname = (string) ($this->courseInfo['code'] ?? 'Unknown Course');
81
        $fullname = (string) ($this->courseInfo['title'] ?? 'Unknown Fullname');
82
        $showgrades = (int) ($this->courseInfo['showgrades'] ?? 0);
83
        $startdate = (int) ($this->courseInfo['startdate'] ?? time());
84
        $enddate = (int) ($this->courseInfo['enddate'] ?? (time() + 31536000));
85
        $visible = (int) ($this->courseInfo['visible'] ?? 1);
86
        $enablecompletion = (int) ($this->courseInfo['enablecompletion'] ?? 0);
87
88
        $xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
89
        $xmlContent .= '<course id="'.$courseId.'" contextid="'.$contextId.'">'.PHP_EOL;
90
        $xmlContent .= '  <shortname>'.htmlspecialchars($shortname).'</shortname>'.PHP_EOL;
91
        $xmlContent .= '  <fullname>'.htmlspecialchars($fullname).'</fullname>'.PHP_EOL;
92
        $xmlContent .= '  <idnumber></idnumber>'.PHP_EOL;
93
        $xmlContent .= '  <summary></summary>'.PHP_EOL;
94
        $xmlContent .= '  <summaryformat>1</summaryformat>'.PHP_EOL;
95
        $xmlContent .= '  <format>topics</format>'.PHP_EOL;
96
        $xmlContent .= '  <showgrades>'.$showgrades.'</showgrades>'.PHP_EOL;
97
        $xmlContent .= '  <newsitems>5</newsitems>'.PHP_EOL;
98
        $xmlContent .= '  <startdate>'.$startdate.'</startdate>'.PHP_EOL;
99
        $xmlContent .= '  <enddate>'.$enddate.'</enddate>'.PHP_EOL;
100
        $xmlContent .= '  <marker>0</marker>'.PHP_EOL;
101
        $xmlContent .= '  <maxbytes>0</maxbytes>'.PHP_EOL;
102
        $xmlContent .= '  <legacyfiles>0</legacyfiles>'.PHP_EOL;
103
        $xmlContent .= '  <showreports>0</showreports>'.PHP_EOL;
104
        $xmlContent .= '  <visible>'.$visible.'</visible>'.PHP_EOL;
105
        $xmlContent .= '  <groupmode>0</groupmode>'.PHP_EOL;
106
        $xmlContent .= '  <groupmodeforce>0</groupmodeforce>'.PHP_EOL;
107
        $xmlContent .= '  <defaultgroupingid>0</defaultgroupingid>'.PHP_EOL;
108
        $xmlContent .= '  <lang></lang>'.PHP_EOL;
109
        $xmlContent .= '  <theme></theme>'.PHP_EOL;
110
        $xmlContent .= '  <timecreated>'.time().'</timecreated>'.PHP_EOL;
111
        $xmlContent .= '  <timemodified>'.time().'</timemodified>'.PHP_EOL;
112
        $xmlContent .= '  <requested>0</requested>'.PHP_EOL;
113
        $xmlContent .= '  <showactivitydates>1</showactivitydates>'.PHP_EOL;
114
        $xmlContent .= '  <showcompletionconditions>1</showcompletionconditions>'.PHP_EOL;
115
        $xmlContent .= '  <enablecompletion>'.$enablecompletion.'</enablecompletion>'.PHP_EOL;
116
        $xmlContent .= '  <completionnotify>0</completionnotify>'.PHP_EOL;
117
        $xmlContent .= '  <category id="1">'.PHP_EOL;
118
        $xmlContent .= '    <name>Miscellaneous</name>'.PHP_EOL;
119
        $xmlContent .= '    <description>$@NULL@$</description>'.PHP_EOL;
120
        $xmlContent .= '  </category>'.PHP_EOL;
121
        $xmlContent .= '  <tags>'.PHP_EOL;
122
        $xmlContent .= '  </tags>'.PHP_EOL;
123
        $xmlContent .= '  <customfields>'.PHP_EOL;
124
        $xmlContent .= '  </customfields>'.PHP_EOL;
125
        $xmlContent .= '  <courseformatoptions>'.PHP_EOL;
126
        $xmlContent .= '    <courseformatoption>'.PHP_EOL;
127
        $xmlContent .= '      <format>topics</format>'.PHP_EOL;
128
        $xmlContent .= '      <sectionid>0</sectionid>'.PHP_EOL;
129
        $xmlContent .= '      <name>hiddensections</name>'.PHP_EOL;
130
        $xmlContent .= '      <value>0</value>'.PHP_EOL;
131
        $xmlContent .= '    </courseformatoption>'.PHP_EOL;
132
        $xmlContent .= '    <courseformatoption>'.PHP_EOL;
133
        $xmlContent .= '      <format>topics</format>'.PHP_EOL;
134
        $xmlContent .= '      <sectionid>0</sectionid>'.PHP_EOL;
135
        $xmlContent .= '      <name>coursedisplay</name>'.PHP_EOL;
136
        $xmlContent .= '      <value>0</value>'.PHP_EOL;
137
        $xmlContent .= '    </courseformatoption>'.PHP_EOL;
138
        $xmlContent .= '  </courseformatoptions>'.PHP_EOL;
139
        $xmlContent .= '</course>';
140
141
        file_put_contents($destinationDir.'/course.xml', $xmlContent);
142
    }
143
144
    /**
145
     * Create enrolments.xml based on the course data.
146
     *
147
     * @param array<int,array<string,mixed>> $enrolmentsData
148
     */
149
    private function createEnrolmentsXml(array $enrolmentsData, string $destinationDir): void
150
    {
151
        $xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
152
        $xmlContent .= '<enrolments>'.PHP_EOL;
153
        foreach ($enrolmentsData as $enrol) {
154
            $id = (int) ($enrol['id'] ?? 0);
155
            $type = (string) ($enrol['type'] ?? 'manual');
156
            $status = (int) ($enrol['status'] ?? 1);
157
158
            $xmlContent .= '  <enrol id="'.$id.'">'.PHP_EOL;
159
            $xmlContent .= '    <enrol>'.htmlspecialchars($type).'</enrol>'.PHP_EOL;
160
            $xmlContent .= '    <status>'.$status.'</status>'.PHP_EOL;
161
            $xmlContent .= '  </enrol>'.PHP_EOL;
162
        }
163
        $xmlContent .= '</enrolments>';
164
165
        file_put_contents($destinationDir.'/enrolments.xml', $xmlContent);
166
    }
167
168
    /**
169
     * Creates the inforef.xml file with question category references and a basic role ref.
170
     */
171
    private function createInforefXml(string $destinationDir): void
172
    {
173
        $xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
174
        $xmlContent .= '<inforef>'.PHP_EOL;
175
176
        // Gather unique question category ids from quiz activities
177
        $questionCategories = [];
178
        foreach ($this->activities as $activity) {
179
            if (($activity['modulename'] ?? '') === 'quiz') {
180
                $quizExport = new QuizExport($this->course);
181
                $quizData = $quizExport->getData((int) $activity['id'], (int) $activity['sectionid']);
182
183
                foreach ($quizData['questions'] as $question) {
184
                    $categoryId = (int) $question['questioncategoryid'];
185
                    if (!\in_array($categoryId, $questionCategories, true)) {
186
                        $questionCategories[] = $categoryId;
187
                    }
188
                }
189
            }
190
        }
191
192
        if (!empty($questionCategories)) {
193
            $xmlContent .= '  <question_categoryref>'.PHP_EOL;
194
            foreach ($questionCategories as $categoryId) {
195
                $xmlContent .= '    <question_category>'.PHP_EOL;
196
                $xmlContent .= '      <id>'.$categoryId.'</id>'.PHP_EOL;
197
                $xmlContent .= '    </question_category>'.PHP_EOL;
198
            }
199
            $xmlContent .= '  </question_categoryref>'.PHP_EOL;
200
        }
201
202
        // Add a minimal role reference (student)
203
        $xmlContent .= '  <roleref>'.PHP_EOL;
204
        $xmlContent .= '    <role>'.PHP_EOL;
205
        $xmlContent .= '      <id>5</id>'.PHP_EOL;
206
        $xmlContent .= '    </role>'.PHP_EOL;
207
        $xmlContent .= '  </roleref>'.PHP_EOL;
208
209
        $xmlContent .= '</inforef>'.PHP_EOL;
210
211
        file_put_contents($destinationDir.'/inforef.xml', $xmlContent);
212
    }
213
214
    /**
215
     * Creates the roles.xml file.
216
     *
217
     * @param array<int,array<string,mixed>> $rolesData
218
     */
219
    private function createRolesXml(array $rolesData, string $destinationDir): void
220
    {
221
        $xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
222
        $xmlContent .= '<roles>'.PHP_EOL;
223
        foreach ($rolesData as $role) {
224
            $roleName = (string) ($role['name'] ?? 'Student');
225
            $xmlContent .= '  <role>'.PHP_EOL;
226
            $xmlContent .= '    <name>'.htmlspecialchars($roleName).'</name>'.PHP_EOL;
227
            $xmlContent .= '  </role>'.PHP_EOL;
228
        }
229
        $xmlContent .= '</roles>';
230
231
        file_put_contents($destinationDir.'/roles.xml', $xmlContent);
232
    }
233
234
    /**
235
     * Creates the calendar.xml file.
236
     *
237
     * @param array<int,array<string,mixed>> $calendarData
238
     */
239
    private function createCalendarXml(array $calendarData, string $destinationDir): void
240
    {
241
        $xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
242
        $xmlContent .= '<calendar>'.PHP_EOL;
243
        foreach ($calendarData as $event) {
244
            $eventName = (string) ($event['name'] ?? 'Event');
245
            $timestart = (int) ($event['timestart'] ?? time());
246
            $duration = (int) ($event['duration'] ?? 3600);
247
248
            $xmlContent .= '  <event>'.PHP_EOL;
249
            $xmlContent .= '    <name>'.htmlspecialchars($eventName).'</name>'.PHP_EOL;
250
            $xmlContent .= '    <timestart>'.$timestart.'</timestart>'.PHP_EOL;
251
            $xmlContent .= '    <duration>'.$duration.'</duration>'.PHP_EOL;
252
            $xmlContent .= '  </event>'.PHP_EOL;
253
        }
254
        $xmlContent .= '</calendar>';
255
256
        file_put_contents($destinationDir.'/calendar.xml', $xmlContent);
257
    }
258
259
    /**
260
     * Creates the comments.xml file.
261
     *
262
     * @param array<int,array<string,mixed>> $commentsData
263
     */
264
    private function createCommentsXml(array $commentsData, string $destinationDir): void
265
    {
266
        $xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
267
        $xmlContent .= '<comments>'.PHP_EOL;
268
        foreach ($commentsData as $comment) {
269
            $content = (string) ($comment['content'] ?? 'No comment');
270
            $author = (string) ($comment['author'] ?? 'Anonymous');
271
272
            $xmlContent .= '  <comment>'.PHP_EOL;
273
            $xmlContent .= '    <content>'.htmlspecialchars($content).'</content>'.PHP_EOL;
274
            $xmlContent .= '    <author>'.htmlspecialchars($author).'</author>'.PHP_EOL;
275
            $xmlContent .= '  </comment>'.PHP_EOL;
276
        }
277
        $xmlContent .= '</comments>';
278
279
        file_put_contents($destinationDir.'/comments.xml', $xmlContent);
280
    }
281
282
    /**
283
     * Creates the competencies.xml file.
284
     *
285
     * @param array<int,array<string,mixed>> $competenciesData
286
     */
287
    private function createCompetenciesXml(array $competenciesData, string $destinationDir): void
288
    {
289
        $xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
290
        $xmlContent .= '<competencies>'.PHP_EOL;
291
        foreach ($competenciesData as $competency) {
292
            $name = (string) ($competency['name'] ?? 'Competency');
293
            $xmlContent .= '  <competency>'.PHP_EOL;
294
            $xmlContent .= '    <name>'.htmlspecialchars($name).'</name>'.PHP_EOL;
295
            $xmlContent .= '  </competency>'.PHP_EOL;
296
        }
297
        $xmlContent .= '</competencies>';
298
299
        file_put_contents($destinationDir.'/competencies.xml', $xmlContent);
300
    }
301
302
    /**
303
     * Creates the completiondefaults.xml file.
304
     *
305
     * @param array<int,array<string,mixed>> $completionData
306
     */
307
    private function createCompletionDefaultsXml(array $completionData, string $destinationDir): void
308
    {
309
        $xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
310
        $xmlContent .= '<completiondefaults>'.PHP_EOL;
311
        foreach ($completionData as $completion) {
312
            $completionState = (int) ($completion['state'] ?? 0);
313
            $xmlContent .= '  <completion>'.PHP_EOL;
314
            $xmlContent .= '    <completionstate>'.$completionState.'</completionstate>'.PHP_EOL;
315
            $xmlContent .= '  </completion>'.PHP_EOL;
316
        }
317
        $xmlContent .= '</completiondefaults>';
318
319
        file_put_contents($destinationDir.'/completiondefaults.xml', $xmlContent);
320
    }
321
322
    /**
323
     * Creates the contentbank.xml file.
324
     *
325
     * @param array<int,array<string,mixed>> $contentBankData
326
     */
327
    private function createContentBankXml(array $contentBankData, string $destinationDir): void
328
    {
329
        $xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
330
        $xmlContent .= '<contentbank>'.PHP_EOL;
331
        foreach ($contentBankData as $content) {
332
            $id = (int) ($content['id'] ?? 0);
333
            $name = (string) ($content['name'] ?? 'Content');
334
            $xmlContent .= '  <content id="'.$id.'">'.htmlspecialchars($name).'</content>'.PHP_EOL;
335
        }
336
        $xmlContent .= '</contentbank>';
337
338
        file_put_contents($destinationDir.'/contentbank.xml', $xmlContent);
339
    }
340
341
    /**
342
     * Creates the filters.xml file.
343
     *
344
     * @param array<int,array<string,mixed>> $filtersData
345
     */
346
    private function createFiltersXml(array $filtersData, string $destinationDir): void
347
    {
348
        $xmlContent = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
349
        $xmlContent .= '<filters>'.PHP_EOL;
350
        foreach ($filtersData as $filter) {
351
            $filterName = (string) ($filter['name'] ?? 'filter_example');
352
            $active = (int) ($filter['active'] ?? 1);
353
354
            $xmlContent .= '  <filter>'.PHP_EOL;
355
            $xmlContent .= '    <filtername>'.htmlspecialchars($filterName).'</filtername>'.PHP_EOL;
356
            $xmlContent .= '    <active>'.$active.'</active>'.PHP_EOL;
357
            $xmlContent .= '  </filter>'.PHP_EOL;
358
        }
359
        $xmlContent .= '</filters>';
360
361
        file_put_contents($destinationDir.'/filters.xml', $xmlContent);
362
    }
363
}
364