Completed
Push — master ( 27e209...a08afa )
by Julito
186:04 queued 150:53
created

MoodleImport::readMainQuestionsXml()   C

Complexity

Conditions 14
Paths 37

Size

Total Lines 53
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 34
nc 37
nop 2
dl 0
loc 53
rs 6.3132
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
/**
5
 * Class MoodleImport
6
 *
7
 * @author José Loguercio <[email protected]>,
8
 * @author Julio Montoya <[email protected]>
9
 *
10
 * @package chamilo.library
11
 */
12
13
class MoodleImport
14
{
15
    /**
16
     * Import moodle file
17
     *
18
     * @param resource $uploadedFile *.* mbz file moodle course backup
19
     * @return bool
20
     */
21
    public function import($uploadedFile)
22
    {
23
        $file = $uploadedFile['tmp_name'];
24
25
        if (is_file($file) && is_readable($file)) {
26
            $package = new PclZip($file);
27
            $mainFileKey = 0;
28
            $packageContent = $package->listContent();
29
            if (!empty($packageContent)) {
30
                foreach ($packageContent as $index => $value) {
31
                    if ($value['filename'] == 'moodle_backup.xml') {
32
                        $mainFileKey = $index;
33
                        break;
34
                    }
35
                }
36
            }
37
38
            if (!$mainFileKey) {
39
                Display::addFlash(
40
                    Display::return_message(
41
                        get_lang('FailedToImportThisIsNotAMoodleFile'),
42
                        'error'
43
                    )
44
                );
45
            }
46
47
            $folder = api_get_unique_id();
48
            $destinationDir = api_get_path(SYS_ARCHIVE_PATH).$folder;
49
            $coursePath = api_get_course_path();
50
            $sessionId = api_get_session_id();
51
            $groupId = api_get_group_id();
52
            $documentPath = api_get_path(SYS_COURSE_PATH).$coursePath.'/document';
53
            $courseInfo = api_get_course_info();
54
55
            mkdir($destinationDir, api_get_permissions_for_new_directories(), true);
56
57
            create_unexisting_directory(
58
                $courseInfo,
59
                api_get_user_id(),
60
                $sessionId,
61
                $groupId,
62
                null,
63
                $documentPath,
64
                '/moodle',
65
                'Moodle Docs',
66
                0
67
            );
68
69
            $package->extract(
70
                PCLZIP_OPT_PATH,
71
                $destinationDir
72
            );
73
74
            // This process will upload all question resource files
75
            $filesXml = @file_get_contents($destinationDir.'/files.xml');
76
            $mainFileModuleValues = $this->getAllQuestionFiles($filesXml);
77
            $currentResourceFilePath = $destinationDir.'/files/';
78
79
            $importedFiles = [];
80
81
            foreach ($mainFileModuleValues as $fileInfo) {
82
                $dirs = new RecursiveDirectoryIterator($currentResourceFilePath);
0 ignored issues
show
Bug introduced by
The call to RecursiveDirectoryIterator::__construct() has too few arguments starting with flags. ( Ignorable by Annotation )

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

82
                $dirs = /** @scrutinizer ignore-call */ new RecursiveDirectoryIterator($currentResourceFilePath);

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

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

Loading history...
83
                foreach (new RecursiveIteratorIterator($dirs) as $file) {
84
                    if (is_file($file) && strpos($file, $fileInfo['contenthash']) !== false) {
85
                        $files = [];
86
                        $files['file']['name'] = $fileInfo['filename'];
87
                        $files['file']['tmp_name'] = $file->getPathname();
88
                        $files['file']['type'] = $fileInfo['mimetype'];
89
                        $files['file']['error'] = 0;
90
                        $files['file']['size'] = $fileInfo['filesize'];
91
                        $files['file']['from_file'] = true;
92
                        $files['file']['move_file'] = true;
93
                        $_POST['language'] = $courseInfo['language'];
94
                        $_POST['moodle_import'] = true;
95
96
                        $data = DocumentManager::upload_document(
97
                            $files,
98
                            '/moodle',
99
                            isset($fileInfo['title']) ? $fileInfo['title'] : pathinfo($fileInfo['filename'], PATHINFO_FILENAME),
100
                            '',
101
                            null,
102
                            null,
103
                            true,
104
                            true,
105
                            'file',
106
                            // This is to validate spaces as hyphens
107
                            false
108
                        );
109
110
                        if ($data) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $data 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...
111
                            $importedFiles[$fileInfo['filename']] = basename($data['path']);
112
                        }
113
                    }
114
                }
115
            }
116
117
            $xml = @file_get_contents($destinationDir.'/moodle_backup.xml');
118
119
            $doc = new DOMDocument();
0 ignored issues
show
Bug introduced by
The call to DOMDocument::__construct() has too few arguments starting with version. ( Ignorable by Annotation )

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

119
            $doc = /** @scrutinizer ignore-call */ new DOMDocument();

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

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

Loading history...
120
            $res = @$doc->loadXML($xml);
121
            if ($res) {
122
                $activities = $doc->getElementsByTagName('activity');
123
                foreach ($activities as $activity) {
124
                    if ($activity->childNodes->length) {
125
                        $currentItem = [];
126
127
                        foreach ($activity->childNodes as $item) {
128
                            $currentItem[$item->nodeName] = $item->nodeValue;
129
                        }
130
131
                        $moduleName = isset($currentItem['modulename']) ? $currentItem['modulename'] : false;
132
                        switch ($moduleName) {
133
                            case 'forum':
134
                                require_once '../forum/forumfunction.inc.php';
135
                                $catForumValues = [];
136
137
                                // Read the current forum module xml.
138
                                $moduleDir = $currentItem['directory'];
139
                                $moduleXml = @file_get_contents($destinationDir.'/'.$moduleDir.'/'.$moduleName.'.xml');
0 ignored issues
show
Bug introduced by
Are you sure $moduleName of type mixed|false can be used in concatenation? ( Ignorable by Annotation )

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

139
                                $moduleXml = @file_get_contents($destinationDir.'/'.$moduleDir.'/'./** @scrutinizer ignore-type */ $moduleName.'.xml');
Loading history...
140
                                $moduleValues = $this->readForumModule($moduleXml);
141
142
                                // Create a Forum category based on Moodle forum type.
143
                                $catForumValues['forum_category_title'] = $moduleValues['type'];
144
                                $catForumValues['forum_category_comment'] = '';
145
                                $catId = store_forumcategory(
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $catId is correct as store_forumcategory($cat...es, $courseInfo, false) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
146
                                    $catForumValues,
147
                                    $courseInfo,
148
                                    false
149
                                );
150
                                $forumValues = [];
151
                                $forumValues['forum_title'] = $moduleValues['name'];
152
                                $forumValues['forum_image'] = '';
153
                                $forumValues['forum_comment'] = $moduleValues['intro'];
154
                                $forumValues['forum_category'] = $catId;
155
                                $forumValues['moderated'] = 0;
156
157
                                store_forum($forumValues, $courseInfo);
158
                                break;
159
                            case 'quiz':
160
                                // Read the current quiz module xml.
161
                                // The quiz case is the very complicate process of all the import.
162
                                // Please if you want to review the script, try to see the readingXML functions.
163
                                // The readingXML functions in this clases do all the mayor work here.
164
165
                                $moduleDir = $currentItem['directory'];
166
                                $moduleXml = @file_get_contents($destinationDir.'/'.$moduleDir.'/'.$moduleName.'.xml');
167
                                $questionsXml = @file_get_contents($destinationDir.'/questions.xml');
168
                                $moduleValues = $this->readQuizModule($moduleXml);
169
170
                                // At this point we got all the prepared resources from Moodle file
171
                                // $moduleValues variable contains all the necesary info to the quiz import
172
                                // var_dump($moduleValues); // <-- uncomment this to see the final array
173
174
                                $exercise = new Exercise($courseInfo['real_id']);
175
                                $title = Exercise::format_title_variable($moduleValues['name']);
176
                                $exercise->updateTitle($title);
177
                                $exercise->updateDescription($moduleValues['intro']);
178
                                $exercise->updateAttempts($moduleValues['attempts_number']);
179
                                $exercise->updateFeedbackType(0);
180
181
                                // Match shuffle question with chamilo
182
                                switch ($moduleValues['shufflequestions']) {
183
                                    case '0':
184
                                        $exercise->setRandom(0);
185
                                        break;
186
                                    case '1':
187
                                        $exercise->setRandom(-1);
188
                                        break;
189
                                    default:
190
                                        $exercise->setRandom(0);
191
                                }
192
                                $exercise->updateRandomAnswers($moduleValues['shuffleanswers']);
193
                                // @todo divide to minutes
194
                                $exercise->updateExpiredTime($moduleValues['timelimit']);
195
196
                                if ($moduleValues['questionsperpage'] == 1) {
197
                                    $exercise->updateType(2);
198
                                } else {
199
                                    $exercise->updateType(1);
200
                                }
201
202
                                // Create the new Quiz
203
                                $exercise->save();
204
205
                                // Ok, we got the Quiz and create it, now its time to add the Questions
206
                                foreach ($moduleValues['question_instances'] as $index => $question) {
207
                                    $questionsValues = $this->readMainQuestionsXml(
208
                                        $questionsXml,
209
                                        $question['questionid']
210
                                    );
211
                                    $moduleValues['question_instances'][$index] = $questionsValues;
212
                                    // Set Question Type from Moodle XML element <qtype>
213
                                    $qType = $moduleValues['question_instances'][$index]['qtype'];
214
                                    // Add the matched chamilo question type to the array
215
                                    $moduleValues['question_instances'][$index]['chamilo_qtype'] = $this->matchMoodleChamiloQuestionTypes($qType);
216
                                    $questionInstance = Question::getInstance(
217
                                        $moduleValues['question_instances'][$index]['chamilo_qtype']
218
                                    );
219
                                    if ($questionInstance) {
220
                                        $questionInstance->updateTitle(
221
                                            $moduleValues['question_instances'][$index]['name']
222
                                        );
223
                                        $questionText = $moduleValues['question_instances'][$index]['questiontext'];
224
225
                                        // Replace the path from @@PLUGINFILE@@ to a correct chamilo path
226
                                        $questionText = str_replace(
227
                                            '@@PLUGINFILE@@',
228
                                            '/courses/'.$coursePath.'/document/moodle',
229
                                            $questionText
230
                                        );
231
232
                                        if ($importedFiles) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $importedFiles 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...
233
                                            $this->fixPathInText($importedFiles, $questionText);
234
                                        }
235
236
                                        $questionInstance->updateDescription($questionText);
237
                                        $questionInstance->updateLevel(1);
238
                                        $questionInstance->updateCategory(0);
239
240
                                        //Save normal question if NOT media
241
                                        if ($questionInstance->type != MEDIA_QUESTION) {
242
                                            $questionInstance->save($exercise);
243
244
                                            // modify the exercise
245
                                            $exercise->addToList($questionInstance->id);
246
                                            $exercise->update_question_positions();
247
                                        }
248
249
                                        $questionList = $moduleValues['question_instances'][$index]['plugin_qtype_'.$qType.'_question'];
250
                                        $currentQuestion = $moduleValues['question_instances'][$index];
251
252
                                        $this->processAnswers(
253
                                            $exercise,
254
                                            $questionList,
255
                                            $qType,
256
                                            $questionInstance,
257
                                            $currentQuestion,
258
                                            $importedFiles
259
                                        );
260
                                    }
261
                                }
262
                                break;
263
                            case 'resource':
264
                                // Read the current resource module xml.
265
                                $moduleDir = $currentItem['directory'];
266
                                $moduleXml = @file_get_contents($destinationDir.'/'.$moduleDir.'/'.$moduleName.'.xml');
267
                                $filesXml = @file_get_contents($destinationDir.'/files.xml');
268
                                $moduleValues = $this->readResourceModule($moduleXml);
269
                                $mainFileModuleValues = $this->readMainFilesXml(
270
                                    $filesXml,
271
                                    $moduleValues['contextid']
272
                                );
273
                                $fileInfo = array_merge($moduleValues, $mainFileModuleValues, $currentItem);
0 ignored issues
show
Bug introduced by
It seems like $moduleValues can also be of type false; however, parameter $array1 of array_merge() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

273
                                $fileInfo = array_merge(/** @scrutinizer ignore-type */ $moduleValues, $mainFileModuleValues, $currentItem);
Loading history...
Bug introduced by
It seems like $mainFileModuleValues can also be of type false; however, parameter $array2 of array_merge() does only seem to accept null|array, maybe add an additional type check? ( Ignorable by Annotation )

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

273
                                $fileInfo = array_merge($moduleValues, /** @scrutinizer ignore-type */ $mainFileModuleValues, $currentItem);
Loading history...
274
                                $currentResourceFilePath = $destinationDir.'/files/';
275
                                $dirs = new RecursiveDirectoryIterator($currentResourceFilePath);
276
                                foreach (new RecursiveIteratorIterator($dirs) as $file) {
277
                                    if (is_file($file) && strpos($file, $fileInfo['contenthash']) !== false) {
278
                                        $files = [];
279
                                        $files['file']['name'] = $fileInfo['filename'];
280
                                        $files['file']['tmp_name'] = $file->getPathname();
281
                                        $files['file']['type'] = $fileInfo['mimetype'];
282
                                        $files['file']['error'] = 0;
283
                                        $files['file']['size'] = $fileInfo['filesize'];
284
                                        $files['file']['from_file'] = true;
285
                                        $files['file']['move_file'] = true;
286
                                        $_POST['language'] = $courseInfo['language'];
287
                                        $_POST['moodle_import'] = true;
288
289
                                        DocumentManager::upload_document(
290
                                            $files,
291
                                            '/moodle',
292
                                            $fileInfo['title'],
293
                                            '',
294
                                            null,
295
                                            null,
296
                                            true,
297
                                            true
298
                                        );
299
                                    }
300
                                }
301
302
                                break;
303
                            case 'url':
304
                                // Read the current url module xml.
305
                                $moduleDir = $currentItem['directory'];
306
                                $moduleXml = @file_get_contents($destinationDir.'/'.$moduleDir.'/'.$moduleName.'.xml');
307
                                $moduleValues = $this->readUrlModule($moduleXml);
308
                                $_POST['title'] = $moduleValues['name'];
309
                                $_POST['url'] = $moduleValues['externalurl'];
310
                                $_POST['description'] = $moduleValues['intro'];
311
                                $_POST['category_id'] = 0;
312
                                $_POST['target'] = '_blank';
313
314
                                Link::addlinkcategory("link");
315
                                break;
316
                        }
317
                    }
318
                }
319
            } else {
320
                removeDir($destinationDir);
321
                return false;
322
            }
323
        } else {
324
            return false;
325
        }
326
327
        removeDir($destinationDir);
328
329
        return $packageContent[$mainFileKey];
330
    }
331
332
    /**
333
     * Read and validate the forum module XML
334
     *
335
     * @param resource $moduleXml XML file
336
     * @return mixed | array if is a valid xml file, false otherwise
337
     */
338
    public function readForumModule($moduleXml)
339
    {
340
        $moduleDoc = new DOMDocument();
0 ignored issues
show
Bug introduced by
The call to DOMDocument::__construct() has too few arguments starting with version. ( Ignorable by Annotation )

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

340
        $moduleDoc = /** @scrutinizer ignore-call */ new DOMDocument();

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

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

Loading history...
341
        $moduleRes = @$moduleDoc->loadXML($moduleXml);
342
        if ($moduleRes) {
343
            $activities = $moduleDoc->getElementsByTagName('forum');
344
            $currentItem = [];
345
            foreach ($activities as $activity) {
346
                if ($activity->childNodes->length) {
347
                    foreach ($activity->childNodes as $item) {
348
                        $currentItem[$item->nodeName] = $item->nodeValue;
349
                    }
350
                }
351
            }
352
353
            return $currentItem;
354
        }
355
356
        return false;
357
    }
358
359
    /**
360
     * Read and validate the resource module XML
361
     *
362
     * @param resource $moduleXml XML file
363
     * @return mixed | array if is a valid xml file, false otherwise
364
     */
365
    public function readResourceModule($moduleXml)
366
    {
367
        $moduleDoc = new DOMDocument();
0 ignored issues
show
Bug introduced by
The call to DOMDocument::__construct() has too few arguments starting with version. ( Ignorable by Annotation )

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

367
        $moduleDoc = /** @scrutinizer ignore-call */ new DOMDocument();

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

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

Loading history...
368
        $moduleRes = @$moduleDoc->loadXML($moduleXml);
369
        if ($moduleRes) {
370
            $activities = $moduleDoc->getElementsByTagName('resource');
371
            $mainActivity = $moduleDoc->getElementsByTagName('activity');
372
            $contextId = $mainActivity->item(0)->getAttribute('contextid');
373
            $currentItem = [];
374
            foreach ($activities as $activity) {
375
                if ($activity->childNodes->length) {
376
                    foreach ($activity->childNodes as $item) {
377
                        $currentItem[$item->nodeName] = $item->nodeValue;
378
                    }
379
                }
380
            }
381
382
            $currentItem['contextid'] = $contextId;
383
384
            return $currentItem;
385
        }
386
387
        return false;
388
    }
389
390
    /**
391
     * Read and validate the url module XML
392
     *
393
     * @param resource $moduleXml XML file
394
     * @return mixed | array if is a valid xml file, false otherwise
395
     */
396
    public function readUrlModule($moduleXml)
397
    {
398
        $moduleDoc = new DOMDocument();
0 ignored issues
show
Bug introduced by
The call to DOMDocument::__construct() has too few arguments starting with version. ( Ignorable by Annotation )

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

398
        $moduleDoc = /** @scrutinizer ignore-call */ new DOMDocument();

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

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

Loading history...
399
        $moduleRes = @$moduleDoc->loadXML($moduleXml);
400
        if ($moduleRes) {
401
            $activities = $moduleDoc->getElementsByTagName('url');
402
            $currentItem = [];
403
            foreach ($activities as $activity) {
404
                if ($activity->childNodes->length) {
405
                    foreach ($activity->childNodes as $item) {
406
                        $currentItem[$item->nodeName] = $item->nodeValue;
407
                    }
408
                }
409
            }
410
411
            return $currentItem;
412
        }
413
414
        return false;
415
    }
416
417
    /**
418
     * Read and validate the quiz module XML
419
     *
420
     * @param resource $moduleXml XML file
421
     * @return mixed | array if is a valid xml file, false otherwise
422
     */
423
    public function readQuizModule($moduleXml)
424
    {
425
        $moduleDoc = new DOMDocument();
0 ignored issues
show
Bug introduced by
The call to DOMDocument::__construct() has too few arguments starting with version. ( Ignorable by Annotation )

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

425
        $moduleDoc = /** @scrutinizer ignore-call */ new DOMDocument();

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

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

Loading history...
426
        $moduleRes = @$moduleDoc->loadXML($moduleXml);
427
        if ($moduleRes) {
428
            $activities = $moduleDoc->getElementsByTagName('quiz');
429
            $currentItem = [];
430
            foreach ($activities as $activity) {
431
                if ($activity->childNodes->length) {
432
                    foreach ($activity->childNodes as $item) {
433
                        $currentItem[$item->nodeName] = $item->nodeValue;
434
                    }
435
                }
436
            }
437
438
            $questions = $moduleDoc->getElementsByTagName('question_instance');
439
440
            $questionList = [];
441
            $counter = 0;
442
            foreach ($questions as $question) {
443
                if ($question->childNodes->length) {
444
                    foreach ($question->childNodes as $item) {
445
                        $questionList[$counter][$item->nodeName] = $item->nodeValue;
446
                    }
447
                    $counter++;
448
                }
449
            }
450
            $currentItem['question_instances'] = $questionList;
451
            return $currentItem;
452
        }
453
454
        return false;
455
    }
456
457
    /**
458
     * Search the current file resource in main Files XML
459
     *
460
     * @param resource $filesXml XML file
461
     * @param int $contextId
462
     * @return mixed | array if is a valid xml file, false otherwise
463
     */
464
    public function readMainFilesXml($filesXml, $contextId)
465
    {
466
        $moduleDoc = new DOMDocument();
0 ignored issues
show
Bug introduced by
The call to DOMDocument::__construct() has too few arguments starting with version. ( Ignorable by Annotation )

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

466
        $moduleDoc = /** @scrutinizer ignore-call */ new DOMDocument();

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

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

Loading history...
467
        $moduleRes = @$moduleDoc->loadXML($filesXml);
468
        if ($moduleRes) {
469
            $activities = $moduleDoc->getElementsByTagName('file');
470
            $currentItem = [];
471
            foreach ($activities as $activity) {
472
                if ($activity->childNodes->length) {
473
                    $isThisItemThatIWant = false;
474
                    foreach ($activity->childNodes as $item) {
475
                        if (!$isThisItemThatIWant && $item->nodeName == 'contenthash') {
476
                            $currentItem['contenthash'] = $item->nodeValue;
477
                        }
478
                        if ($item->nodeName == 'contextid' &&
479
                            intval($item->nodeValue) == intval($contextId) && !$isThisItemThatIWant
480
                        ) {
481
                            $isThisItemThatIWant = true;
482
                            continue;
483
                        }
484
485
                        if ($isThisItemThatIWant && $item->nodeName == 'filename') {
486
                            $currentItem['filename'] = $item->nodeValue;
487
                        }
488
489
                        if ($isThisItemThatIWant && $item->nodeName == 'filesize') {
490
                            $currentItem['filesize'] = $item->nodeValue;
491
                        }
492
493
                        if ($isThisItemThatIWant && $item->nodeName == 'mimetype' &&
494
                            $item->nodeValue == 'document/unknown'
495
                        ) {
496
                            break;
497
                        }
498
499
                        if ($isThisItemThatIWant && $item->nodeName == 'mimetype' &&
500
                            $item->nodeValue !== 'document/unknown'
501
                        ) {
502
                            $currentItem['mimetype'] = $item->nodeValue;
503
                            break 2;
504
                        }
505
                    }
506
                }
507
            }
508
509
            return $currentItem;
510
        }
511
512
        return false;
513
    }
514
515
    /**
516
     * Search the current question resource in main Questions XML
517
     *
518
     * @param resource $questionsXml XML file
519
     * @param int $questionId
520
     * @return mixed | array if is a valid xml file, false otherwise
521
     */
522
    public function readMainQuestionsXml($questionsXml, $questionId)
523
    {
524
        $moduleDoc = new DOMDocument();
0 ignored issues
show
Bug introduced by
The call to DOMDocument::__construct() has too few arguments starting with version. ( Ignorable by Annotation )

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

524
        $moduleDoc = /** @scrutinizer ignore-call */ new DOMDocument();

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

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

Loading history...
525
        $moduleRes = @$moduleDoc->loadXML($questionsXml);
526
        if ($moduleRes) {
527
            $questions = $moduleDoc->getElementsByTagName('question');
528
            $currentItem = [];
529
            foreach ($questions as $question) {
530
                if (intval($question->getAttribute('id')) == $questionId) {
531
                    if ($question->childNodes->length) {
532
                        $currentItem['questionid'] = $questionId;
533
                        $questionType = '';
534
                        foreach ($question->childNodes as $item) {
535
                            $currentItem[$item->nodeName] = $item->nodeValue;
536
                            if ($item->nodeName == 'qtype') {
537
                                $questionType = $item->nodeValue;
538
                            }
539
540
                            if ($item->nodeName == 'plugin_qtype_'.$questionType.'_question') {
541
                                $answer = $item->getElementsByTagName($this->getQuestionTypeAnswersTag($questionType));
542
                                $currentItem['plugin_qtype_'.$questionType.'_question'] = [];
543
                                for ($i = 0; $i <= $answer->length - 1; $i++) {
544
                                    $currentItem['plugin_qtype_'.$questionType.'_question'][$i]['answerid'] = $answer->item($i)->getAttribute('id');
545
                                    foreach ($answer->item($i)->childNodes as $properties) {
546
                                        $currentItem['plugin_qtype_'.$questionType.'_question'][$i][$properties->nodeName] = $properties->nodeValue;
547
                                    }
548
                                }
549
550
                                $typeValues = $item->getElementsByTagName($this->getQuestionTypeOptionsTag($questionType));
551
                                for ($i = 0; $i <= $typeValues->length - 1; $i++) {
552
                                    foreach ($typeValues->item($i)->childNodes as $properties) {
553
                                        $currentItem[$questionType.'_values'][$properties->nodeName] = $properties->nodeValue;
554
                                        if ($properties->nodeName == 'sequence') {
555
                                            $sequence = $properties->nodeValue;
556
                                            $sequenceIds = explode(',', $sequence);
557
                                            foreach ($sequenceIds as $qId) {
558
                                                $questionMatch = $this->readMainQuestionsXml($questionsXml, $qId);
559
                                                $currentItem['plugin_qtype_'.$questionType.'_question'][] = $questionMatch;
560
                                            }
561
                                        }
562
                                    }
563
                                }
564
                            }
565
                        }
566
                    }
567
                }
568
            }
569
570
            $this->traverseArray($currentItem, ['#text', 'question_hints', 'tags']);
571
            return $currentItem;
572
        }
573
574
        return false;
575
    }
576
577
    /**
578
     * return the correct question type options tag
579
     *
580
     * @param string $questionType name
581
     * @return string question type tag
582
     */
583
    public function getQuestionTypeOptionsTag($questionType)
584
    {
585
        switch ($questionType) {
586
            case 'match':
587
            case 'ddmatch':
588
                return 'matchoptions';
589
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
590
            default:
591
                return $questionType;
592
                break;
593
        }
594
    }
595
596
    /**
597
     * return the correct question type answers tag
598
     *
599
     * @param string $questionType name
600
     * @return string question type tag
601
     */
602
    public function getQuestionTypeAnswersTag($questionType)
603
    {
604
        switch ($questionType) {
605
            case 'match':
606
            case 'ddmatch':
607
                return 'match';
608
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
609
            default:
610
                return 'answer';
611
                break;
612
        }
613
    }
614
615
    /**
616
     *
617
     * @param string $moodleQuestionType
618
     * @return integer Chamilo question type
619
     */
620
    public function matchMoodleChamiloQuestionTypes($moodleQuestionType)
621
    {
622
        switch ($moodleQuestionType) {
623
            case 'multichoice':
624
                return UNIQUE_ANSWER;
625
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
626
            case 'multianswer':
627
            case 'shortanswer':
628
            case 'match':
629
                return FILL_IN_BLANKS;
630
                break;
631
            case 'essay':
632
                return FREE_ANSWER;
633
                break;
634
            case 'truefalse':
635
                return UNIQUE_ANSWER_NO_OPTION;
636
                break;
637
        }
638
    }
639
640
    /**
641
     * Fix moodle files that contains spaces
642
     * @param array $importedFiles
643
     * @param string $text
644
     * @return mixed
645
     */
646
    public function fixPathInText($importedFiles, &$text)
647
    {
648
        if ($importedFiles) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $importedFiles 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...
649
            foreach ($importedFiles as $old => $new) {
650
                // Ofaj fix moodle file names
651
                // In some questions moodle text contains file with name like:
652
                // Bild%20Check-In-Formular%20Ausfu%CC%88llen.jpg"
653
                // rawurlencode function transforms '' (whitespace) to %20 and so on
654
                $text = str_replace(rawurlencode($old), $new, $text);
655
            }
656
        }
657
658
        return $text;
659
    }
660
661
    /**
662
     * Process Moodle Answers to Chamilo
663
     *
664
     * @param Exercise $exercise
665
     * @param array $questionList
666
     * @param string $questionType
667
     * @param Question $questionInstance Question/Answer instance
668
     * @param array $currentQuestion
669
     * @param array $importedFiles
670
     * @return integer db response
671
     */
672
    public function processAnswers(
673
        $exercise,
674
        $questionList,
675
        $questionType,
676
        $questionInstance,
677
        $currentQuestion,
678
        $importedFiles
679
    ) {
680
        switch ($questionType) {
681
            case 'multichoice':
682
                $objAnswer = new Answer($questionInstance->id);
683
                $questionWeighting = 0;
684
                foreach ($questionList as $slot => $answer) {
685
                    $this->processUniqueAnswer(
686
                        $objAnswer,
687
                        $answer,
688
                        $slot + 1,
689
                        $questionWeighting,
690
                        $importedFiles
691
                    );
692
                }
693
694
                // saves the answers into the data base
695
                $objAnswer->save();
696
                // sets the total weighting of the question
697
                $questionInstance->updateWeighting($questionWeighting);
698
                $questionInstance->save($exercise);
699
700
                return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the documented return type integer.
Loading history...
701
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
702
            case 'multianswer':
703
                $objAnswer = new Answer($questionInstance->id);
704
                $coursePath = api_get_course_path();
705
                $placeholder = str_replace(
706
                    '@@PLUGINFILE@@',
707
                    '/courses/'.$coursePath.'/document/moodle',
708
                    $currentQuestion['questiontext']
709
                );
710
                $optionsValues = [];
711
                foreach ($questionList as $slot => $subQuestion) {
712
                    $qtype = $subQuestion['qtype'];
713
                    $optionsValues[] = $this->processFillBlanks(
714
                        $objAnswer,
715
                        $qtype,
716
                        $subQuestion['plugin_qtype_'.$qtype.'_question'],
717
                        $placeholder,
718
                        $slot + 1,
719
                        $importedFiles
720
                    );
721
                }
722
723
                $answerOptionsWeight = '::';
724
                $answerOptionsSize = '';
725
                $questionWeighting = 0;
726
                foreach ($optionsValues as $index => $value) {
727
                    $questionWeighting += $value['weight'];
728
                    $answerOptionsWeight .= $value['weight'].',';
729
                    $answerOptionsSize .= $value['size'].',';
730
                }
731
732
                $answerOptionsWeight = substr($answerOptionsWeight, 0, -1);
733
                $answerOptionsSize = substr($answerOptionsSize, 0, -1);
734
                $answerOptions = $answerOptionsWeight.':'.$answerOptionsSize.':0@';
735
                $placeholder = $placeholder.PHP_EOL.$answerOptions;
736
737
                // This is a minor trick to clean the question description that in a multianswer is the main placeholder
738
                $questionInstance->updateDescription('');
739
                // sets the total weighting of the question
740
                $questionInstance->updateWeighting($questionWeighting);
741
                $questionInstance->save($exercise);
742
                $this->fixPathInText($importedFiles, $placeholder);
743
744
                // saves the answers into the data base
745
                $objAnswer->createAnswer($placeholder, 0, '', 0, 1);
746
                $objAnswer->save();
747
748
                return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the documented return type integer.
Loading history...
749
            case 'match':
750
                $objAnswer = new Answer($questionInstance->id);
751
                $placeholder = '';
752
753
                $optionsValues = $this->processFillBlanks(
754
                    $objAnswer,
755
                    'match',
756
                    $questionList,
757
                    $placeholder,
758
                    0,
759
                    $importedFiles
760
                );
761
762
                $answerOptionsWeight = '::';
763
                $answerOptionsSize = '';
764
                $questionWeighting = 0;
765
                foreach ($optionsValues as $index => $value) {
0 ignored issues
show
Bug introduced by
The expression $optionsValues of type integer is not traversable.
Loading history...
766
                    $questionWeighting += $value['weight'];
767
                    $answerOptionsWeight .= $value['weight'].',';
768
                    $answerOptionsSize .= $value['size'].',';
769
                }
770
771
                $answerOptionsWeight = substr($answerOptionsWeight, 0, -1);
772
                $answerOptionsSize = substr($answerOptionsSize, 0, -1);
773
                $answerOptions = $answerOptionsWeight.':'.$answerOptionsSize.':0@';
774
                $placeholder = $placeholder.PHP_EOL.$answerOptions;
775
776
                // sets the total weighting of the question
777
                $questionInstance->updateWeighting($questionWeighting);
778
                $questionInstance->save($exercise);
779
                // saves the answers into the database
780
                $this->fixPathInText($importedFiles, $placeholder);
781
                $objAnswer->createAnswer($placeholder, 0, '', 0, 1);
782
                $objAnswer->save();
783
784
                return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the documented return type integer.
Loading history...
785
                break;
786
            case 'shortanswer':
787
            case 'ddmatch':
788
                $questionWeighting = $currentQuestion['defaultmark'];
789
                $questionInstance->updateWeighting($questionWeighting);
790
                $questionInstance->updateDescription(get_lang('ThisQuestionIsNotSupportedYet'));
791
                $questionInstance->save($exercise);
792
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
793
                break;
794
            case 'essay':
795
                $questionWeighting = $currentQuestion['defaultmark'];
796
                $questionInstance->updateWeighting($questionWeighting);
797
                $questionInstance->save($exercise);
798
                return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the documented return type integer.
Loading history...
799
                break;
800
            case 'truefalse':
801
                $objAnswer = new Answer($questionInstance->id);
802
                $questionWeighting = 0;
803
                foreach ($questionList as $slot => $answer) {
804
                    $this->processTrueFalse(
805
                        $objAnswer,
806
                        $answer,
807
                        $slot + 1,
808
                        $questionWeighting,
809
                        $importedFiles
810
                    );
811
                }
812
813
                // saves the answers into the data base
814
                $objAnswer->save();
815
                // sets the total weighting of the question
816
                $questionInstance->updateWeighting($questionWeighting);
817
                $questionInstance->save($exercise);
818
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
819
                break;
820
            default:
821
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
822
                break;
823
        }
824
    }
825
826
    /**
827
     * Process Chamilo Unique Answer
828
     *
829
     * @param object $objAnswer
830
     * @param array $answerValues
831
     * @param integer $position
832
     * @param integer $questionWeighting
833
     * @param array $importedFiles
834
     * @return integer db response
835
     */
836
    public function processUniqueAnswer(
837
        $objAnswer,
838
        $answerValues,
839
        $position,
840
        &$questionWeighting,
841
        $importedFiles
842
    ) {
843
        $correct = intval($answerValues['fraction']) ? intval($answerValues['fraction']) : 0;
844
        $answer = $answerValues['answertext'];
845
        $comment = $answerValues['feedback'];
846
        $weighting = $answerValues['fraction'];
847
        $weighting = abs($weighting);
848
        if ($weighting > 0) {
849
            $questionWeighting += $weighting;
850
        }
851
        $goodAnswer = $correct ? true : false;
852
853
        $this->fixPathInText($importedFiles, $answer);
854
855
        $objAnswer->createAnswer(
856
            $answer,
857
            $goodAnswer,
858
            $comment,
859
            $weighting,
860
            $position,
861
            null,
862
            null,
863
            ''
864
        );
865
    }
866
867
    /**
868
     * Process Chamilo True False
869
     *
870
     * @param object $objAnswer
871
     * @param array $answerValues
872
     * @param integer $position
873
     * @param integer $questionWeighting
874
     * @param array $importedFiles
875
     *
876
     * @return integer db response
877
     */
878
    public function processTrueFalse(
879
        $objAnswer,
880
        $answerValues,
881
        $position,
882
        &$questionWeighting,
883
        $importedFiles
884
    ) {
885
        $correct = intval($answerValues['fraction']) ? intval($answerValues['fraction']) : 0;
886
        $answer = $answerValues['answertext'];
887
        $comment = $answerValues['feedback'];
888
        $weighting = $answerValues['fraction'];
889
        $weighting = abs($weighting);
890
        if ($weighting > 0) {
891
            $questionWeighting += $weighting;
892
        }
893
        $goodAnswer = $correct ? true : false;
894
895
        $this->fixPathInText($importedFiles, $answer);
896
897
        $objAnswer->createAnswer(
898
            $answer,
899
            $goodAnswer,
900
            $comment,
901
            $weighting,
902
            $position,
903
            null,
904
            null,
905
            ''
906
        );
907
    }
908
909
    /**
910
     * Process Chamilo FillBlanks
911
     *
912
     * @param object $objAnswer
913
     * @param array $questionType
914
     * @param array $answerValues
915
     * @param string $placeholder
916
     * @param integer $position
917
     * @param array $importedFiles
918
     * @return integer db response
919
     *
920
     */
921
    public function processFillBlanks(
922
        $objAnswer,
0 ignored issues
show
Unused Code introduced by
The parameter $objAnswer is not used and could be removed. ( Ignorable by Annotation )

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

922
        /** @scrutinizer ignore-unused */ $objAnswer,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
923
        $questionType,
924
        $answerValues,
925
        &$placeholder,
926
        $position,
927
        $importedFiles
0 ignored issues
show
Unused Code introduced by
The parameter $importedFiles is not used and could be removed. ( Ignorable by Annotation )

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

927
        /** @scrutinizer ignore-unused */ $importedFiles

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
928
    ) {
929
        $coursePath = api_get_course_path();
930
931
        switch ($questionType) {
932
            case 'multichoice':
933
                $optionsValues = [];
934
                $correctAnswer = '';
935
                $othersAnswer = '';
936
                foreach ($answerValues as $answer) {
937
                    $correct = intval($answer['fraction']);
938
                    if ($correct) {
939
                        $correctAnswer .= $answer['answertext'].'|';
940
                        $optionsValues['weight'] = $answer['fraction'];
941
                        $optionsValues['size'] = '200';
942
                    } else {
943
                        $othersAnswer .= $answer['answertext'].'|';
944
                    }
945
                }
946
                $currentAnswers = $correctAnswer.$othersAnswer;
947
                $currentAnswers = '['.substr($currentAnswers, 0, -1).']';
948
                $placeholder = str_replace("{#$position}", $currentAnswers, $placeholder);
949
950
                return $optionsValues;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $optionsValues returns the type array|array<mixed,mixed|string> which is incompatible with the documented return type integer.
Loading history...
951
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
952
            case 'shortanswer':
953
                $optionsValues = [];
954
                $correctAnswer = '';
955
                foreach ($answerValues as $answer) {
956
                    $correct = intval($answer['fraction']);
957
                    if ($correct) {
958
                        $correctAnswer .= $answer['answertext'];
959
                        $optionsValues['weight'] = $answer['fraction'];
960
                        $optionsValues['size'] = '200';
961
                    }
962
                }
963
964
                $currentAnswers = '['.$correctAnswer.']';
965
                $placeholder = str_replace("{#$position}", $currentAnswers, $placeholder);
966
967
                return $optionsValues;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $optionsValues returns the type array|array<mixed,mixed|string> which is incompatible with the documented return type integer.
Loading history...
968
                break;
969
            case 'match':
970
                $answers = [];
971
                // Here first we need to extract all the possible answers
972
                foreach ($answerValues as $slot => $answer) {
973
                    $answers[$slot] = $answer['answertext'];
974
                }
975
976
                // Now we set the order of the values matching the correct answer and set it to the first element
977
                $optionsValues = [];
978
                foreach ($answerValues as $slot => $answer) {
979
                    $correctAnswer = '';
980
                    $othersAnswers = '';
981
                    $correctAnswer .= $answer['answertext'].'|';
982
983
                    foreach ($answers as $other) {
984
                        if ($other !== $answer['answertext']) {
985
                            $othersAnswers .= $other.'|';
986
                        }
987
                    }
988
989
                    $optionsValues[$slot]['weight'] = 1;
990
                    $optionsValues[$slot]['size'] = '200';
991
992
                    $currentAnswers = htmlentities($correctAnswer.$othersAnswers);
993
                    $currentAnswers = '['.substr($currentAnswers, 0, -1).'] ';
994
                    $answer['questiontext'] = str_replace(
995
                        '@@PLUGINFILE@@',
996
                        '/courses/'.$coursePath.'/document/moodle',
997
                        $answer['questiontext']
998
                    );
999
1000
                    $placeholder .= '<p> '.strip_tags($answer['questiontext']).' '.$currentAnswers.' </p>';
1001
                }
1002
1003
                return $optionsValues;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $optionsValues returns the type array which is incompatible with the documented return type integer.
Loading history...
1004
1005
                break;
1006
            default:
1007
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
1008
                break;
1009
        }
1010
    }
1011
1012
    /**
1013
     * get All files associated with a question
1014
     *
1015
     * @param $filesXml
1016
     * @return array
1017
     */
1018
    public function getAllQuestionFiles($filesXml)
1019
    {
1020
        $moduleDoc = new DOMDocument();
0 ignored issues
show
Bug introduced by
The call to DOMDocument::__construct() has too few arguments starting with version. ( Ignorable by Annotation )

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

1020
        $moduleDoc = /** @scrutinizer ignore-call */ new DOMDocument();

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

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

Loading history...
1021
        $moduleRes = @$moduleDoc->loadXML($filesXml);
1022
        $allFiles = [];
1023
        if ($moduleRes) {
1024
            $activities = $moduleDoc->getElementsByTagName('file');
1025
            foreach ($activities as $activity) {
1026
                $currentItem = [];
1027
                $thisIsAnInvalidItem = false;
1028
1029
                if ($activity->childNodes->length) {
1030
                    foreach ($activity->childNodes as $item) {
1031
                        if ($item->nodeName == 'component' && $item->nodeValue == 'mod_resource') {
1032
                            $thisIsAnInvalidItem = true;
1033
                        }
1034
1035
                        if ($item->nodeName == 'contenthash') {
1036
                            $currentItem['contenthash'] = $item->nodeValue;
1037
                        }
1038
1039
                        if ($item->nodeName == 'filename') {
1040
                            $currentItem['filename'] = $item->nodeValue;
1041
                        }
1042
1043
                        if ($item->nodeName == 'filesize') {
1044
                            $currentItem['filesize'] = $item->nodeValue;
1045
                        }
1046
1047
                        if ($item->nodeName == 'mimetype' && $item->nodeValue == 'document/unknown') {
1048
                            $thisIsAnInvalidItem = true;
1049
                        }
1050
1051
                        if ($item->nodeName == 'mimetype' && $item->nodeValue !== 'document/unknown') {
1052
                            $currentItem['mimetype'] = $item->nodeValue;
1053
                        }
1054
                    }
1055
                }
1056
1057
                if (!$thisIsAnInvalidItem) {
1058
                    $allFiles[] = $currentItem;
1059
                }
1060
            }
1061
        }
1062
1063
        return $allFiles;
1064
    }
1065
1066
1067
    /**
1068
     * Litle utility to delete the unuseful tags
1069
     *
1070
     * @param $array
1071
     * @param $keys
1072
     */
1073
    public function traverseArray(&$array, $keys)
1074
    {
1075
        foreach ($array as $key => &$value) {
1076
            if (is_array($value)) {
1077
                $this->traverseArray($value, $keys);
1078
            } else {
1079
                if (in_array($key, $keys)) {
1080
                    unset($array[$key]);
1081
                }
1082
            }
1083
        }
1084
    }
1085
}
1086