Passed
Push — master ( 3b9d17...c5f69b )
by Julito
17:12
created

displayDegreeChartChildren()   F

Complexity

Conditions 20
Paths 15360

Size

Total Lines 169
Code Lines 110

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
eloc 110
nc 15360
nop 9
dl 0
loc 169
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Framework\Container;
6
use Chamilo\CourseBundle\Entity\CQuizQuestion;
7
use ChamiloSession as Session;
8
9
/**
10
 * Class MultipleAnswerTrueFalseDegreeCertainty
11
 * This class allows to instantiate an object of type MULTIPLE_ANSWER
12
 * (MULTIPLE CHOICE, MULTIPLE ANSWER), extending the class question.
13
 */
14
class MultipleAnswerTrueFalseDegreeCertainty extends Question
15
{
16
    public const LEVEL_DARKGREEN = 1;
17
    public const LEVEL_LIGHTGREEN = 2;
18
    public const LEVEL_WHITE = 3;
19
    public const LEVEL_LIGHTRED = 4;
20
    public const LEVEL_DARKRED = 5;
21
22
    public $typePicture = 'mccert.png';
23
    public $explanationLangVar = 'Multiple answer true/false/degree of certainty';
24
    public $optionsTitle;
25
    public $options;
26
27
    public function __construct()
28
    {
29
        parent::__construct();
30
        $this->type = MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY;
31
        $this->isContent = $this->getIsContent();
32
        $this->optionsTitle = [1 => 'Answers', 2 => 'DegreeOfCertaintyThatMyAnswerIsCorrect'];
33
        $this->options = [
34
            1 => 'True',
35
            2 => 'False',
36
            3 => '50%',
37
            4 => '60%',
38
            5 => '70%',
39
            6 => '80%',
40
            7 => '90%',
41
            8 => '100%',
42
        ];
43
    }
44
45
    /**
46
     * Redefines Question::createAnswersForm: creates the HTML form to answer the question.
47
     *
48
     * @uses \globals $text and $class, defined in the calling script
49
     *
50
     * @param FormValidator $form
51
     *
52
     * @throws Exception
53
     */
54
    public function createAnswersForm($form)
55
    {
56
        global $text;
57
        $nbAnswers = isset($_POST['nb_answers']) ? (int) $_POST['nb_answers'] : 4;
58
        // The previous default value was 2. See task #1759.
59
        $nbAnswers += (isset($_POST['lessAnswers']) ? -1 : (isset($_POST['moreAnswers']) ? 1 : 0));
60
61
        $courseId = api_get_course_int_id();
62
        $objEx = Session::read('objExercise');
63
        $renderer = &$form->defaultRenderer();
64
        $defaults = [];
65
66
        $form->addHeader(get_lang('Answers'));
67
        $html = '<table class="table table-striped table-hover">
68
            <tr>
69
                <th width="10px">'.get_lang('Number').'</th>
70
                <th width="10px">'.get_lang('True').'</th>
71
                <th width="10px">'.get_lang('False').'</th>
72
                <th width="50%">'.get_lang('Answer').'</th>';
73
74
        // show column comment when feedback is enable
75
        if (EXERCISE_FEEDBACK_TYPE_EXAM != $objEx->getFeedbackType()) {
76
            $html .= '<th width="50%">'.get_lang('Comment').'</th>';
77
        }
78
        $html .= '</tr>';
79
80
        $form->addHtml($html);
81
82
        $correct = 0;
83
        $answer = null;
84
        if (!empty($this->id)) {
85
            $answer = new Answer($this->id);
86
            $answer->read();
87
            if ($answer->nbrAnswers > 0 && !$form->isSubmitted()) {
88
                $nbAnswers = $answer->nbrAnswers;
89
            }
90
        }
91
92
        $form->addElement('hidden', 'nb_answers');
93
        $boxesNames = [];
94
95
        if ($nbAnswers < 1) {
96
            $nbAnswers = 1;
97
            echo Display::return_message(get_lang('You have to create at least one answer'));
98
        }
99
100
        // Can be more options
101
        $optionData = Question::readQuestionOption($this->id, $courseId);
102
103
        for ($i = 1; $i <= $nbAnswers; $i++) {
104
            $renderer->setElementTemplate(
105
                '<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>',
106
                'correct['.$i.']'
107
            );
108
            $renderer->setElementTemplate(
109
                '<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>',
110
                'counter['.$i.']'
111
            );
112
            $renderer->setElementTemplate(
113
                '<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>',
114
                'answer['.$i.']'
115
            );
116
            $renderer->setElementTemplate(
117
                '<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>',
118
                'comment['.$i.']'
119
            );
120
121
            $answerNumber = $form->addElement('text', 'counter['.$i.']', null, 'value="'.$i.'"');
122
            $answerNumber->freeze();
123
124
            $defaults['answer['.$i.']'] = '';
125
            $defaults['comment['.$i.']'] = '';
126
            $defaults['correct['.$i.']'] = '';
127
128
            if (is_object($answer)) {
129
                $defaults['answer['.$i.']'] = isset($answer->answer[$i]) ? $answer->answer[$i] : '';
130
                if (isset($_POST['answer']) && isset($_POST['answer'][$i])) {
131
                    $defaults['answer['.$i.']'] = Security::remove_XSS($_POST['answer'][$i]);
132
                }
133
134
                $defaults['comment['.$i.']'] = isset($answer->comment[$i]) ? $answer->comment[$i] : '';
135
                if (isset($_POST['comment']) && isset($_POST['comment'][$i])) {
136
                    $defaults['comment['.$i.']'] = Security::remove_XSS($_POST['comment'][$i]);
137
                }
138
139
                $defaults['weighting['.$i.']'] = isset($answer->weighting[$i]) ? float_format($answer->weighting[$i], 1) : '';
140
                $correct = isset($answer->correct[$i]) ? $answer->correct[$i] : '';
141
                $defaults['correct['.$i.']'] = $correct;
142
                if (isset($_POST['correct']) && isset($_POST['correct'][$i])) {
143
                    $defaults['correct['.$i.']'] = Security::remove_XSS($_POST['correct'][$i]);
144
                }
145
146
                $j = 1;
147
                if (!empty($optionData)) {
148
                    foreach ($optionData as $id => $data) {
149
                        $rdoCorrect = $form->addElement('radio', 'correct['.$i.']', null, null, $id);
150
151
                        if (isset($_POST['correct']) && isset($_POST['correct'][$i]) && $id == $_POST['correct'][$i]) {
152
                            $rdoCorrect->setValue(Security::remove_XSS($_POST['correct'][$i]));
153
                        }
154
                        $j++;
155
                        if (3 == $j) {
156
                            break;
157
                        }
158
                    }
159
                }
160
            } else {
161
                $form->addElement('radio', 'correct['.$i.']', null, null, 1);
162
                $form->addElement('radio', 'correct['.$i.']', null, null, 2);
163
            }
164
165
            $boxesNames[] = 'correct['.$i.']';
166
            $txtAnswer = $form->addElement(
167
                'html_editor',
168
                'answer['.$i.']',
169
                null,
170
                ['style' => 'vertical-align:middle;'],
171
                ['ToolbarSet' => 'TestProposedAnswer', 'Width' => '100%', 'Height' => '100']
172
            );
173
            $form->addRule('answer['.$i.']', get_lang('Required field'), 'required');
174
175
            if (isset($_POST['answer']) && isset($_POST['answer'][$i])) {
176
                $txtAnswer->setValue(Security::remove_XSS($_POST['answer'][$i]));
177
            }
178
            // show comment when feedback is enable
179
            if (EXERCISE_FEEDBACK_TYPE_EXAM != $objEx->getFeedbackType()) {
180
                $txtComment = $form->addElement(
181
                    'html_editor',
182
                    'comment['.$i.']',
183
                    null,
184
                    ['style' => 'vertical-align:middle;'],
185
                    ['ToolbarSet' => 'TestProposedAnswer', 'Width' => '100%', 'Height' => '100']
186
                );
187
                if (isset($_POST['comment']) && isset($_POST['comment'][$i])) {
188
                    $txtComment->setValue(Security::remove_XSS($_POST['comment'][$i]));
189
                }
190
            }
191
            $form->addElement('html', '</tr>');
192
        }
193
194
        $form->addElement('html', '</table>');
195
        $form->addElement('html', '<br />');
196
197
        // 3 scores
198
        $txtOption1 = $form->addElement('text', 'option[1]', get_lang('Correct'), ['value' => '1']);
199
        $txtOption2 = $form->addElement('text', 'option[2]', get_lang('Wrong'), ['value' => '-0.5']);
200
201
        $form->addElement('hidden', 'option[3]', 0);
202
203
        $form->addRule('option[1]', get_lang('Required field'), 'required');
204
        $form->addRule('option[2]', get_lang('Required field'), 'required');
205
206
        $form->addElement('html', '</tr><table>');
207
        $form->addElement('hidden', 'options_count', 3);
208
        $form->addElement('html', '</table><br /><br />');
209
210
        //Extra values True, false,  Dont known
211
        if (!empty($this->extra)) {
212
            $scores = explode(':', $this->extra);
213
            if (!empty($scores)) {
214
                $txtOption1->setValue($scores[0]);
215
                $txtOption2->setValue($scores[1]);
216
            }
217
        }
218
219
        if (true === $objEx->edit_exercise_in_lp ||
220
            (empty($this->exerciseList) && empty($objEx->id))
221
        ) {
222
            $form->addElement('submit', 'lessAnswers', get_lang('Remove answer option'), 'class="btn btn-danger minus"');
223
            $form->addElement('submit', 'moreAnswers', get_lang('Add answer option'), 'class="btn btn-primary plus"');
224
            $form->addElement('submit', 'submitQuestion', $text, 'class = "btn btn-primary"');
225
        }
226
        $renderer->setElementTemplate('{element}&nbsp;', 'lessAnswers');
227
        $renderer->setElementTemplate('{element}&nbsp;', 'submitQuestion');
228
        $renderer->setElementTemplate('{element}&nbsp;', 'moreAnswers');
229
        $form->addElement('html', '</div></div>');
230
231
        if (!empty($this->id) && !$form->isSubmitted()) {
232
            $form->setDefaults($defaults);
233
        }
234
        $form->setConstants(['nb_answers' => $nbAnswers]);
235
    }
236
237
    /**
238
     * abstract function which creates the form to create / edit the answers of the question.
239
     *
240
     * @param FormValidator $form
241
     * @param Exercise      $exercise
242
     */
243
    public function processAnswersCreation($form, $exercise)
244
    {
245
        $questionWeighting = 0;
246
        $objAnswer = new Answer($this->id);
247
        $nbAnswers = $form->getSubmitValue('nb_answers');
248
        $courseId = api_get_course_int_id();
249
250
        $repo = Container::getQuestionRepository();
251
        /** @var CQuizQuestion $question */
252
        $question = $repo->find($this->id);
253
        $options = $question->getOptions();
254
255
        if (!empty($options)) {
256
            foreach ($options as $optionData) {
257
                $optionData->setName($optionData);
258
            }
259
        } else {
260
            for ($i = 1; $i <= 8; $i++) {
261
                Question::saveQuestionOption($question, $this->options[$i], $i);
262
            }
263
        }
264
265
        /* Getting quiz_question_options (true, false, doubt) because
266
          it's possible that there are more options in the future */
267
        $newOptions = Question::readQuestionOption($this->id, $courseId);
268
        $sortedByPosition = [];
269
        foreach ($newOptions as $item) {
270
            $sortedByPosition[$item['position']] = $item;
271
        }
272
273
        /* Saving quiz_question.extra values that has the correct scores of
274
          the true, false, doubt options registered in this format
275
          XX:YY:ZZZ where XX is a float score value. */
276
        $extraValues = [];
277
        for ($i = 1; $i <= 3; $i++) {
278
            $score = trim($form->getSubmitValue('option['.$i.']'));
279
            $extraValues[] = $score;
280
        }
281
        $this->setExtra(implode(':', $extraValues));
282
283
        for ($i = 1; $i <= $nbAnswers; $i++) {
284
            $answer = trim($form->getSubmitValue('answer['.$i.']'));
285
            $comment = trim($form->getSubmitValue('comment['.$i.']'));
286
            $goodAnswer = trim($form->getSubmitValue('correct['.$i.']'));
287
            if (empty($options)) {
288
                // If this is the first time that the question is created then change
289
                // the default values from the form 1 and 2 by the correct "option id" registered
290
                if (!empty($goodAnswer)) {
291
                    $goodAnswer = $sortedByPosition[$goodAnswer]['iid'];
292
                }
293
            }
294
            $questionWeighting += $extraValues[0]; //By default 0 has the correct answers
295
            $objAnswer->createAnswer($answer, $goodAnswer, $comment, '', $i);
296
        }
297
298
        // saves the answers into the data base
299
        $objAnswer->save();
300
301
        // sets the total weighting of the question
302
        $this->updateWeighting($questionWeighting);
303
        $this->save($exercise);
304
    }
305
306
    public function return_header(Exercise $exercise, $counter = null, $score = [])
307
    {
308
        $header = parent::return_header($exercise, $counter, $score);
309
        $header .= '<table class="'.$this->question_table_class.'"><tr>';
310
        $header .= '<th>'.get_lang('Your choice').'</th>';
311
312
        if ($exercise->showExpectedChoiceColumn()) {
313
            $header .= '<th>'.get_lang('Expected choice').'</th>';
314
        }
315
316
        $header .= '<th>'
317
            .get_lang('Answer')
318
            .'</th><th colspan="2" style="text-align:center;">'
319
            .get_lang('Your degree of certainty')
320
            .'</th>'
321
        ;
322
        if (false === $exercise->hideComment) {
323
            if (EXERCISE_FEEDBACK_TYPE_EXAM != $exercise->getFeedbackType()) {
324
                $header .= '<th>'.get_lang('Comment').'</th>';
325
            }
326
        }
327
        $header .= '</tr>';
328
329
        return $header;
330
    }
331
332
    /**
333
     * Get color code, status, label and description for the current answer.
334
     *
335
     * @param string $studentAnswer
336
     * @param string $expectedAnswer
337
     * @param int    $studentDegreeChoicePosition
338
     *
339
     * @return array An array with indexes 'color', 'background-color', 'status', 'label' and 'description'
340
     */
341
    public function getResponseDegreeInfo($studentAnswer, $expectedAnswer, $studentDegreeChoicePosition)
342
    {
343
        $result = [];
344
        if (3 == $studentDegreeChoicePosition) {
345
            $result = [
346
                'color' => '#000000',
347
                'background-color' => '#F6BA2A',
348
                'status' => self::LEVEL_WHITE,
349
                'label' => get_lang('Declared ignorance'),
350
                'description' => get_lang('Declared ignoranceDescription'),
351
            ];
352
        } else {
353
            $checkResult = $studentAnswer == $expectedAnswer ? true : false;
354
            if ($checkResult) {
355
                if ($studentDegreeChoicePosition >= 6) {
356
                    $result = [
357
                        'color' => '#FFFFFF',
358
                        'background-color' => '#1E9C55',
359
                        'status' => self::LEVEL_DARKGREEN,
360
                        'label' => get_lang('Very sure'),
361
                        'description' => get_lang('Very sureDescription'),
362
                    ];
363
                } elseif ($studentDegreeChoicePosition >= 4 && $studentDegreeChoicePosition <= 5) {
364
                    $result = [
365
                        'color' => '#000000',
366
                        'background-color' => '#B1E183',
367
                        'status' => self::LEVEL_LIGHTGREEN,
368
                        'label' => get_lang('Pretty sure'),
369
                        'description' => get_lang('Pretty sureDescription'),
370
                    ];
371
                }
372
            } else {
373
                if ($studentDegreeChoicePosition >= 6) {
374
                    $result = [
375
                        'color' => '#FFFFFF',
376
                        'background-color' => '#ED4040',
377
                        'status' => self::LEVEL_DARKRED,
378
                        'label' => get_lang('Very unsure'),
379
                        'description' => get_lang('Very unsureDescription'),
380
                    ];
381
                } elseif ($studentDegreeChoicePosition >= 4 && $studentDegreeChoicePosition <= 5) {
382
                    $result = [
383
                        'color' => '#000000',
384
                        'background-color' => '#F79B88',
385
                        'status' => self::LEVEL_LIGHTRED,
386
                        'label' => get_lang('Unsure'),
387
                        'description' => get_lang('UnsureDescription'),
388
                    ];
389
                }
390
            }
391
        }
392
393
        return $result;
394
    }
395
396
    /**
397
     * Method to show the code color and his meaning for the test result.
398
     */
399
    public static function showColorCodes()
400
    {
401
        ?>
402
        <table class="fc-border-separate" cellspacing="0" style="width:600px;
403
            margin: auto; border: 3px solid #A39E9E;" >
404
            <tr style="border-bottom: 1px solid #A39E9E;">
405
                <td style="width:15%; height:30px; background-color: #088A08; border-right: 1px solid #A39E9E;">
406
                    &nbsp;
407
                </td>
408
                <td style="padding-left:10px;">
409
                    <b><?php echo get_lang('Very sure'); ?> :</b>
410
                    <?php echo get_lang('Very sureDescription'); ?>
411
                </td>
412
            </tr>
413
            <tr style="border-bottom: 1px solid #A39E9E;">
414
                <td style="width:15%; height:30px; background-color: #A9F5A9; border-right: 1px solid #A39E9E;">
415
                    &nbsp;
416
                </td>
417
                <td style="padding-left:10px;">
418
                    <b><?php echo get_lang('Pretty sure'); ?> :</b>
419
                    <?php echo get_lang('Pretty sureDescription'); ?>
420
                </td>
421
            </tr>
422
            <tr style="border: 1px solid #A39E9E;">
423
                <td style="width:15%; height:30px; background-color: #FFFFFF; border-right: 1px solid #A39E9E;">
424
                    &nbsp;
425
                </td>
426
                <td style="padding-left:10px;">
427
                    <b><?php echo get_lang('Declared ignorance'); ?> :</b>
428
                    <?php echo get_lang('Declared ignoranceDescription'); ?>
429
                </td>
430
            </tr>
431
            <tr style="border: 1px solid #A39E9E;">
432
                <td style="width:15%; height:30px; background-color: #F6CECE; border-right: 1px solid #A39E9E;">
433
                    &nbsp;
434
                </td>
435
                <td style="padding-left:10px;">
436
                    <b><?php echo get_lang('Unsure'); ?> :</b>
437
                    <?php echo get_lang('UnsureDescription'); ?>
438
                </td>
439
            </tr>
440
            <tr style="border-bottom: 1px solid #A39E9E;">
441
                <td style="width:15%; height:30px; background-color: #FE2E2E; border-right: 1px solid #A39E9E;">
442
                    &nbsp;
443
                </td>
444
                <td style="padding-left:10px;">
445
                    <b><?php echo get_lang('Very unsure'); ?> :</b>
446
                    <?php echo get_lang('Very unsureDescription'); ?>
447
                </td>
448
            </tr>
449
        </table><br/>
450
        <?php
451
    }
452
453
    /**
454
     * Display basic bar charts of results by category of questions.
455
     *
456
     * @param array  $scoreListAll
457
     * @param string $title        The block title
458
     * @param int    $sizeRatio
459
     *
460
     * @return string The HTML/CSS code for the charts block
461
     */
462
    public static function displayDegreeChartByCategory($scoreListAll, $title, $sizeRatio = 1)
463
    {
464
        $maxHeight = 0;
465
        $groupCategoriesByBracket = false;
466
        if ($groupCategoriesByBracket) {
467
            $scoreList = [];
468
            $categoryPrefixList = [];
469
            // categoryPrefix['Math'] = firstCategoryId for this prefix
470
            // rebuild $scoreList factorizing data with category prefix
471
            foreach ($scoreListAll as $categoryId => $scoreListForCategory) {
472
                $objCategory = new Testcategory();
473
                $objCategoryNum = $objCategory->getCategory($categoryId);
474
                preg_match("/^\[([^]]+)\]/", $objCategoryNum->name, $matches);
475
476
                if (count($matches) > 1) {
477
                    // check if we have already see this prefix
478
                    if (array_key_exists($matches[1], $categoryPrefixList)) {
479
                        // add the result color for this entry
480
                        $scoreList[$categoryPrefixList[$matches[1]]][self::LEVEL_DARKGREEN] +=
481
                            $scoreListForCategory[self::LEVEL_DARKGREEN];
482
                        $scoreList[$categoryPrefixList[$matches[1]]][self::LEVEL_LIGHTGREEN] +=
483
                            $scoreListForCategory[self::LEVEL_LIGHTGREEN];
484
                        $scoreList[$categoryPrefixList[$matches[1]]][self::LEVEL_WHITE] +=
485
                            $scoreListForCategory[self::LEVEL_WHITE];
486
                        $scoreList[$categoryPrefixList[$matches[1]]][self::LEVEL_LIGHTRED] +=
487
                            $scoreListForCategory[self::LEVEL_LIGHTRED];
488
                        $scoreList[$categoryPrefixList[$matches[1]]][self::LEVEL_DARKRED] +=
489
                            $scoreListForCategory[self::LEVEL_DARKRED];
490
                    } else {
491
                        $categoryPrefixList[$matches[1]] = $categoryId;
492
                        $scoreList[$categoryId] = $scoreListAll[$categoryId];
493
                    }
494
                } else {
495
                    // doesn't match the prefix '[math] Math category'
496
                    $scoreList[$categoryId] = $scoreListAll[$categoryId];
497
                }
498
            }
499
        } else {
500
            $scoreList = $scoreListAll;
501
        }
502
503
        // get the max height of item to have each table the same height if displayed side by side
504
        foreach ($scoreList as $categoryId => $scoreListForCategory) {
505
            [$noValue, $height] = self::displayDegreeChartChildren(
506
                $scoreListForCategory,
507
                300,
508
                '',
509
                1,
510
                0,
511
                false,
512
                true,
513
                0
514
            );
515
            if ($height > $maxHeight) {
516
                $maxHeight = $height;
517
            }
518
        }
519
520
        $html = '<div class="row-chart">';
521
        $html .= '<h4 class="chart-title">'.$title.'</h4>';
522
523
        $legendTitle = [
524
            'Very unsure',
525
            'Unsure',
526
            'Declared ignorance',
527
            'Pretty sure',
528
            'Very sure',
529
        ];
530
        $html .= '<ul class="chart-legend">';
531
        foreach ($legendTitle as $i => $item) {
532
            $html .= '<li><i class="fa fa-square square_color'.$i.'" aria-hidden="true"></i> '.get_lang($item).'</li>';
533
        }
534
        $html .= '</ul>';
535
536
        // get the html of items
537
        $i = 0;
538
        $testCategory = new Testcategory();
539
        foreach ($scoreList as $categoryId => $scoreListForCategory) {
540
            $category = $testCategory->getCategory($categoryId);
541
            $categoryQuestionName = '';
542
            if ($category) {
543
                $categoryQuestionName = $category->name;
544
            }
545
546
            if ('' === $categoryQuestionName) {
547
                $categoryName = get_lang('Without category');
548
            } else {
549
                $categoryName = $categoryQuestionName;
550
            }
551
552
            $html .= '<div class="col-md-4">';
553
            $html .= self::displayDegreeChartChildren(
554
                $scoreListForCategory,
555
                300,
556
                $categoryName,
557
                1,
558
                $maxHeight,
559
                false,
560
                false,
561
                $groupCategoriesByBracket
562
            );
563
            $html .= '</div>';
564
565
            if (2 == $i) {
566
                $html .= '<div style="clear:both; height: 10px;">&nbsp;</div>';
567
                $i = 0;
568
            } else {
569
                $i++;
570
            }
571
        }
572
        $html .= '</div>';
573
574
        return $html.'<div style="clear:both; height: 10px;" >&nbsp;</div>';
575
    }
576
577
    /**
578
     * Return HTML code for the $scoreList of MultipleAnswerTrueFalseDegreeCertainty questions.
579
     *
580
     * @param        $scoreList
581
     * @param        $widthTable
582
     * @param string $title
583
     * @param int    $sizeRatio
584
     * @param int    $minHeight
585
     * @param bool   $displayExplanationText
586
     * @param bool   $returnHeight
587
     * @param bool   $groupCategoriesByBracket
588
     * @param int    $numberOfQuestions
589
     *
590
     * @return array|string
591
     */
592
    public static function displayDegreeChart(
593
        $scoreList,
594
        $widthTable,
595
        $title = '',
596
        $sizeRatio = 1,
597
        $minHeight = 0,
598
        $displayExplanationText = true,
599
        $returnHeight = false,
600
        $groupCategoriesByBracket = false,
601
        $numberOfQuestions = 0
602
    ) {
603
        $topAndBottomMargin = 10;
604
        $colorList = [
605
            self::LEVEL_DARKRED,
606
            self::LEVEL_LIGHTRED,
607
            self::LEVEL_WHITE,
608
            self::LEVEL_LIGHTGREEN,
609
            self::LEVEL_DARKGREEN,
610
        ];
611
612
        // get total attempt number
613
        $highterColorHeight = 0;
614
        foreach ($scoreList as $color => $number) {
615
            if ($number > $highterColorHeight) {
616
                $highterColorHeight = $number;
617
            }
618
        }
619
620
        $totalAttemptNumber = $numberOfQuestions;
621
        $verticalLineHeight = $highterColorHeight * $sizeRatio * 2 + 122 + $topAndBottomMargin * 2;
622
        if ($verticalLineHeight < $minHeight) {
623
            $minHeightCorrection = $minHeight - $verticalLineHeight;
624
            $verticalLineHeight += $minHeightCorrection;
625
        }
626
627
        // draw chart
628
        $html = '';
629
630
        if ($groupCategoriesByBracket) {
631
            $title = api_preg_replace('/[^]]*$/', '', $title);
632
            $title = ucfirst(api_preg_replace("/[\[\]]/", '', $title));
633
        }
634
635
        $titleDisplay = strpos($title, 'ensemble') > 0 ?
636
            $title."<br/>($totalAttemptNumber questions)" :
637
            $title;
638
        $textSize = strpos($title, 'ensemble') > 0 ||
639
            strpos($title, 'votre dernier résultat à ce test') > 0 ? 100 : 80;
640
641
        $html .= '<div class="row-chart">';
642
        $html .= '<h4 class="chart-title">'.$titleDisplay.'</h4>';
643
644
        $nbResponsesInc = 0;
645
        if (isset($scoreList[4])) {
646
            $nbResponsesInc += (int) $scoreList[4];
647
        }
648
        if (isset($scoreList[5])) {
649
            $nbResponsesInc += (int) $scoreList[5];
650
        }
651
652
        $nbResponsesIng = isset($scoreList[3]) ? $scoreList[3] : 0;
653
654
        $nbResponsesCor = 0;
655
        if (isset($scoreList[1])) {
656
            $nbResponsesCor += (int) $scoreList[1];
657
        }
658
        if (isset($scoreList[2])) {
659
            $nbResponsesCor += (int) $scoreList[2];
660
        }
661
662
        $IncorrectAnswers = sprintf(get_lang('Incorrect answers: %s'), $nbResponsesInc);
663
        $IgnoranceAnswers = sprintf(get_lang('Ignorance: %s'), $nbResponsesIng);
664
        $CorrectAnswers = sprintf(get_lang('Correct answers: %s'), $nbResponsesCor);
665
666
        $html .= '<div class="chart-grid">';
667
668
        $explainHistoList = null;
669
        if ($displayExplanationText) {
670
            // Display of histogram text
671
            $explainHistoList = [
672
                'Very unsure',
673
                'Unsure',
674
                'Declared ignorance',
675
                'Pretty sure',
676
                'Very sure',
677
            ];
678
        }
679
680
        foreach ($colorList as $i => $color) {
681
            if (array_key_exists($color, $scoreList)) {
682
                $scoreOnBottom = $scoreList[$color]; // height of the colored area on the bottom
683
            } else {
684
                $scoreOnBottom = 0;
685
            }
686
            $sizeBar = ($scoreOnBottom * $sizeRatio * 2).'px;';
687
688
            if (0 == $i) {
689
                $html .= '<div class="item">';
690
                $html .= '<div class="panel-certaint" style="min-height:'.$verticalLineHeight.'px; position: relative;">';
691
                $html .= '<div class="answers-title">'.$IncorrectAnswers.'</div>';
692
                $html .= '<ul class="certaint-list-two">';
693
            } elseif (3 == $i) {
694
                $html .= '<div class="item">';
695
                $html .= '<div class="panel-certaint" style="height:'.$verticalLineHeight.'px;  position: relative;">';
696
                $html .= '<div class="answers-title">'.$CorrectAnswers.'</div>';
697
                $html .= '<ul class="certaint-list-two">';
698
            } elseif (2 == $i) {
699
                $html .= '<div class="item">';
700
                $html .= '<div class="panel-certaint" style="height:'.$verticalLineHeight.'px;  position: relative;">';
701
                $html .= '<div class="answers-title">'.$IgnoranceAnswers.'</div>';
702
                $html .= '<ul class="certaint-list">';
703
            }
704
            $html .= '<li>';
705
            $html .= '<div class="certaint-score">';
706
            $html .= $scoreOnBottom;
707
            $html .= '</div>';
708
            $html .= '<div class="levelbar_'.$color.'" style="height:'.$sizeBar.'">&nbsp;</div>';
709
            $html .= '<div class="certaint-text">'.get_lang($explainHistoList[$i]).'</div>';
710
            $html .= '</li>';
711
712
            if (1 == $i || 2 == $i || 4 == $i) {
713
                $html .= '</ul>';
714
                $html .= '</div>';
715
                $html .= '</div>';
716
            }
717
        }
718
719
        $html .= '</div>';
720
        $html .= '</div>';
721
722
        if ($returnHeight) {
723
            return [$html, $verticalLineHeight];
724
        } else {
725
            return $html;
726
        }
727
    }
728
729
    /**
730
     * Return HTML code for the $scoreList of MultipleAnswerTrueFalseDegreeCertainty questions.
731
     *
732
     * @param        $scoreList
733
     * @param        $widthTable
734
     * @param string $title
735
     * @param int    $sizeRatio
736
     * @param int    $minHeight
737
     * @param bool   $displayExplanationText
738
     * @param bool   $returnHeight
739
     * @param bool   $groupCategoriesByBracket
740
     * @param int    $numberOfQuestions
741
     *
742
     * @return array|string
743
     */
744
    public static function displayDegreeChartChildren(
745
        $scoreList,
746
        $widthTable,
747
        $title = '',
748
        $sizeRatio = 1,
749
        $minHeight = 0,
750
        $displayExplanationText = true,
751
        $returnHeight = false,
752
        $groupCategoriesByBracket = false,
753
        $numberOfQuestions = 0
754
    ) {
755
        $topAndBottomMargin = 10;
756
        $colorList = [
757
            self::LEVEL_DARKRED,
758
            self::LEVEL_LIGHTRED,
759
            self::LEVEL_WHITE,
760
            self::LEVEL_LIGHTGREEN,
761
            self::LEVEL_DARKGREEN,
762
        ];
763
764
        // get total attempt number
765
        $highterColorHeight = 0;
766
        foreach ($scoreList as $color => $number) {
767
            if ($number > $highterColorHeight) {
768
                $highterColorHeight = $number;
769
            }
770
        }
771
772
        $totalAttemptNumber = $numberOfQuestions;
773
        $verticalLineHeight = $highterColorHeight * $sizeRatio * 2 + 122 + $topAndBottomMargin * 2;
774
        if ($verticalLineHeight < $minHeight) {
775
            $minHeightCorrection = $minHeight - $verticalLineHeight;
776
            $verticalLineHeight += $minHeightCorrection;
777
        }
778
779
        // draw chart
780
        $html = '';
781
782
        if ($groupCategoriesByBracket) {
783
            $title = api_preg_replace('/[^]]*$/', '', $title);
784
            $title = ucfirst(api_preg_replace("/[\[\]]/", '', $title));
785
        }
786
787
        $textSize = 80;
788
789
        $classGlobalChart = '';
790
        if ($displayExplanationText) {
791
            // global chart
792
            $classGlobalChart = 'globalChart';
793
        }
794
795
        $html .= '<table class="certaintyTable" style="height :'.$verticalLineHeight.'px; margin-bottom: 10px;" >';
796
        $html .= '<tr><th colspan="5" class="'.$classGlobalChart.'">'
797
            .$title
798
            .'</th><tr>'
799
        ;
800
801
        $nbResponsesInc = 0;
802
        if (isset($scoreList[4])) {
803
            $nbResponsesInc += (int) $scoreList[4];
804
        }
805
        if (isset($scoreList[5])) {
806
            $nbResponsesInc += (int) $scoreList[5];
807
        }
808
809
        $nbResponsesIng = isset($scoreList[3]) ? $scoreList[3] : 0;
810
811
        $nbResponsesCor = 0;
812
        if (isset($scoreList[1])) {
813
            $nbResponsesCor += (int) $scoreList[1];
814
        }
815
        if (isset($scoreList[2])) {
816
            $nbResponsesCor += (int) $scoreList[2];
817
        }
818
819
        $colWidth = $widthTable / 5;
820
821
        $html .= '<tr>
822
                <td class="firstLine borderRight '.$classGlobalChart.'"
823
                    colspan="2"
824
                    style="width:'.($colWidth * 2).'px; line-height: 15px; font-size:'.$textSize.'%;">'.
825
            sprintf(get_lang('Incorrect answers: %s'), $nbResponsesInc).'
826
                </td>
827
                <td class="firstLine borderRight '.$classGlobalChart.'"
828
                    style="width:'.$colWidth.'px; line-height: 15px; font-size :'.$textSize.'%;">'.
829
            sprintf(get_lang('Ignorance: %s'), $nbResponsesIng).'
830
                </td>
831
                <td class="firstLine '.$classGlobalChart.'"
832
                    colspan="2"
833
                    style="width:'.($colWidth * 2).'px; line-height: 15px; font-size:'.$textSize.'%;">'.
834
            sprintf(get_lang('Correct answers: %s'), $nbResponsesCor).'
835
                </td>
836
            </tr>';
837
        $html .= '<tr>';
838
839
        foreach ($colorList as $i => $color) {
840
            if (array_key_exists($color, $scoreList)) {
841
                $scoreOnBottom = $scoreList[$color]; // height of the colored area on the bottom
842
            } else {
843
                $scoreOnBottom = 0;
844
            }
845
            $sizeOnBottom = $scoreOnBottom * $sizeRatio * 2;
846
            if (1 == $i || 2 == $i) {
847
                $html .= '<td width="'
848
                    .$colWidth
849
                    .'px" style="border-right: 1px dotted #7FC5FF; vertical-align: bottom;font-size: '
850
                    .$textSize
851
                    .'%;">'
852
                ;
853
            } else {
854
                $html .= '<td width="'
855
                    .$colWidth
856
                    .'px" style="vertical-align: bottom;font-size: '
857
                    .$textSize
858
                    .'%;">'
859
                ;
860
            }
861
            $html .= '<div class="certaint-score">'
862
                .$scoreOnBottom
863
                .'</div><div class="levelbar_'
864
                .$color
865
                .'" style="height: '
866
                .$sizeOnBottom
867
                .'px;">&nbsp;</div>'
868
            ;
869
            $html .= '</td>';
870
        }
871
872
        $html .= '</tr>';
873
874
        if ($displayExplanationText) {
875
            // Display of histogram text
876
            $explainHistoList = [
877
                'Very unsure',
878
                'Unsure',
879
                'Declared ignorance',
880
                'Pretty sure',
881
                'Very sure',
882
            ];
883
            $html .= '<tr>';
884
            $i = 0;
885
            foreach ($explainHistoList as $explain) {
886
                if (1 == $i || 2 == $i) {
887
                    $class = 'borderRight';
888
                } else {
889
                    $class = '';
890
                }
891
                $html .= '<td class="firstLine '
892
                    .$class
893
                    .' '
894
                    .$classGlobalChart
895
                    .'" style="width="'
896
                    .$colWidth
897
                    .'px; font-size:'
898
                    .$textSize
899
                    .'%;">'
900
                ;
901
                $html .= get_lang($explain);
902
                $html .= '</td>';
903
                $i++;
904
            }
905
            $html .= '</tr>';
906
        }
907
        $html .= '</table></center>';
908
909
        if ($returnHeight) {
910
            return [$html, $verticalLineHeight];
911
        } else {
912
            return $html;
913
        }
914
    }
915
916
    /**
917
     * return previous attempt id for this test for student, 0 if no previous attempt.
918
     *
919
     * @param $exeId
920
     *
921
     * @return int
922
     */
923
    public static function getPreviousAttemptId($exeId)
924
    {
925
        $tblTrackEExercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
926
        $exeId = (int) $exeId;
927
        $sql = "SELECT * FROM $tblTrackEExercise
928
                WHERE exe_id = ".$exeId;
929
        $res = Database::query($sql);
930
931
        if (empty(Database::num_rows($res))) {
932
            // if we cannot find the exe_id
933
            return 0;
934
        }
935
936
        $data = Database::fetch_assoc($res);
937
        $courseCode = $data['c_id'];
938
        $exerciseId = $data['exe_exo_id'];
939
        $userId = $data['exe_user_id'];
940
        $attemptDate = $data['exe_date'];
941
942
        if ('0000-00-00 00:00:00' === $attemptDate) {
943
            // incomplete attempt, close it before continue
944
            return 0;
945
        }
946
947
        // look for previous attempt
948
        $exerciseId = (int) $exerciseId;
949
        $userId = (int) $userId;
950
        $sql = "SELECT *
951
                FROM $tblTrackEExercise
952
                WHERE
953
                      c_id = '$courseCode' AND
954
                      exe_exo_id = $exerciseId AND
955
                      exe_user_id = $userId AND
956
                      status = '' AND
957
                      exe_date > '0000-00-00 00:00:00' AND
958
                      exe_date < '$attemptDate'
959
                ORDER BY exe_date DESC";
960
961
        $res = Database::query($sql);
962
963
        if (0 == Database::num_rows($res)) {
964
            // no previous attempt
965
            return 0;
966
        }
967
968
        $data = Database::fetch_assoc($res);
969
970
        return $data['exe_id'];
971
    }
972
973
    /**
974
     * return an array of number of answer color for exe attempt
975
     * for question type = MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY
976
     * e.g.
977
     * [LEVEL_DARKGREEN => 3, LEVEL_LIGHTGREEN => 0, LEVEL_WHITE => 5, LEVEL_LIGHTRED => 12, LEVEL_DARKTRED => 0].
978
     *
979
     * @param $exeId
980
     *
981
     * @return array
982
     */
983
    public static function getColorNumberListForAttempt($exeId)
984
    {
985
        $result = [
986
            self::LEVEL_DARKGREEN => 0,
987
            self::LEVEL_LIGHTGREEN => 0,
988
            self::LEVEL_WHITE => 0,
989
            self::LEVEL_LIGHTRED => 0,
990
            self::LEVEL_DARKRED => 0,
991
        ];
992
993
        $attemptInfoList = self::getExerciseAttemptInfo($exeId);
994
995
        foreach ($attemptInfoList as $attemptInfo) {
996
            $oQuestion = new self();
997
            $oQuestion->read($attemptInfo['question_id']);
998
            if (MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY == $oQuestion->type) {
999
                $answerColor = self::getAnswerColor($exeId, $attemptInfo['question_id'], $attemptInfo['position']);
1000
                if ($answerColor) {
1001
                    $result[$answerColor]++;
1002
                }
1003
            }
1004
        }
1005
1006
        return $result;
1007
    }
1008
1009
    /**
1010
     * return an array of number of color for question type = MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY
1011
     * for each question category.
1012
     *
1013
     * e.g.
1014
     * [
1015
     *      (categoryId=)5 => [LEVEL_DARKGREEN => 3, LEVEL_WHITE => 5, LEVEL_LIGHTRED => 12]
1016
     *      (categoryId=)2 => [LEVEL_DARKGREEN => 8, LEVEL_LIGHTRED => 2, LEVEL_DARKTRED => 8]
1017
     *      (categoryId=)0 => [LEVEL_DARKGREEN => 1,
1018
     *          LEVEL_LIGHTGREEN => 2,
1019
     *          LEVEL_WHITE => 6,
1020
     *          LEVEL_LIGHTRED => 1,
1021
     *          LEVEL_DARKTRED => 9]
1022
     * ]
1023
     *
1024
     * @param int $exeId
1025
     *
1026
     * @return array
1027
     */
1028
    public static function getColorNumberListForAttemptByCategory($exeId)
1029
    {
1030
        $result = [];
1031
        $attemptInfoList = self::getExerciseAttemptInfo($exeId);
1032
1033
        foreach ($attemptInfoList as $attemptInfo) {
1034
            $oQuestion = new self();
1035
            $oQuestion->read($attemptInfo['question_id']);
1036
            if (MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY == $oQuestion->type) {
1037
                $questionCategory = Testcategory::getCategoryForQuestion($attemptInfo['question_id']);
1038
1039
                if (!array_key_exists($questionCategory, $result)) {
1040
                    $result[$questionCategory] = [];
1041
                }
1042
1043
                $answerColor = self::getAnswerColor($exeId, $attemptInfo['question_id'], $attemptInfo['position']);
1044
                if ($answerColor && isset($result[$questionCategory])) {
1045
                    if (!isset($result[$questionCategory][$answerColor])) {
1046
                        $result[$questionCategory][$answerColor] = 0;
1047
                    }
1048
                    $result[$questionCategory][$answerColor]++;
1049
                }
1050
            }
1051
        }
1052
1053
        return $result;
1054
    }
1055
1056
    /**
1057
     * Return true if answer of $exeId, $questionId, $position is correct, otherwise return false.
1058
     *
1059
     * @param $exeId
1060
     * @param $questionId
1061
     * @param $position
1062
     *
1063
     * @return int
1064
     */
1065
    public static function getAnswerColor($exeId, $questionId, $position)
1066
    {
1067
        $attemptInfoList = self::getExerciseAttemptInfo($exeId, $questionId, $position);
1068
1069
        if (1 != count($attemptInfoList)) {
1070
            // havent got the answer
1071
            return 0;
1072
        }
1073
1074
        $answerCodes = $attemptInfoList[0]['answer'];
1075
1076
        // student answer
1077
        $splitAnswer = preg_split('/:/', $answerCodes);
1078
        // get correct answer option id
1079
        $correctAnswerOptionId = self::getCorrectAnswerOptionId($splitAnswer[0]);
1080
        if (0 == $correctAnswerOptionId) {
1081
            // error returning the correct answer option id
1082
            return 0;
1083
        }
1084
1085
        // get student answer option id
1086
        $studentAnswerOptionId = $splitAnswer[1] ?? null;
1087
1088
        // we got the correct answer option id, let's compare ti with the student answer
1089
        $percentage = null;
1090
        if (isset($splitAnswer[2])) {
1091
            $percentage = self::getPercentagePosition($splitAnswer[2]);
1092
        }
1093
1094
        if ($studentAnswerOptionId == $correctAnswerOptionId) {
1095
            // yeah, student got correct answer
1096
            switch ($percentage) {
1097
                case 3:
1098
                    return self::LEVEL_WHITE;
1099
                case 4:
1100
                case 5:
1101
                    return self::LEVEL_LIGHTGREEN;
1102
                case 6:
1103
                case 7:
1104
                case 8:
1105
                    return self::LEVEL_DARKGREEN;
1106
                default:
1107
                    return 0;
1108
            }
1109
        } else {
1110
            // bummer, wrong answer dude
1111
            switch ($percentage) {
1112
                case 3:
1113
                    return self::LEVEL_WHITE;
1114
                case 4:
1115
                case 5:
1116
                    return self::LEVEL_LIGHTRED;
1117
                case 6:
1118
                case 7:
1119
                case 8:
1120
                    return self::LEVEL_DARKRED;
1121
                default:
1122
                    return 0;
1123
            }
1124
        }
1125
    }
1126
1127
    /**
1128
     * Return the position of certitude %age choose by student.
1129
     *
1130
     * @param $optionId
1131
     *
1132
     * @return int
1133
     */
1134
    public static function getPercentagePosition($optionId)
1135
    {
1136
        $tblAnswerOption = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION);
1137
        $courseId = api_get_course_int_id();
1138
        $optionId = (int) $optionId;
1139
        $sql = "SELECT position
1140
                FROM $tblAnswerOption
1141
                WHERE c_id = $courseId AND id = $optionId";
1142
        $res = Database::query($sql);
1143
1144
        if (0 == Database::num_rows($res)) {
1145
            return 0;
1146
        }
1147
1148
        $data = Database::fetch_assoc($res);
1149
1150
        return $data['position'];
1151
    }
1152
1153
    /**
1154
     * return the correct id from c_quiz_question_option for question idAuto.
1155
     *
1156
     * @param $idAuto
1157
     *
1158
     * @return int
1159
     */
1160
    public static function getCorrectAnswerOptionId($idAuto)
1161
    {
1162
        $tblAnswer = Database::get_course_table(TABLE_QUIZ_ANSWER);
1163
        $idAuto = (int) $idAuto;
1164
        $sql = "SELECT correct FROM $tblAnswer
1165
                WHERE iid = $idAuto";
1166
1167
        $res = Database::query($sql);
1168
        $data = Database::fetch_assoc($res);
1169
        if (Database::num_rows($res) > 0) {
1170
            return $data['correct'];
1171
        }
1172
1173
        return 0;
1174
    }
1175
1176
    /**
1177
     * return an array of exe info from track_e_attempt.
1178
     *
1179
     * @param int $exeId
1180
     * @param int $questionId
1181
     * @param int $position
1182
     *
1183
     * @return array
1184
     */
1185
    public static function getExerciseAttemptInfo($exeId, $questionId = -1, $position = -1)
1186
    {
1187
        $result = [];
1188
        $and = '';
1189
        $questionId = (int) $questionId;
1190
        $position = (int) $position;
1191
        $exeId = (int) $exeId;
1192
1193
        if ($questionId >= 0) {
1194
            $and .= " AND question_id = $questionId";
1195
        }
1196
        if ($position >= 0) {
1197
            $and .= " AND position = $position";
1198
        }
1199
1200
        $tblExeAttempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1201
        $cId = api_get_course_int_id();
1202
        $sql = "SELECT * FROM $tblExeAttempt
1203
                WHERE c_id = $cId AND exe_id = $exeId $and";
1204
1205
        $res = Database::query($sql);
1206
        while ($data = Database::fetch_assoc($res)) {
1207
            $result[] = $data;
1208
        }
1209
1210
        return $result;
1211
    }
1212
1213
    /**
1214
     * @param int $exeId
1215
     *
1216
     * @return int
1217
     */
1218
    public static function getNumberOfQuestionsForExeId($exeId)
1219
    {
1220
        $tableTrackEExercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1221
        $exeId = (int) $exeId;
1222
1223
        $sql = "SELECT exe_exo_id
1224
                FROM $tableTrackEExercise
1225
                WHERE exe_id=".$exeId;
1226
        $res = Database::query($sql);
1227
        $data = Database::fetch_assoc($res);
1228
        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...
1229
            $exerciseId = $data['exe_exo_id'];
1230
1231
            $objectExercise = new Exercise();
1232
            $objectExercise->read($exerciseId);
1233
1234
            return $objectExercise->getQuestionCount();
1235
        }
1236
1237
        return 0;
1238
    }
1239
1240
    /**
1241
     * Display student chart results for these question types.
1242
     *
1243
     * @param int      $exeId
1244
     * @param Exercise $objExercice
1245
     *
1246
     * @return string
1247
     */
1248
    public static function displayStudentsChartResults($exeId, $objExercice)
1249
    {
1250
        $numberOfQuestions = self::getNumberOfQuestionsForExeId($exeId);
1251
        $globalScoreList = self::getColorNumberListForAttempt($exeId);
1252
        $html = self::displayDegreeChart(
1253
            $globalScoreList,
1254
            600,
1255
            get_lang('Your overall results for the test'),
1256
            2,
1257
            0,
1258
            true,
1259
            false,
1260
            false,
1261
            $numberOfQuestions
1262
        );
1263
        $html .= '<br/>';
1264
1265
        $previousAttemptId = self::getPreviousAttemptId($exeId);
1266
        if ($previousAttemptId > 0) {
1267
            $previousAttemptScoreList = self::getColorNumberListForAttempt(
1268
                $previousAttemptId
1269
            );
1270
            $html .= self::displayDegreeChart(
1271
                $previousAttemptScoreList,
1272
                600,
1273
                get_lang('In comparison, your latest results for this test'),
1274
                2
1275
            );
1276
            $html .= '<br/>';
1277
        }
1278
1279
        $list = self::getColorNumberListForAttemptByCategory($exeId);
1280
        $html .= self::displayDegreeChartByCategory(
1281
            $list,
1282
            get_lang('Your results by discipline'),
1283
            1,
1284
            $objExercice
1285
        );
1286
        $html .= '<br/>';
1287
1288
        return $html;
1289
    }
1290
1291
    /**
1292
     * send mail to student with degre certainty result test.
1293
     *
1294
     * @param int      $userId
1295
     * @param Exercise $objExercise
1296
     * @param int      $exeId
1297
     */
1298
    public static function sendQuestionCertaintyNotification($userId, $objExercise, $exeId)
1299
    {
1300
        $userInfo = api_get_user_info($userId);
1301
        $recipientName = api_get_person_name($userInfo['firstname'],
1302
            $userInfo['lastname'],
1303
            null,
1304
            PERSON_NAME_EMAIL_ADDRESS
1305
        );
1306
        $subject = '['.get_lang('Please do not reply').'] '
1307
            .html_entity_decode(get_lang('Results for the accomplished test').' "'.$objExercise->title.'"');
1308
1309
        // message sended to the student
1310
        $message = get_lang('Dear').' '.$recipientName.',<br /><br />';
1311
        $exerciseLink = "<a href='".api_get_path(WEB_CODE_PATH).'/exercise/result.php?show_headers=1&'
1312
            .api_get_cidreq()
1313
            ."&id=$exeId'>";
1314
        $exerciseTitle = $objExercise->title;
1315
1316
        $message .= sprintf(
1317
            get_lang('Please follow the instructions below to check your results for test %s.<br /><br />'),
1318
            $exerciseTitle,
1319
            api_get_path(WEB_PATH),
1320
            $exerciseLink
1321
        );
1322
1323
        // show histogram
1324
        $message .= self::displayStudentsChartResults($exeId, $objExercise);
1325
        $message .= get_lang('Kind regards,');
1326
        $message = api_preg_replace("/\\\n/", '', $message);
1327
1328
        MessageManager::send_message_simple($userId, $subject, $message);
1329
    }
1330
}
1331