Passed
Pull Request — master (#6921)
by
unknown
09:03
created

Cc13Convert::getItemSections()   C

Complexity

Conditions 12
Paths 10

Size

Total Lines 53
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 37
c 1
b 0
f 0
nc 10
nop 5
dl 0
loc 53
rs 6.9666

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
declare(strict_types=1);
6
7
namespace Chamilo\CourseBundle\Component\CourseCopy\CommonCartridge\Export;
8
9
use Chamilo\CourseBundle\Component\CourseCopy\CommonCartridge\Export\Interfaces\CcIItem;
10
use Chamilo\CourseBundle\Component\CourseCopy\CommonCartridge\Export\Interfaces\CcIManifest;
11
use Chamilo\CourseBundle\Component\CourseCopy\Course;
12
use Exception;
13
use InvalidArgumentException;
14
use RuntimeException;
15
16
use const DIRECTORY_SEPARATOR;
17
18
class Cc13Convert
19
{
20
    /**
21
     * Converts a course object into a CC13 package and writes it to disk.
22
     *
23
     * @param Course $objCourse the Course object is "augmented" with info from the api_get_course_info() function, into the "$objCourse->info" array attribute
24
     *
25
     * @return bool
26
     *
27
     * @throws Exception
28
     */
29
    public static function convert(string $packagedir, string $outdir, Course $objCourse)
30
    {
31
        $dir = realpath($packagedir);
32
        if (empty($dir)) {
33
            throw new InvalidArgumentException('Directory does not exist!');
34
        }
35
        $odir = realpath($outdir);
36
        if (empty($odir)) {
37
            throw new InvalidArgumentException('Directory does not exist!');
38
        }
39
40
        if (!empty($objCourse)) {
41
            // Initialize the manifest metadata class
42
            $meta = new CcMetadataManifest();
43
44
            // Package metadata
45
            $metageneral = new CcMetadataGeneral();
46
            $metageneral->setLanguage($objCourse->info['language']);
47
            $metageneral->setTitle($objCourse->info['title'], $objCourse->info['language']);
48
            $metageneral->setDescription('', $objCourse->info['language']);
49
            $metageneral->setCatalog('category');
50
            $metageneral->setEntry($objCourse->info['categoryName']);
51
            $meta->addMetadataGeneral($metageneral);
52
53
            // Create the manifest
54
            $manifest = new CcManifest();
55
56
            $manifest->addMetadataManifest($meta);
57
58
            $organization = null;
59
60
            // Get the course structure - this will be transformed into organization
61
            // Step 1 - Get the list and order of sections/topics
62
63
            $count = 1;
64
            $sections = [];
65
            $resources = $objCourse->resources;
66
67
            // We check the quiz sections
68
            if (isset($resources['quiz'])) {
69
                $quizSections = self::getItemSections(
70
                    $resources['quiz'], // array of quiz IDs generated by the course backup process
71
                    'quiz',
72
                    $count,
73
                    $objCourse->info['code'],
74
                    $resources[RESOURCE_QUIZQUESTION] // selected question IDs from the course export form
75
                );
76
                $sections = array_merge($sections, $quizSections);
77
            }
78
79
            // We check the document sections
80
            if (isset($resources['document'])) {
81
                $documentSections = self::getItemSections(
82
                    $resources['document'],
83
                    'document',
84
                    $count,
85
                    $objCourse->info['code']
86
                );
87
                $sections = array_merge($sections, $documentSections);
88
            }
89
90
            // We check the wiki sections
91
            if (isset($resources['wiki'])) {
92
                $wikiSections = self::getItemSections(
93
                    $resources['wiki'],
94
                    'wiki',
95
                    $count,
96
                    $objCourse->info['code']
97
                );
98
                $sections = array_merge($sections, $wikiSections);
99
            }
100
101
            // We check the forum sections
102
            if (isset($resources['forum'])) {
103
                $forumSections = self::getItemSections(
104
                    $resources['forum'],
105
                    'forum',
106
                    $count,
107
                    $objCourse->info['code'],
108
                    $resources['Forum_Category']
109
                );
110
                $sections = array_merge($sections, $forumSections);
111
            }
112
113
            // We check the link sections
114
            if (isset($resources['link'])) {
115
                $linkSections = self::getItemSections(
116
                    $resources['link'],
117
                    'link',
118
                    $count,
119
                    $objCourse->info['code'],
120
                    $resources['Link_Category']
121
                );
122
                $sections = array_merge($sections, $linkSections);
123
            }
124
125
            // organization title
126
            $organization = new CcOrganization();
127
            foreach ($sections as $sectionid => $values) {
128
                $item = new CcItem();
129
                $item->title = $values[0];
130
                self::processSequence($item, $manifest, $values[1], $dir, $odir);
131
                $organization->addItem($item);
132
            }
133
            $manifest->putNodes();
134
135
            if (!empty($organization)) {
136
                $manifest->addNewOrganization($organization);
137
            }
138
139
            $manifestpath = $outdir.DIRECTORY_SEPARATOR.'imsmanifest.xml';
140
141
            return $manifest->saveTo($manifestpath);
142
        }
143
144
        return false;
145
    }
146
147
    /**
148
     * Return array of type $sections[1]['quiz', [sequence]] where sequence is the result of a call to getSequence().
149
     *
150
     * @param string $courseCode     The course code litteral
151
     * @param ?array $itmesExtraData If defined, represents the items IDs selected in the course export form
152
     *
153
     * @return array
154
     *
155
     * @reference self::getSequence()
156
     */
157
    protected static function getItemSections(array $itemData, string $itemType, int &$count, string $courseCode, ?array $itmesExtraData = null)
158
    {
159
        $sections = [];
160
161
        switch ($itemType) {
162
            case 'quiz':
163
            case 'document':
164
            case 'wiki':
165
                $convertType = $itemType;
166
                if ('wiki' == $itemType) {
167
                    $convertType = 'Page';
168
                }
169
                $sectionid = $count;
170
                $sectiontitle = ucfirst($itemType);
171
                $sequence = self::getSequence($itemData, 0, $convertType, $courseCode, $itmesExtraData);
172
                $sections[$sectionid] = [$sectiontitle, $sequence];
173
                $count++;
174
175
                break;
176
177
            case 'link':
178
                $links = self::getSequence($itemData, null, $itemType);
179
                foreach ($links as $categoryId => $sequence) {
180
                    $sectionid = $count;
181
                    if (isset($itmesExtraData[$categoryId])) {
182
                        $sectiontitle = $itmesExtraData[$categoryId]->title;
183
                    } else {
184
                        $sectiontitle = 'General';
185
                    }
186
                    $sections[$sectionid] = [$sectiontitle, $sequence];
187
                    $count++;
188
                }
189
190
                break;
191
192
            case 'forum':
193
                if (isset($itmesExtraData)) {
194
                    foreach ($itmesExtraData as $fcategory) {
195
                        if (isset($fcategory->obj)) {
196
                            $objCategory = $fcategory->obj;
197
                            $sectionid = $count;
198
                            $sectiontitle = $objCategory->cat_title;
199
                            $sequence = self::getSequence($itemData, $objCategory->iid, $itemType);
200
                            $sections[$sectionid] = [$sectiontitle, $sequence];
201
                            $count++;
202
                        }
203
                    }
204
                }
205
206
                break;
207
        }
208
209
        return $sections;
210
    }
211
212
    /**
213
     * Return array of items by category and item ID ("test" level, not "question" level) with details like title,
214
     * comment (description), type, questions, max_attempt, etc.
215
     *
216
     * @param array $objItems Array of item objects as returned by the course backup code
217
     *
218
     * @return array|mixed
219
     */
220
    protected static function getSequence(array $objItems, ?int $categoryId = null, ?string $itemType = null, ?string $coursecode = null, ?array $itemQuestions = null)
221
    {
222
        $sequences = [];
223
224
        switch ($itemType) {
225
            case 'quiz':
226
                $sequence = [];
227
                foreach ($objItems as $objItem) {
228
                    if (0 === $categoryId) {
229
                        $questions = [];
230
                        foreach ($objItem->obj->question_ids as $questionId) {
231
                            if (isset($itemQuestions[$questionId])) {
232
                                $questions[$questionId] = $itemQuestions[$questionId];
233
                            }
234
                        }
235
                        // As weird as this may sound, the constructors for the different object types (found in
236
                        // src/CourseBundle/Component/CourseCopy/Resources/[objecttype].php) store the object property
237
                        // in the "obj" attribute. Old code...
238
                        // So here we recover properties from the quiz object, including questions (array built above).
239
                        $sequence[$categoryId][$objItem->obj->iid] = [
240
                            'title' => $objItem->obj->title,
241
                            'comment' => $objItem->obj->description,
242
                            'cc_type' => 'quiz',
243
                            'source_id' => $objItem->obj->iid,
244
                            'questions' => $questions,
245
                            'max_attempt' => $objItem->obj->max_attempt,
246
                            'expired_time' => $objItem->obj->expired_time,
247
                            'pass_percentage' => $objItem->obj->pass_percentage,
248
                            'random_answers' => $objItem->obj->random_answers,
249
                            'course_code' => $coursecode,
250
                        ];
251
                    }
252
                }
253
                $sequences = $sequence[$categoryId];
254
255
                break;
256
257
            case 'document':
258
                $sequence = [];
259
                foreach ($objItems as $objItem) {
260
                    if (0 === $categoryId) {
261
                        $sequence[$categoryId][$objItem->source_id] = [
262
                            'title' => $objItem->title,
263
                            'comment' => $objItem->comment,
264
                            'cc_type' => ('folder' == $objItem->file_type ? 'folder' : 'resource'),
265
                            'source_id' => $objItem->source_id,
266
                            'path' => $objItem->path,
267
                            'file_type' => $objItem->file_type,
268
                            'course_code' => $coursecode,
269
                        ];
270
                    }
271
                }
272
                $sequences = $sequence[$categoryId];
273
274
                break;
275
276
            case 'forum':
277
                foreach ($objItems as $objItem) {
278
                    if ($categoryId == $objItem->obj->forum_category) {
279
                        $sequence[$categoryId][$objItem->obj->forum_id] = [
280
                            'title' => $objItem->obj->forum_title,
281
                            'comment' => $objItem->obj->forum_comment,
282
                            'cc_type' => 'forum',
283
                            'source_id' => $objItem->obj->iid,
284
                        ];
285
                    }
286
                }
287
                $sequences = $sequence[$categoryId];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sequence does not seem to be defined for all execution paths leading up to this point.
Loading history...
288
289
                break;
290
291
            case 'page':
292
                foreach ($objItems as $objItem) {
293
                    if (0 === $categoryId) {
294
                        $sequence[$categoryId][$objItem->page_id] = [
295
                            'title' => $objItem->title,
296
                            'comment' => $objItem->content,
297
                            'cc_type' => 'page',
298
                            'source_id' => $objItem->page_id,
299
                            'reflink' => $objItem->reflink,
300
                        ];
301
                    }
302
                }
303
                $sequences = $sequence[$categoryId];
304
305
                break;
306
307
            case 'link':
308
                if (!isset($categoryId)) {
309
                    $categories = [];
310
                    foreach ($objItems as $objItem) {
311
                        $categories[$objItem->category_id] = self::getSequence($objItems, $objItem->category_id, $itemType);
312
                    }
313
                    $sequences = $categories;
314
                } else {
315
                    foreach ($objItems as $objItem) {
316
                        if ($categoryId == $objItem->category_id) {
317
                            $sequence[$categoryId][$objItem->source_id] = [
318
                                'title' => $objItem->title,
319
                                'comment' => $objItem->description,
320
                                'cc_type' => 'url',
321
                                'source_id' => $objItem->source_id,
322
                                'url' => $objItem->url,
323
                                'target' => $objItem->target,
324
                            ];
325
                        }
326
                    }
327
                    $sequences = $sequence[$categoryId];
328
                }
329
330
                break;
331
        }
332
333
        return $sequences;
334
    }
335
336
    /**
337
     * Process the different types of activities exported from the course.
338
     * When dealing with tests, the "sequence" provided here is a test, not a question.
339
     * For each sequence, call the corresponding CcConverter[Type] object instantiation method in export/src/converter/.
340
     */
341
    protected static function processSequence(CcIItem &$item, CcIManifest &$manifest, array $sequence, string $packageroot, string $outdir): void
342
    {
343
        if (!empty($sequence)) {
344
            foreach ($sequence as $seq) {
345
                $activity_type = ucfirst($seq['cc_type']);
346
                $activity_indentation = 0;
347
                $aitem = self::itemIndenter($item, $activity_indentation);
348
                $caller = "CcConverter{$activity_type}";
349
                if (class_exists($caller)) {
350
                    $obj = new $caller($aitem, $manifest, $packageroot, $outdir);
351
                    if (!$obj->convert($outdir, $seq)) {
352
                        throw new RuntimeException("failed to convert {$activity_type}");
353
                    }
354
                }
355
            }
356
        }
357
    }
358
359
    protected static function itemIndenter(CcIItem &$item, $level = 0)
360
    {
361
        $indent = (int) $level;
362
        $indent = $indent <= 0 ? 0 : $indent;
363
        $nprev = null;
364
        $nfirst = null;
365
        for ($pos = 0, $size = $indent; $pos < $size; $pos++) {
366
            $nitem = new CcItem();
367
            $nitem->title = '';
368
            if (empty($nfirst)) {
369
                $nfirst = $nitem;
370
            }
371
            if (!empty($nprev)) {
372
                $nprev->addChildItem($nitem);
373
            }
374
            $nprev = $nitem;
375
        }
376
        $result = $item;
377
        if (!empty($nfirst)) {
378
            $item->addChildItem($nfirst);
379
            $result = $nprev;
380
        }
381
382
        return $result;
383
    }
384
}
385