Cc13Quiz::getDefaultgrade()   A
last analyzed

Complexity

Conditions 5
Paths 3

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 3
nop 2
dl 0
loc 15
rs 9.6111
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
class Cc13Quiz extends Cc13Entities
5
{
6
    /**
7
     * Get all data from the object instance (coming from the xml file) into a clean array.
8
     *
9
     * @return array
10
     */
11
    public function generateData()
12
    {
13
        $data = [];
14
        $instances = $this->generateInstances();
15
        if (!empty($instances)) {
16
            foreach ($instances as $instance) {
17
                if ($instance['is_question_bank'] == 0) {
18
                    $data[] = $this->getQuizData($instance);
19
                }
20
            }
21
        }
22
23
        return $data;
24
    }
25
26
    /**
27
     * Create a quiz based on the information available in the assessment structure.
28
     *
29
     * @param $quiz
30
     *
31
     * @return void
32
     */
33
    public function storeQuiz($quiz)
34
    {
35
        $token = '/\$(?:IMS|1EdTech)[-_]CC[-_]FILEBASE\$\.\.\//';
36
        $courseInfo = api_get_course_info();
37
        // Replace by the path in documents in which we place all relevant CC files
38
        $replacementPath = '/courses/'.$courseInfo['directory'].'/document/commoncartridge/';
39
        $exercise = new Exercise($courseInfo['real_id']);
40
        $title = Exercise::format_title_variable($quiz['title']);
41
        $exercise->updateTitle($title);
42
        $description = preg_replace($token, $replacementPath, $quiz['description']);
43
        $exercise->updateDescription($description);
44
        $exercise->updateAttempts($quiz['max_attempts']);
45
        $exercise->updateFeedbackType(0);
46
47
        $exercise->setRandom(0);
48
        $exercise->updateRandomAnswers(!empty($moduleValues['shuffleanswers']));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $moduleValues seems to never exist and therefore empty should always be true.
Loading history...
49
        $exercise->updateExpiredTime((int) $quiz['timelimit']);
50
        $exercise->updateType(1);
51
52
        // Create the new Quiz
53
        $exercise->save();
54
55
        if (!empty($quiz['questions'])) {
56
            foreach ($quiz['questions'] as $question) {
57
                $qtype = $question['type'];
58
59
                $types = [
60
                    'unique_answer' => UNIQUE_ANSWER,
61
                    'multiple_answer' => MULTIPLE_ANSWER,
62
                    'fib' => FILL_IN_BLANKS,
63
                    'essay' => FREE_ANSWER,
64
                ];
65
                $questionType = $types[$qtype];
66
67
                $questionInstance = Question::getInstance($questionType);
68
                if (empty($questionInstance)) {
69
                    continue;
70
                }
71
72
                $questionInstance->updateTitle(substr(Security::remove_XSS(strip_tags_blacklist($question['title'], ['br', 'p'])), 0, 20));
73
                $questionText = Security::remove_XSS(strip_tags_blacklist($question['title'], ['br', 'p']));
74
                // Replace the path from $1EdTech-CC-FILEBASE$ to a correct chamilo path
75
                $questionText = preg_replace($token, $replacementPath, $questionText);
76
                $questionInstance->updateDescription($questionText);
77
78
                $questionInstance->updateLevel(1);
79
                $questionInstance->updateCategory(0);
80
81
                //Save normal question if NOT media
82
                if ($questionInstance->type != MEDIA_QUESTION) {
83
                    $questionInstance->save($exercise);
84
                    // modify the exercise
85
                    $exercise->addToList($questionInstance->iid);
86
                    $exercise->update_question_positions();
87
                }
88
89
                if ($qtype == 'unique_answer') {
90
                    $objAnswer = new Answer($questionInstance->iid);
91
                    $questionWeighting = 0;
92
                    foreach ($question['answers'] as $slot => $answerValues) {
93
                        $correct = $answerValues['score'] ? (int) $answerValues['score'] : 0;
94
                        $answer = Security::remove_XSS(preg_replace($token, $replacementPath, $answerValues['title']));
95
                        $comment = Security::remove_XSS(preg_replace($token, $replacementPath, $answerValues['feedback']));
96
                        $weighting = $answerValues['score'];
97
                        $weighting = abs($weighting);
98
                        if ($weighting > 0) {
99
                            $questionWeighting += $weighting;
100
                        }
101
                        $goodAnswer = $correct ? true : false;
102
103
                        $objAnswer->createAnswer(
104
                            $answer,
105
                            $goodAnswer,
106
                            $comment,
107
                            $weighting,
108
                            $slot + 1,
109
                            null,
110
                            null,
111
                            ''
112
                        );
113
                    }
114
                    // saves the answers into the database
115
                    $objAnswer->save();
116
                    // sets the total weighting of the question
117
                    $questionInstance->updateWeighting($questionWeighting);
118
                    $questionInstance->save($exercise);
119
                } else {
120
                    $objAnswer = new Answer($questionInstance->iid);
121
                    $questionWeighting = 0;
122
                    if (is_array($question['answers'])) {
123
                        foreach ($question['answers'] as $slot => $answerValues) {
124
                            $answer = Security::remove_XSS(preg_replace($token, $replacementPath, $answerValues['title']));
125
                            $comment = Security::remove_XSS(preg_replace($token, $replacementPath, $answerValues['feedback']));
126
                            $weighting = $answerValues['score'];
127
                            if ($weighting > 0) {
128
                                $questionWeighting += $weighting;
129
                            }
130
                            $goodAnswer = $weighting > 0;
131
132
                            $objAnswer->createAnswer(
133
                                $answer,
134
                                $goodAnswer,
135
                                $comment,
136
                                $weighting,
137
                                $slot + 1,
138
                                null,
139
                                null,
140
                                ''
141
                            );
142
                        }
143
                    } elseif ($qtype == 'essay') {
144
                        $questionWeighting = $question['ponderation'];
145
                    }
146
147
                    // saves the answers into the database
148
                    $objAnswer->save();
149
                    // sets the total weighting of the question
150
                    $questionInstance->updateWeighting($questionWeighting);
151
                    $questionInstance->save($exercise);
152
                }
153
            }
154
        }
155
    }
156
157
    public function storeQuizzes($quizzes)
158
    {
159
        if (!empty($quizzes)) {
160
            foreach ($quizzes as $quiz) {
161
                $this->storeQuiz($quiz);
162
            }
163
        }
164
    }
165
166
    public function getQuizData($instance)
167
    {
168
        $values = [];
169
        if (!empty($instance)) {
170
            $questions = [];
171
            if (!empty($instance['questions'])) {
172
                foreach ($instance['questions'] as $question) {
173
                    $questions[$question['id']] = [
174
                        'title' => $question['title'],
175
                        'type' => $question['qtype'],
176
                        'ponderation' => $question['defaultgrade'],
177
                        'answers' => $question['answers'],
178
                    ];
179
                }
180
            }
181
            $values = [
182
                'id' => $instance['id'],
183
                'title' => $instance['title'],
184
                'description' => $instance['description'],
185
                'timelimit' => $instance['options']['timelimit'],
186
                'max_attempts' => $instance['options']['max_attempts'],
187
                'questions' => $questions,
188
            ];
189
        }
190
191
        return $values;
192
    }
193
194
    private function generateInstances()
195
    {
196
        $lastInstanceId = 0;
197
        $lastQuestionId = 0;
198
        $lastAnswerId = 0;
199
200
        $instances = [];
201
202
        $types = [TOOL_TYPE_QUIZ];
203
204
        foreach ($types as $type) {
205
            if (!empty(Cc1p3Convert::$instances['instances'][$type])) {
206
                foreach (Cc1p3Convert::$instances['instances'][$type] as $instance) {
207
                    if ($type == TOOL_TYPE_QUIZ) {
208
                        $is_question_bank = 0;
209
                    } else {
210
                        $is_question_bank = 1;
211
                    }
212
213
                    // Get the path of the assessment.xml file
214
                    $assessmentFile = $this->getExternalXml($instance['resource_identifier']);
215
216
                    if (!empty($assessmentFile)) {
217
                        $assessment = $this->loadXmlResource(Cc1p3Convert::$pathToManifestFolder.DIRECTORY_SEPARATOR.$assessmentFile);
218
219
                        if (!empty($assessment)) {
220
                            $replaceValues = ['unlimited' => 0];
221
222
                            $questions = $this->getQuestions($assessment, $lastQuestionId, $lastAnswerId, dirname($assessmentFile), $is_question_bank);
223
                            $questionCount = count($questions);
224
225
                            if (!empty($questionCount)) {
226
                                $lastInstanceId++;
227
228
                                $instances[$instance['resource_identifier']]['questions'] = $questions;
229
                                $instances[$instance['resource_identifier']]['id'] = $lastInstanceId;
230
                                $instances[$instance['resource_identifier']]['title'] = $instance['title'];
231
                                $instances[$instance['resource_identifier']]['description'] = $this->getQuizDescription($assessment);
232
                                $instances[$instance['resource_identifier']]['is_question_bank'] = $is_question_bank;
233
                                $instances[$instance['resource_identifier']]['options']['timelimit'] = $this->getGlobalConfig($assessment, 'qmd_timelimit', 0);
234
                                $instances[$instance['resource_identifier']]['options']['max_attempts'] = $this->getGlobalConfig($assessment, 'cc_maxattempts', 0, $replaceValues);
235
                            }
236
                        }
237
                    }
238
                }
239
            }
240
        }
241
242
        return $instances;
243
    }
244
245
    private function getGlobalConfig($assessment, $option, $defaultValue, $replaceValues = '')
246
    {
247
        $xpath = Cc1p3Convert::newxPath($assessment, Cc1p3Convert::getquizns());
248
        $metadata = $xpath->query('/xmlns:questestinterop/xmlns:assessment/xmlns:qtimetadata/xmlns:qtimetadatafield');
249
250
        foreach ($metadata as $field) {
251
            $fieldLabel = $xpath->query('xmlns:fieldlabel', $field);
252
            $fieldLabel = !empty($fieldLabel->item(0)->nodeValue) ? $fieldLabel->item(0)->nodeValue : '';
253
254
            if (strtolower($fieldLabel) == strtolower($option)) {
255
                $fieldEntry = $xpath->query('xmlns:fieldentry', $field);
256
                $response = !empty($fieldEntry->item(0)->nodeValue) ? $fieldEntry->item(0)->nodeValue : '';
257
            }
258
        }
259
260
        $response = !empty($response) ? trim($response) : '';
261
262
        if (!empty($replaceValues)) {
263
            foreach ($replaceValues as $key => $value) {
264
                $response = ($key == $response) ? $value : $response;
265
            }
266
        }
267
268
        $response = empty($response) ? $defaultValue : $response;
269
270
        return $response;
271
    }
272
273
    private function getQuizDescription(DOMDocument $assessment): string
274
    {
275
        $xpath = Cc1p3Convert::newxPath($assessment, Cc1p3Convert::getquizns());
276
        $fieldEntry = $xpath->query('/xmlns:questestinterop/xmlns:assessment/xmlns:rubric/xmlns:material/xmlns:mattext');
277
        $response = !empty($fieldEntry->item(0)->nodeValue) ? $fieldEntry->item(0)->nodeValue : '';
278
279
        return $response;
280
    }
281
282
    private function getQuestions($assessment, &$lastQuestionId, &$last_answer_id, $rootPath, $is_question_bank)
283
    {
284
        $questions = [];
285
286
        $xpath = Cc1p3Convert::newxPath($assessment, Cc1p3Convert::getquizns());
287
288
        if (!$is_question_bank) {
289
            $questionsItems = $xpath->query('/xmlns:questestinterop/xmlns:assessment/xmlns:section/xmlns:item');
290
        } else {
291
            $questionsItems = $xpath->query('/xmlns:questestinterop/xmlns:objectbank/xmlns:item');
292
        }
293
294
        foreach ($questionsItems as $question_item) {
295
            $countQuestions = $xpath->evaluate('count(xmlns:presentation/xmlns:flow/xmlns:material/xmlns:mattext)', $question_item);
296
297
            if ($countQuestions == 0) {
298
                $questionTitle = $xpath->query('xmlns:presentation/xmlns:material/xmlns:mattext', $question_item);
299
            } else {
300
                $questionTitle = $xpath->query('xmlns:presentation/xmlns:flow/xmlns:material/xmlns:mattext', $question_item);
301
            }
302
303
            $questionTitle = !empty($questionTitle->item(0)->nodeValue) ? $questionTitle->item(0)->nodeValue : '';
304
305
            $questionIdentifier = $xpath->query('@ident', $question_item);
306
            $questionIdentifier = !empty($questionIdentifier->item(0)->nodeValue) ? $questionIdentifier->item(0)->nodeValue : '';
307
308
            if (!empty($questionIdentifier)) {
309
                $questionType = $this->getQuestionType($questionIdentifier, $assessment);
310
311
                if (!empty($questionType['qtype'])) {
312
                    $lastQuestionId++;
313
314
                    $questions[$questionIdentifier]['id'] = $lastQuestionId;
315
316
                    $questionTitle = $this->updateSources($questionTitle, $rootPath);
317
                    $questionTitle = !empty($questionTitle) ? str_replace("%24", "\$", $this->includeTitles($questionTitle)) : '';
318
319
                    $questionname = $xpath->query('@title', $question_item);
320
                    $questionname = !empty($questionname->item(0)->nodeValue) ? $questionname->item(0)->nodeValue : '';
321
322
                    $questions[$questionIdentifier]['title'] = $questionTitle;
323
                    $questions[$questionIdentifier]['name'] = $questionname;
324
                    $questions[$questionIdentifier]['identifier'] = $questionIdentifier;
325
                    $questions[$questionIdentifier]['qtype'] = $questionType['qtype'];
326
                    $questions[$questionIdentifier]['cc_type'] = $questionType['cc'];
327
                    $questions[$questionIdentifier]['feedback'] = $this->getGeneralFeedback($assessment, $questionIdentifier);
328
                    $questions[$questionIdentifier]['defaultgrade'] = $this->getDefaultgrade($assessment, $questionIdentifier);
329
                    $questions[$questionIdentifier]['answers'] = $this->getAnswers($questionIdentifier, $assessment, $lastAnswerId);
330
                }
331
            }
332
        }
333
334
        $questions = !empty($questions) ? $questions : '';
335
336
        return $questions;
337
    }
338
339
    private function getDefaultgrade($assessment, $questionIdentifier)
340
    {
341
        $result = 1;
342
        $xpath = Cc1p3Convert::newxPath($assessment, Cc1p3Convert::getquizns());
343
        $query = '//xmlns:item[@ident="'.$questionIdentifier.'"]';
344
        $query .= '//xmlns:qtimetadatafield[xmlns:fieldlabel="cc_weighting"]/xmlns:fieldentry';
345
        $defgrade = $xpath->query($query);
346
        if (!empty($defgrade) && ($defgrade->length > 0)) {
347
            $resp = (int) $defgrade->item(0)->nodeValue;
348
            if ($resp >= 0 && $resp <= 99) {
349
                $result = $resp;
350
            }
351
        }
352
353
        return $result;
354
    }
355
356
    private function getGeneralFeedback($assessment, $questionIdentifier)
357
    {
358
        $xpath = Cc1p3Convert::newxPath($assessment, Cc1p3Convert::getquizns());
359
360
        $respconditions = $xpath->query('//xmlns:item[@ident="'.$questionIdentifier.'"]/xmlns:resprocessing/xmlns:respcondition');
361
362
        if (!empty($respconditions)) {
363
            foreach ($respconditions as $respcondition) {
364
                $continue = $respcondition->getAttributeNode('continue');
365
                $continue = !empty($continue->nodeValue) ? strtolower($continue->nodeValue) : '';
366
367
                if ($continue == 'yes') {
368
                    $displayFeedback = $xpath->query('xmlns:displayfeedback', $respcondition);
369
370
                    if (!empty($displayFeedback)) {
371
                        foreach ($displayFeedback as $feedback) {
372
                            $feedbackIdentifier = $feedback->getAttributeNode('linkrefid');
373
                            $feedbackIdentifier = !empty($feedbackIdentifier->nodeValue) ? $feedbackIdentifier->nodeValue : '';
374
375
                            if (!empty($feedbackIdentifier)) {
376
                                $feedbackIdentifiers[] = $feedbackIdentifier;
377
                            }
378
                        }
379
                    }
380
                }
381
            }
382
        }
383
384
        $feedback = '';
385
        $feedbackIdentifiers = empty($feedbackIdentifiers) ? '' : $feedbackIdentifiers;
386
387
        if (!empty($feedbackIdentifiers)) {
388
            foreach ($feedbackIdentifiers as $feedbackIdentifier) {
389
                $feedbacks = $xpath->query('//xmlns:item[@ident="'.$questionIdentifier.'"]/xmlns:itemfeedback[@ident="'.$feedbackIdentifier.'"]/xmlns:flow_mat/xmlns:material/xmlns:mattext');
390
                $feedback .= !empty($feedbacks->item(0)->nodeValue) ? $feedbacks->item(0)->nodeValue.' ' : '';
391
            }
392
        }
393
394
        return $feedback;
395
    }
396
397
    private function getFeedback($assessment, $identifier, $itemIdentifier, $questionType)
398
    {
399
        $xpath = Cc1p3Convert::newxPath($assessment, Cc1p3Convert::getquizns());
400
401
        $resourceProcessing = $xpath->query('//xmlns:item[@ident="'.$itemIdentifier.'"]/xmlns:resprocessing/xmlns:respcondition');
402
403
        if (!empty($resourceProcessing)) {
404
            foreach ($resourceProcessing as $response) {
405
                $varequal = $xpath->query('xmlns:conditionvar/xmlns:varequal', $response);
406
                $varequal = !empty($varequal->item(0)->nodeValue) ? $varequal->item(0)->nodeValue : '';
407
408
                if (strtolower($varequal) == strtolower($identifier) || ($questionType == CC_QUIZ_ESSAY)) {
409
                    $displayFeedback = $xpath->query('xmlns:displayfeedback', $response);
410
411
                    if (!empty($displayFeedback)) {
412
                        foreach ($displayFeedback as $feedback) {
413
                            $feedbackIdentifier = $feedback->getAttributeNode('linkrefid');
414
                            $feedbackIdentifier = !empty($feedbackIdentifier->nodeValue) ? $feedbackIdentifier->nodeValue : '';
415
416
                            if (!empty($feedbackIdentifier)) {
417
                                $feedbackIdentifiers[] = $feedbackIdentifier;
418
                            }
419
                        }
420
                    }
421
                }
422
            }
423
        }
424
425
        $feedback = '';
426
        $feedbackIdentifiers = empty($feedbackIdentifiers) ? '' : $feedbackIdentifiers;
427
428
        if (!empty($feedbackIdentifiers)) {
429
            foreach ($feedbackIdentifiers as $feedbackIdentifier) {
430
                $feedbacks = $xpath->query('//xmlns:item[@ident="'.$itemIdentifier.'"]/xmlns:itemfeedback[@ident="'.$feedbackIdentifier.'"]/xmlns:flow_mat/xmlns:material/xmlns:mattext');
431
                $feedback .= !empty($feedbacks->item(0)->nodeValue) ? $feedbacks->item(0)->nodeValue.' ' : '';
432
            }
433
        }
434
435
        return $feedback;
436
    }
437
438
    private function getAnswersFib($questionIdentifier, $identifier, $assessment, &$lastAnswerId)
439
    {
440
        $xpath = Cc1p3Convert::newxPath($assessment, Cc1p3Convert::getquizns());
441
442
        $correctanswersfib = [];
443
        $incorrectanswersfib = [];
444
445
        $responseItems = $xpath->query('//xmlns:item[@ident="'.$questionIdentifier.'"]/xmlns:resprocessing/xmlns:respcondition');
446
447
        $correctrespcond = $xpath->query('//xmlns:item[@ident="'.$questionIdentifier.'"]/xmlns:resprocessing/xmlns:respcondition/xmlns:setvar[text()="100"]/..');
448
        $correctanswers = $xpath->query('xmlns:conditionvar/xmlns:varequal', $correctrespcond->item(0));
449
450
        // Correct answers.
451
        foreach ($correctanswers as $correctans) {
452
            $answertitle = !empty($correctans->nodeValue) ? $correctans->nodeValue : '';
453
            if (empty($answertitle)) {
454
                continue;
455
            }
456
457
            $lastAnswerId++;
458
459
            $correctanswersfib[$answertitle] = [
460
                'id' => $lastAnswerId,
461
                'title' => $answertitle,
462
                'score' => 1,
463
                'feedback' => '',
464
                'case' => 0, ];
465
        }
466
467
        // Handle incorrect answers and feedback for all items.
468
        foreach ($responseItems as $response_item) {
469
            $setvar = $xpath->query('xmlns:setvar', $response_item);
470
            if (!empty($setvar->length) && $setvar->item(0)->nodeValue == '100') {
471
                // Skip the correct answer responsecondition.
472
                continue;
473
            }
474
475
            $varequal = $xpath->query('xmlns:conditionvar/xmlns:varequal', $response_item);
476
            if (empty($varequal->length)) {
477
                // Skip respcondition elements that don't have varequal containing an answer
478
                continue;
479
            }
480
            $answerTitle = !empty($varequal->item(0)->nodeValue) ? $varequal->item(0)->nodeValue : '';
481
482
            $displayFeedback = $xpath->query('xmlns:displayfeedback', $response_item);
483
484
            unset($feedbackIdentifiers);
485
486
            if (!empty($displayFeedback)) {
487
                foreach ($displayFeedback as $feedback) {
488
                    $feedbackIdentifier = $feedback->getAttributeNode('linkrefid');
489
                    $feedbackIdentifier = !empty($feedbackIdentifier->nodeValue) ? $feedbackIdentifier->nodeValue : '';
490
491
                    if (!empty($feedbackIdentifier)) {
492
                        $feedbackIdentifiers[] = $feedbackIdentifier;
493
                    }
494
                }
495
            }
496
497
            $feedback = '';
498
            $feedbackIdentifiers = empty($feedbackIdentifiers) ? '' : $feedbackIdentifiers;
499
500
            if (!empty($feedbackIdentifiers)) {
501
                foreach ($feedbackIdentifiers as $feedbackIdentifier) {
502
                    $feedbacks = $xpath->query('//xmlns:item[@ident="'.$questionIdentifier.'"]/xmlns:itemfeedback[@ident="'.$feedbackIdentifier.'"]/xmlns:flow_mat/xmlns:material/xmlns:mattext');
503
                    $feedback .= !empty($feedbacks->item(0)->nodeValue) ? $feedbacks->item(0)->nodeValue.' ' : '';
504
                }
505
            }
506
507
            if (array_key_exists($answerTitle, $correctanswersfib)) {
508
                // Already a correct answer, just need the feedback for the correct answer.
509
                $correctanswerfib[$answerTitle]['feedback'] = $feedback;
510
            } else {
511
                // Need to add an incorrect answer.
512
                $lastAnswerId++;
513
                $incorrectanswersfib[] = [
514
                    'id' => $lastAnswerId,
515
                    'title' => $answerTitle,
516
                    'score' => 0,
517
                    'feedback' => $feedback,
518
                    'case' => 0, ];
519
            }
520
        }
521
522
        $answersFib = array_merge($correctanswersfib, $incorrectanswersfib);
523
        $answersFib = empty($answersFib) ? '' : $answersFib;
524
525
        return $answersFib;
526
    }
527
528
    private function getAnswersPatternMatch($questionIdentifier, $identifier, $assessment, &$lastAnswerId)
529
    {
530
        $xpath = Cc1p3Convert::newxPath($assessment, Cc1p3Convert::getquizns());
531
532
        $answersFib = [];
533
534
        $responseItems = $xpath->query('//xmlns:item[@ident="'.$questionIdentifier.'"]/xmlns:resprocessing/xmlns:respcondition');
535
536
        foreach ($responseItems as $response_item) {
537
            $setvar = $xpath->query('xmlns:setvar', $response_item);
538
            $setvar = is_object($setvar->item(0)) ? $setvar->item(0)->nodeValue : '';
539
540
            if ($setvar != '') {
541
                $lastAnswerId++;
542
543
                $answerTitle = $xpath->query('xmlns:conditionvar/xmlns:varequal[@respident="'.$identifier.'"]', $response_item);
544
                $answerTitle = !empty($answerTitle->item(0)->nodeValue) ? $answerTitle->item(0)->nodeValue : '';
545
546
                if (empty($answerTitle)) {
547
                    $answerTitle = $xpath->query('xmlns:conditionvar/xmlns:varsubstring[@respident="'.$identifier.'"]', $response_item);
548
                    $answerTitle = !empty($answerTitle->item(0)->nodeValue) ? '*'.$answerTitle->item(0)->nodeValue.'*' : '';
549
                }
550
551
                if (empty($answerTitle)) {
552
                    $answerTitle = '*';
553
                }
554
555
                $case = $xpath->query('xmlns:conditionvar/xmlns:varequal/@case', $response_item);
556
                $case = is_object($case->item(0)) ? $case->item(0)->nodeValue : 'no'
557
                                    ;
558
                $case = strtolower($case) == 'yes' ? 1 :
559
                            0;
560
561
                $displayFeedback = $xpath->query('xmlns:displayfeedback', $response_item);
562
563
                unset($feedbackIdentifiers);
564
565
                if (!empty($displayFeedback)) {
566
                    foreach ($displayFeedback as $feedback) {
567
                        $feedbackIdentifier = $feedback->getAttributeNode('linkrefid');
568
                        $feedbackIdentifier = !empty($feedbackIdentifier->nodeValue) ? $feedbackIdentifier->nodeValue : '';
569
570
                        if (!empty($feedbackIdentifier)) {
571
                            $feedbackIdentifiers[] = $feedbackIdentifier;
572
                        }
573
                    }
574
                }
575
576
                $feedback = '';
577
                $feedbackIdentifiers = empty($feedbackIdentifiers) ? '' : $feedbackIdentifiers;
578
579
                if (!empty($feedbackIdentifiers)) {
580
                    foreach ($feedbackIdentifiers as $feedbackIdentifier) {
581
                        $feedbacks = $xpath->query('//xmlns:item[@ident="'.$questionIdentifier.'"]/xmlns:itemfeedback[@ident="'.$feedbackIdentifier.'"]/xmlns:flow_mat/xmlns:material/xmlns:mattext');
582
                        $feedback .= !empty($feedbacks->item(0)->nodeValue) ? $feedbacks->item(0)->nodeValue.' ' : '';
583
                    }
584
                }
585
586
                $answersFib[] = ['id' => $lastAnswerId,
587
                                       'title' => $answerTitle,
588
                                       'score' => $setvar,
589
                                       'feedback' => $feedback,
590
                                       'case' => $case, ];
591
            }
592
        }
593
594
        $answersFib = empty($answersFib) ? '' : $answersFib;
595
596
        return $answersFib;
597
    }
598
599
    private function getAnswers($identifier, $assessment, &$lastAnswerId)
600
    {
601
        $xpath = Cc1p3Convert::newxPath($assessment, Cc1p3Convert::getquizns());
602
603
        $answers = [];
604
605
        $questionCcType = $this->getQuestionType($identifier, $assessment);
606
        $questionCcType = $questionCcType['cc'];
607
        $isMultiresponse = ($questionCcType == CC_QUIZ_MULTIPLE_RESPONSE);
608
609
        if ($questionCcType == CC_QUIZ_MULTIPLE_CHOICE || $isMultiresponse || $questionCcType == CC_QUIZ_TRUE_FALSE) {
610
            $queryAnswers = '//xmlns:item[@ident="'.$identifier.'"]/xmlns:presentation/xmlns:response_lid/xmlns:render_choice/xmlns:response_label';
611
            $queryAnswersWithFlow = '//xmlns:item[@ident="'.$identifier.'"]/xmlns:presentation/xmlns:flow/xmlns:response_lid/xmlns:render_choice/xmlns:response_label';
612
613
            $queryIndentifer = '@ident';
614
            $queryTitle = 'xmlns:material/xmlns:mattext';
615
        }
616
617
        if ($questionCcType == CC_QUIZ_ESSAY) {
618
            $queryAnswers = '//xmlns:item[@ident="'.$identifier.'"]/xmlns:presentation/xmlns:response_str';
619
            $queryAnswersWithFlow = '//xmlns:item[@ident="'.$identifier.'"]/xmlns:presentation/xmlns:flow/xmlns:response_str';
620
621
            $queryIndentifer = '@ident';
622
            $queryTitle = 'xmlns:render_fib';
623
        }
624
625
        if ($questionCcType == CC_QUIZ_FIB || $questionCcType == CC_QUIZ_PATTERN_MACHT) {
626
            $xpathQuery = '//xmlns:item[@ident="'.$identifier.'"]/xmlns:presentation/xmlns:response_str/@ident';
627
            $xpathQueryWithFlow = '//xmlns:item[@ident="'.$identifier.'"]/xmlns:presentation/xmlns:flow/xmlns:response_str/@ident';
628
629
            $countResponse = $xpath->evaluate('count('.$xpathQueryWithFlow.')');
630
631
            if ($countResponse == 0) {
632
                $answerIdentifier = $xpath->query($xpathQuery);
633
            } else {
634
                $answerIdentifier = $xpath->query($xpathQueryWithFlow);
635
            }
636
637
            $answerIdentifier = !empty($answerIdentifier->item(0)->nodeValue) ? $answerIdentifier->item(0)->nodeValue : '';
638
639
            if ($questionCcType == CC_QUIZ_FIB) {
640
                $answers = $this->getAnswersFib($identifier, $answerIdentifier, $assessment, $lastAnswerId);
641
            } else {
642
                $answers = $this->getAnswersPatternMatch($identifier, $answerIdentifier, $assessment, $lastAnswerId);
643
            }
644
        } else {
645
            $countResponse = $xpath->evaluate('count('.$queryAnswersWithFlow.')');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $queryAnswersWithFlow does not seem to be defined for all execution paths leading up to this point.
Loading history...
646
647
            if ($countResponse == 0) {
648
                $responseItems = $xpath->query($queryAnswers);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $queryAnswers does not seem to be defined for all execution paths leading up to this point.
Loading history...
649
            } else {
650
                $responseItems = $xpath->query($queryAnswersWithFlow);
651
            }
652
653
            if (!empty($responseItems)) {
654
                if ($isMultiresponse) {
655
                    $correctAnswerScore = 0;
656
                    //get the correct answers count
657
                    $canswers_query = "//xmlns:item[@ident='{$identifier}']//xmlns:setvar[@varname='SCORE'][.=100]/../xmlns:conditionvar//xmlns:varequal[@case='Yes'][not(parent::xmlns:not)]";
658
                    $canswers = $xpath->query($canswers_query);
659
                    if ($canswers->length > 0) {
660
                        $correctAnswerScore = round(1.0 / (float) $canswers->length, 7); //weird
661
                        $correctAanswersIdent = [];
662
                        foreach ($canswers as $cnode) {
663
                            $correctAanswersIdent[$cnode->nodeValue] = true;
664
                        }
665
                    }
666
                }
667
668
                foreach ($responseItems as $response_item) {
669
                    $lastAnswerId++;
670
671
                    $answerIdentifier = $xpath->query($queryIndentifer, $response_item);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $queryIndentifer does not seem to be defined for all execution paths leading up to this point.
Loading history...
672
                    $answerIdentifier = !empty($answerIdentifier->item(0)->nodeValue) ? $answerIdentifier->item(0)->nodeValue : '';
673
674
                    $answerTitle = $xpath->query($queryTitle, $response_item);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $queryTitle does not seem to be defined for all execution paths leading up to this point.
Loading history...
675
                    $answerTitle = !empty($answerTitle->item(0)->nodeValue) ? $answerTitle->item(0)->nodeValue : '';
676
677
                    $answerFeedback = $this->getFeedback($assessment, $answerIdentifier, $identifier, $questionCcType);
678
679
                    $answer_score = $this->getScore($assessment, $answerIdentifier, $identifier);
680
681
                    if ($isMultiresponse && isset($correctAanswersIdent[$answerIdentifier])) {
682
                        $answer_score = $correctAnswerScore;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $correctAnswerScore does not seem to be defined for all execution paths leading up to this point.
Loading history...
683
                    }
684
685
                    $answers[] = ['id' => $lastAnswerId,
686
                                       'title' => $answerTitle,
687
                                       'score' => $answer_score,
688
                                       'identifier' => $answerIdentifier,
689
                                       'feedback' => $answerFeedback, ];
690
                }
691
            }
692
        }
693
694
        $answers = empty($answers) ? '' : $answers;
695
696
        return $answers;
697
    }
698
699
    private function getScore($assessment, $identifier, $questionIdentifier)
700
    {
701
        $xpath = Cc1p3Convert::newxPath($assessment, Cc1p3Convert::getquizns());
702
703
        $resourceProcessing = $xpath->query('//xmlns:item[@ident="'.$questionIdentifier.'"]/xmlns:resprocessing/xmlns:respcondition');
704
705
        if (!empty($resourceProcessing)) {
706
            foreach ($resourceProcessing as $response) {
707
                $questionCcType = $this->getQuestionType($questionIdentifier, $assessment);
708
                $questionCcType = $questionCcType['cc'];
709
710
                $varequal = $xpath->query('xmlns:conditionvar/xmlns:varequal', $response);
711
                $varequal = !empty($varequal->item(0)->nodeValue) ? $varequal->item(0)->nodeValue : '';
712
713
                if (strtolower($varequal) == strtolower($identifier)) {
714
                    $score = $xpath->query('xmlns:setvar', $response);
715
                    $score = !empty($score->item(0)->nodeValue) ? $score->item(0)->nodeValue : '';
716
                }
717
            }
718
        }
719
720
        $score = empty($score) ? "0.0000000" : '1.0000000';
721
722
        return $score;
723
    }
724
725
    private function getQuestionType($identifier, $assessment)
726
    {
727
        $xpath = Cc1p3Convert::newxPath($assessment, Cc1p3Convert::getquizns());
728
729
        $metadata = $xpath->query('//xmlns:item[@ident="'.$identifier.'"]/xmlns:itemmetadata/xmlns:qtimetadata/xmlns:qtimetadatafield');
730
731
        foreach ($metadata as $field) {
732
            $fieldLabel = $xpath->query('xmlns:fieldlabel', $field);
733
            $fieldLabel = !empty($fieldLabel->item(0)->nodeValue) ? $fieldLabel->item(0)->nodeValue : '';
734
735
            if ($fieldLabel == 'cc_profile') {
736
                $fieldEntry = $xpath->query('xmlns:fieldentry', $field);
737
                $type = !empty($fieldEntry->item(0)->nodeValue) ? $fieldEntry->item(0)->nodeValue : '';
738
            }
739
        }
740
741
        $returnType = [];
742
743
        $returnType['qtype'] = '';
744
        $returnType['cc'] = $type;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $type does not seem to be defined for all execution paths leading up to this point.
Loading history...
745
746
        switch ($type) {
747
            case CC_QUIZ_MULTIPLE_CHOICE:
748
                $returnType['qtype'] = 'unique_answer';
749
                break;
750
            case CC_QUIZ_MULTIPLE_RESPONSE:
751
                $returnType['qtype'] = 'multiple_answer';
752
                break;
753
            case CC_QUIZ_FIB:
754
                $returnType['qtype'] = 'fib';
755
                break;
756
            case CC_QUIZ_ESSAY:
757
                $returnType['qtype'] = 'essay';
758
                break;
759
        }
760
761
        return $returnType;
762
    }
763
}
764