Passed
Push — master ( 5db41b...b5271b )
by Julito
10:05
created

lp_upload_quiz_main()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 58
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 43
nc 4
nop 0
dl 0
loc 58
rs 9.232
c 0
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use ChamiloSession as Session;
6
7
/**
8
 * Upload quiz: This script shows the upload quiz feature.
9
 */
10
$help_content = 'exercise_upload';
11
require_once __DIR__.'/../inc/global.inc.php';
12
13
api_protect_course_script(true);
14
15
$is_allowed_to_edit = api_is_allowed_to_edit(null, true);
16
$debug = false;
17
$origin = api_get_origin();
18
if (!$is_allowed_to_edit) {
19
    api_not_allowed(true);
20
}
21
22
$this_section = SECTION_COURSES;
23
$htmlHeadXtra[] = "<script>
24
$(function(){
25
    $('#user_custom_score').click(function() {
26
        $('#options').toggle();
27
    });
28
});
29
</script>";
30
31
// Action handling
32
lp_upload_quiz_action_handling();
33
34
$interbreadcrumb[] = [
35
    'url' => 'exercise.php?'.api_get_cidreq(),
36
    'name' => get_lang('Tests'),
37
];
38
39
Display::display_header(get_lang('Import quiz from Excel'), 'Exercises');
40
41
echo '<div class="actions">';
42
echo lp_upload_quiz_actions();
43
echo '</div>';
44
45
// the main content
46
lp_upload_quiz_main();
47
48
function lp_upload_quiz_actions()
49
{
50
    return '<a href="exercise.php?'.api_get_cidreq().'">'.
51
        Display::return_icon(
52
            'back.png',
53
            get_lang('BackToTestsList'),
54
            '',
55
            ICON_SIZE_MEDIUM
56
        ).'</a>';
57
}
58
59
function lp_upload_quiz_main()
60
{
61
    $lp_id = isset($_GET['lp_id']) ? (int) $_GET['lp_id'] : null;
62
63
    $form = new FormValidator(
64
        'upload',
65
        'POST',
66
        api_get_self().'?'.api_get_cidreq().'&lp_id='.$lp_id,
67
        '',
68
        ['enctype' => 'multipart/form-data']
69
    );
70
    $form->addElement('header', get_lang('Import quiz from Excel'));
71
    $form->addElement('file', 'user_upload_quiz', get_lang('File upload'));
72
73
    $link = '<a href="../exercise/quiz_template.xls">'.
74
        Display::return_icon('export_excel.png', get_lang('Download the Excel Template')).get_lang('Download the Excel Template').'</a>';
75
    $form->addElement('label', '', $link);
76
77
    $table = new HTML_Table(['class' => 'table']);
78
79
    $tableList = [
80
        UNIQUE_ANSWER => get_lang('Multiple choice'),
81
        MULTIPLE_ANSWER => get_lang('Multiple answers'),
82
        FILL_IN_BLANKS => get_lang('Fill blanks or form'),
83
        MATCHING => get_lang('Matching'),
84
        FREE_ANSWER => get_lang('Open question'),
85
        GLOBAL_MULTIPLE_ANSWER => get_lang('Global multiple answer'),
86
    ];
87
88
    $table->setHeaderContents(0, 0, get_lang('Question type'));
89
    $table->setHeaderContents(0, 1, '#');
90
91
    $row = 1;
92
    foreach ($tableList as $key => $label) {
93
        $table->setCellContents($row, 0, $label);
94
        $table->setCellContents($row, 1, $key);
95
        $row++;
96
    }
97
    $table = $table->toHtml();
98
99
    $form->addElement('label', get_lang('Question type'), $table);
100
    $form->addElement(
101
        'checkbox',
102
        'user_custom_score',
103
        null,
104
        get_lang('Use custom score for all questions'),
105
        ['id' => 'user_custom_score']
106
    );
107
    $form->addElement('html', '<div id="options" style="display:none">');
108
    $form->addElement('text', 'correct_score', get_lang('Correct score'));
109
    $form->addElement('text', 'incorrect_score', get_lang('Incorrect score'));
110
    $form->addElement('html', '</div>');
111
112
    $form->addRule('user_upload_quiz', get_lang('Required field'), 'required');
113
114
    $form->addProgress();
115
    $form->addButtonUpload(get_lang('Upload'), 'submit_upload_quiz');
116
    $form->display();
117
}
118
119
/**
120
 * Handles a given Excel spreadsheets as in the template provided.
121
 */
122
function lp_upload_quiz_action_handling()
123
{
124
    if (!isset($_POST['submit_upload_quiz'])) {
125
        return;
126
    }
127
128
    $_course = api_get_course_info();
129
130
    if (empty($_course)) {
131
        return false;
132
    }
133
134
    $courseId = $_course['real_id'];
135
136
    // Get the extension of the document.
137
    $path_info = pathinfo($_FILES['user_upload_quiz']['name']);
138
139
    // Check if the document is an Excel document
140
    if (!in_array($path_info['extension'], ['xls', 'xlsx'])) {
141
        return;
142
    }
143
144
    // Variables
145
    $numberQuestions = 0;
146
    $question = [];
147
    $scoreList = [];
148
    $feedbackTrueList = [];
149
    $feedbackFalseList = [];
150
    $questionDescriptionList = [];
151
    $noNegativeScoreList = [];
152
    $questionTypeList = [];
153
    $answerList = [];
154
    $quizTitle = '';
155
156
    $objPHPExcel = PHPExcel_IOFactory::load($_FILES['user_upload_quiz']['tmp_name']);
157
    $objPHPExcel->setActiveSheetIndex(0);
158
    $worksheet = $objPHPExcel->getActiveSheet();
159
    $highestRow = $worksheet->getHighestRow(); // e.g. 10
160
    //  $highestColumn = $worksheet->getHighestColumn(); // e.g 'F'
161
162
    $correctScore = isset($_POST['correct_score']) ? $_POST['correct_score'] : null;
163
    $incorrectScore = isset($_POST['incorrect_score']) ? $_POST['incorrect_score'] : null;
164
    $useCustomScore = isset($_POST['user_custom_score']) ? true : false;
165
166
    for ($row = 1; $row <= $highestRow; $row++) {
167
        $cellTitleInfo = $worksheet->getCellByColumnAndRow(0, $row);
168
        $cellDataInfo = $worksheet->getCellByColumnAndRow(1, $row);
169
        $cellScoreInfo = $worksheet->getCellByColumnAndRow(2, $row);
170
        $title = $cellTitleInfo->getValue();
171
172
        switch ($title) {
173
            case 'Quiz':
174
                $quizTitle = $cellDataInfo->getValue();
175
176
                break;
177
            case 'Question':
178
                $question[] = $cellDataInfo->getValue();
179
                // Search cell with Answer title
180
                $answerRow = $row;
181
                $continue = true;
182
                $answerIndex = 0;
183
                while ($continue) {
184
                    $answerRow++;
185
                    $answerInfoTitle = $worksheet->getCellByColumnAndRow(0, $answerRow);
186
                    $answerInfoData = $worksheet->getCellByColumnAndRow(1, $answerRow);
187
                    $answerInfoExtra = $worksheet->getCellByColumnAndRow(2, $answerRow);
188
                    $answerInfoTitle = $answerInfoTitle->getValue();
189
                    if (false !== strpos($answerInfoTitle, 'Answer')) {
190
                        $answerList[$numberQuestions][$answerIndex]['data'] = $answerInfoData->getValue();
191
                        $answerList[$numberQuestions][$answerIndex]['extra'] = $answerInfoExtra->getValue();
192
                    } else {
193
                        $continue = false;
194
                    }
195
                    $answerIndex++;
196
197
                    // To avoid loops
198
                    if ($answerIndex > 60) {
199
                        $continue = false;
200
                    }
201
                }
202
203
                // Search cell with question type
204
                $answerRow = $row;
205
                $continue = true;
206
                $questionTypeIndex = 0;
207
                while ($continue) {
208
                    $answerRow++;
209
                    $questionTypeTitle = $worksheet->getCellByColumnAndRow(0, $answerRow);
210
                    $questionTypeExtra = $worksheet->getCellByColumnAndRow(2, $answerRow);
211
                    $title = $questionTypeTitle->getValue();
212
                    if ('QuestionType' == $title) {
213
                        $questionTypeList[$numberQuestions] = $questionTypeExtra->getValue();
214
                        $continue = false;
215
                    }
216
                    if ('Question' == $title) {
217
                        $continue = false;
218
                    }
219
                    // To avoid loops
220
                    if ($questionTypeIndex > 60) {
221
                        $continue = false;
222
                    }
223
                    $questionTypeIndex++;
224
                }
225
226
                // Detect answers
227
                $numberQuestions++;
228
229
                break;
230
            case 'Score':
231
                $scoreList[] = $cellScoreInfo->getValue();
232
233
                break;
234
            case 'NoNegativeScore':
235
                $noNegativeScoreList[] = $cellScoreInfo->getValue();
236
237
                break;
238
            case 'Category':
239
                $categoryList[] = $cellDataInfo->getValue();
240
241
                break;
242
            case 'FeedbackTrue':
243
                $feedbackTrueList[] = $cellDataInfo->getValue();
244
245
                break;
246
            case 'FeedbackFalse':
247
                $feedbackFalseList[] = $cellDataInfo->getValue();
248
249
                break;
250
            case 'EnrichQuestion':
251
                $questionDescriptionList[] = $cellDataInfo->getValue();
252
253
                break;
254
        }
255
    }
256
257
    $propagateNegative = 0;
258
    if ($useCustomScore && !empty($incorrectScore)) {
259
        if ($incorrectScore < 0) {
260
            $propagateNegative = 1;
261
        }
262
    }
263
264
    if ('' != $quizTitle) {
265
        // Variables
266
        $type = 2;
267
        $random = $active = $results = $max_attempt = $expired_time = 0;
268
        // Make sure feedback is enabled (3 to disable), otherwise the fields
269
        // added to the XLS are not shown, which is confusing
270
        $feedback = 0;
271
272
        // Quiz object
273
        $exercise = new Exercise();
274
        $exercise->updateTitle($quizTitle);
275
        $exercise->updateExpiredTime($expired_time);
276
        $exercise->updateType($type);
277
        $exercise->setRandom($random);
278
        $exercise->active = $active;
279
        $exercise->updateResultsDisabled($results);
280
        $exercise->updateAttempts($max_attempt);
281
        $exercise->updateFeedbackType($feedback);
282
        $exercise->updatePropagateNegative($propagateNegative);
283
        $quiz_id = $exercise->save();
284
285
        if ($quiz_id) {
286
            // Import questions.
287
            for ($i = 0; $i < $numberQuestions; $i++) {
288
                // Question name
289
                $questionTitle = $question[$i];
290
                $myAnswerList = isset($answerList[$i]) ? $answerList[$i] : [];
291
                $description = isset($questionDescriptionList[$i]) ? $questionDescriptionList[$i] : '';
292
                $categoryId = null;
293
                if (isset($categoryList[$i]) && !empty($categoryList[$i])) {
294
                    $categoryName = $categoryList[$i];
295
                    $categoryId = TestCategory::get_category_id_for_title($categoryName, $courseId);
296
                    if (empty($categoryId)) {
297
                        $category = new TestCategory();
298
                        $category->name = $categoryName;
299
                        $categoryId = $category->save();
300
                    }
301
                }
302
303
                $question_description_text = '<p></p>';
304
                if (!empty($description)) {
305
                    // Question description.
306
                    $question_description_text = "<p>$description</p>";
307
                }
308
309
                // Unique answers are the only question types available for now
310
                // through xls-format import
311
                $question_id = null;
312
                if (isset($questionTypeList[$i]) && '' != $questionTypeList[$i]) {
313
                    $detectQuestionType = (int) $questionTypeList[$i];
314
                } else {
315
                    $detectQuestionType = detectQuestionType($myAnswerList);
316
                }
317
318
                /** @var Question $answer */
319
                switch ($detectQuestionType) {
320
                    case FREE_ANSWER:
321
                        $answer = new FreeAnswer();
322
323
                        break;
324
                    case GLOBAL_MULTIPLE_ANSWER:
325
                        $answer = new GlobalMultipleAnswer();
326
327
                        break;
328
                    case MULTIPLE_ANSWER:
329
                        $answer = new MultipleAnswer();
330
331
                        break;
332
                    case FILL_IN_BLANKS:
333
                        $answer = new FillBlanks();
334
                        $question_description_text = '';
335
336
                        break;
337
                    case MATCHING:
338
                        $answer = new Matching();
339
340
                        break;
341
                    case UNIQUE_ANSWER:
342
                    default:
343
                        $answer = new UniqueAnswer();
344
345
                        break;
346
                }
347
348
                if ('' != $questionTitle) {
349
                    $question_id = $answer->create_question(
350
                        $quiz_id,
351
                        $questionTitle,
352
                        $question_description_text,
353
                        0, // max score
354
                        $answer->type
355
                    );
356
357
                    if (!empty($categoryId)) {
358
                        TestCategory::addCategoryToQuestion(
359
                            $categoryId,
360
                            $question_id,
361
                            $courseId
362
                        );
363
                    }
364
                }
365
                switch ($detectQuestionType) {
366
                    case GLOBAL_MULTIPLE_ANSWER:
367
                    case MULTIPLE_ANSWER:
368
                    case UNIQUE_ANSWER:
369
                        $total = 0;
370
                        if (is_array($myAnswerList) && !empty($myAnswerList) && !empty($question_id)) {
371
                            $id = 1;
372
                            $objAnswer = new Answer($question_id, $courseId);
373
                            $globalScore = isset($scoreList[$i]) ? $scoreList[$i] : null;
374
375
                            // Calculate the number of correct answers to divide the
376
                            // score between them when importing from CSV
377
                            $numberRightAnswers = 0;
378
                            foreach ($myAnswerList as $answer_data) {
379
                                if ('x' == strtolower($answer_data['extra'])) {
380
                                    $numberRightAnswers++;
381
                                }
382
                            }
383
384
                            foreach ($myAnswerList as $answer_data) {
385
                                $answerValue = $answer_data['data'];
386
                                $correct = 0;
387
                                $score = 0;
388
                                if ('x' == strtolower($answer_data['extra'])) {
389
                                    $correct = 1;
390
                                    $score = isset($scoreList[$i]) ? $scoreList[$i] : 0;
391
                                    $comment = isset($feedbackTrueList[$i]) ? $feedbackTrueList[$i] : '';
392
                                } else {
393
                                    $comment = isset($feedbackFalseList[$i]) ? $feedbackFalseList[$i] : '';
394
                                    $floatVal = (float) $answer_data['extra'];
395
                                    if (is_numeric($floatVal)) {
396
                                        $score = $answer_data['extra'];
397
                                    }
398
                                }
399
400
                                if ($useCustomScore) {
401
                                    if ($correct) {
402
                                        $score = $correctScore;
403
                                    } else {
404
                                        $score = $incorrectScore;
405
                                    }
406
                                }
407
408
                                // Fixing scores:
409
                                switch ($detectQuestionType) {
410
                                    case GLOBAL_MULTIPLE_ANSWER:
411
                                        if ($correct) {
412
                                            $score = abs($scoreList[$i]);
413
                                        } else {
414
                                            if (isset($noNegativeScoreList[$i]) && 'x' == $noNegativeScoreList[$i]) {
415
                                                $score = 0;
416
                                            } else {
417
                                                $score = -abs($scoreList[$i]);
418
                                            }
419
                                        }
420
                                        $score /= $numberRightAnswers;
421
422
                                        break;
423
                                    case UNIQUE_ANSWER:
424
                                        break;
425
                                    case MULTIPLE_ANSWER:
426
                                        if (!$correct) {
427
                                            //$total = $total - $score;
428
                                        }
429
430
                                        break;
431
                                }
432
433
                                $objAnswer->createAnswer(
434
                                    $answerValue,
435
                                    $correct,
436
                                    $comment,
437
                                    $score,
438
                                    $id
439
                                );
440
                                if ($correct) {
441
                                    $total += (float) $score;
442
                                }
443
                                $id++;
444
                            }
445
446
                            $objAnswer->save();
447
448
                            $questionObj = Question::read(
449
                                $question_id,
450
                                $_course
451
                            );
452
453
                            if ($questionObj) {
454
                                switch ($detectQuestionType) {
455
                                    case GLOBAL_MULTIPLE_ANSWER:
456
                                        $questionObj->updateWeighting($globalScore);
457
458
                                        break;
459
                                    case UNIQUE_ANSWER:
460
                                    case MULTIPLE_ANSWER:
461
                                    default:
462
                                        $questionObj->updateWeighting($total);
463
464
                                        break;
465
                                }
466
                                $questionObj->save($exercise);
467
                            }
468
                        }
469
470
                        break;
471
                    case FREE_ANSWER:
472
                        $globalScore = isset($scoreList[$i]) ? $scoreList[$i] : null;
473
                        $questionObj = Question::read($question_id, $_course);
474
                        if ($questionObj) {
475
                            $questionObj->updateWeighting($globalScore);
476
                            $questionObj->save($exercise);
477
                        }
478
479
                        break;
480
                    case FILL_IN_BLANKS:
481
                        $fillInScoreList = [];
482
                        $size = [];
483
                        $globalScore = 0;
484
                        foreach ($myAnswerList as $data) {
485
                            $score = isset($data['extra']) ? $data['extra'] : 0;
486
                            $globalScore += $score;
487
                            $fillInScoreList[] = $score;
488
                            $size[] = 200;
489
                        }
490
491
                        $scoreToString = implode(',', $fillInScoreList);
492
                        $sizeToString = implode(',', $size);
493
494
                        //<p>Texte long avec les [mots] à [remplir] mis entre [crochets]</p>::10,10,10:200.36363999999998,200,200:0@'
495
                        $answerValue = $description.'::'.$scoreToString.':'.$sizeToString.':0@';
496
                        $objAnswer = new Answer($question_id, $courseId);
497
                        $objAnswer->createAnswer(
498
                            $answerValue,
499
                            '', //$correct,
500
                            '', //$comment,
501
                            $globalScore,
502
                            1
503
                        );
504
505
                        $objAnswer->save();
506
507
                        $questionObj = Question::read($question_id, $_course);
508
                        if ($questionObj) {
509
                            $questionObj->updateWeighting($globalScore);
510
                            $questionObj->save($exercise);
511
                        }
512
513
                        break;
514
                    case MATCHING:
515
                        $globalScore = isset($scoreList[$i]) ? $scoreList[$i] : null;
516
                        $position = 1;
517
518
                        $objAnswer = new Answer($question_id, $courseId);
519
                        foreach ($myAnswerList as $data) {
520
                            $option = isset($data['extra']) ? $data['extra'] : '';
521
                            $objAnswer->createAnswer($option, 0, '', 0, $position);
522
                            $position++;
523
                        }
524
525
                        $counter = 1;
526
                        foreach ($myAnswerList as $data) {
527
                            $value = isset($data['data']) ? $data['data'] : '';
528
                            $position++;
529
                            $objAnswer->createAnswer(
530
                                $value,
531
                                $counter,
532
                                ' ',
533
                                $globalScore,
534
                                $position
535
                            );
536
                            $counter++;
537
                        }
538
                        $objAnswer->save();
539
                        $questionObj = Question::read($question_id, $_course);
540
                        if ($questionObj) {
541
                            $questionObj->updateWeighting($globalScore);
542
                            $questionObj->save($exercise);
543
                        }
544
545
                        break;
546
                }
547
            }
548
        }
549
550
        $lpObject = Session::read('lpobject');
551
552
        if (!empty($lpObject)) {
553
            /** @var learnpath $oLP */
554
            $oLP = UnserializeApi::unserialize('lp', $lpObject);
555
            if (is_object($oLP)) {
556
                if (empty($oLP->cc) || $oLP->cc != api_get_course_id()) {
557
                    $oLP = null;
558
                    Session::erase('oLP');
559
                    Session::erase('lpobject');
560
                } else {
561
                    Session::write('oLP', $oLP);
562
                }
563
            }
564
        }
565
        Display::addFlash(Display::return_message(get_lang('FileImported')));
566
567
        if (isset($_SESSION['oLP']) && isset($_GET['lp_id'])) {
568
            $previous = $_SESSION['oLP']->select_previous_item_id();
569
            $parent = 0;
570
            // Add a Quiz as Lp Item
571
            $_SESSION['oLP']->add_item(
572
                $parent,
573
                $previous,
574
                TOOL_QUIZ,
575
                $quiz_id,
576
                $quizTitle,
577
                ''
578
            );
579
            // Redirect to home page for add more content
580
            header('Location: ../lp/lp_controller.php?'.api_get_cidreq().'&action=add_item&type=step&lp_id='.(int) ($_GET['lp_id']));
581
            exit;
582
        } else {
583
            //  header('location: exercise.php?' . api_get_cidreq());
584
        $exerciseUrl = api_get_path(WEB_CODE_PATH).
585
            'exercise/admin.php?'.api_get_cidreq().'&exerciseId='.$quiz_id.'&session_id='.api_get_session_id();
586
        api_location($exerciseUrl);
587
    }
588
}
589
590
/**
591
 * @param array $answers_data
592
 *
593
 * @return int
594
 */
595
function detectQuestionType($answers_data)
596
{
597
    $correct = 0;
598
    $isNumeric = false;
599
600
    if (empty($answers_data)) {
601
        return FREE_ANSWER;
602
    }
603
604
    foreach ($answers_data as $answer_data) {
605
        if ('x' == strtolower($answer_data['extra'])) {
606
            $correct++;
607
        } else {
608
            if (is_numeric($answer_data['extra'])) {
609
                $isNumeric = true;
610
            }
611
        }
612
    }
613
614
    if (1 == $correct) {
615
        $type = UNIQUE_ANSWER;
616
    } else {
617
        if ($correct > 1) {
618
            $type = MULTIPLE_ANSWER;
619
        } else {
620
            $type = FREE_ANSWER;
621
        }
622
    }
623
624
    if (MULTIPLE_ANSWER == $type) {
625
        if ($isNumeric) {
626
            $type = MULTIPLE_ANSWER;
627
        } else {
628
            $type = GLOBAL_MULTIPLE_ANSWER;
629
        }
630
    }
631
632
    return $type;
633
}
634
635
if ('learnpath' != $origin) {
636
    //so we are not in learnpath tool
637
    Display::display_footer();
638
}
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected EOF on line 638 at column 0
Loading history...
639