Completed
Push — master ( 5f1c93...626f54 )
by Julito
31:28
created

FillBlanks::getFillTheBlankHtml()   C

Complexity

Conditions 9
Paths 5

Size

Total Lines 53
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 39
nc 5
nop 10
dl 0
loc 53
rs 6.8963
c 0
b 0
f 0

How to fix   Long Method    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
/* For licensing terms, see /license.txt */
3
4
/**
5
 *	Class FillBlanks
6
 *
7
 *	@author Eric Marguin
8
 * 	@author Julio Montoya multiple fill in blank option added
9
 *	@package chamilo.exercise
10
 **/
11
class FillBlanks extends Question
12
{
13
    public static $typePicture = 'fill_in_blanks.png';
14
    public static $explanationLangVar = 'FillBlanks';
15
16
    const FILL_THE_BLANK_STANDARD = 0;
17
    const FILL_THE_BLANK_MENU = 1;
18
    const FILL_THE_BLANK_SEVERAL_ANSWER = 2;
19
20
    /**
21
     * Constructor
22
     */
23
    public function __construct()
24
    {
25
        parent::__construct();
26
        $this->type = FILL_IN_BLANKS;
27
        $this->isContent = $this->getIsContent();
28
    }
29
30
    /**
31
     * function which redefines Question::createAnswersForm
32
     * @param FormValidator $form
33
     */
34
    public function createAnswersForm($form)
35
    {
36
        //$fillBlanksAllowedSeparator = self::getAllowedSeparator();
37
        $defaults = array();
38
39
        if (!empty($this->id)) {
40
            $objectAnswer = new Answer($this->id);
41
            $answer = $objectAnswer->selectAnswer(1);
42
            $listAnswersInfo = FillBlanks::getAnswerInfo($answer);
43
            if ($listAnswersInfo['switchable']) {
44
                $defaults['multiple_answer'] = 1;
45
            } else {
46
                $defaults['multiple_answer'] = 0;
47
            }
48
            //take the complete string except after the last '::'
49
            $defaults['answer'] = $listAnswersInfo['text'];
50
            $defaults['select_separator'] = $listAnswersInfo['blankseparatornumber'];
51
            $blankSeparatorNumber = $listAnswersInfo['blankseparatornumber'];
52
        } else {
53
            $defaults['answer'] = get_lang('DefaultTextInBlanks');
54
            $defaults['select_separator'] = 0;
55
            $blankSeparatorNumber = 0;
56
        }
57
58
        $blankSeparatorStart = self::getStartSeparator($blankSeparatorNumber);
59
        $blankSeparatorEnd = self::getEndSeparator($blankSeparatorNumber);
60
61
        $setWeightAndSize = '';
62
        if (isset($listAnswersInfo) && count($listAnswersInfo['tabweighting']) > 0) {
63
            foreach ($listAnswersInfo['tabweighting'] as $i => $weighting) {
64
                $setWeightAndSize .= 'document.getElementById("weighting['.$i.']").value = "'.$weighting.'";';
65
            }
66
            foreach ($listAnswersInfo['tabinputsize'] as $i => $sizeOfInput) {
67
                //var_dump($listAnswersInfo['tabwords']);
68
                $setWeightAndSize .= 'document.getElementById("sizeofinput['.$i.']").value = "'.$sizeOfInput.'";';
69
                $setWeightAndSize .= 'document.getElementById("samplesize['.$i.']").style.width = "'.$sizeOfInput.'px";';
70
            }
71
        }
72
73
        echo '<script>
74
            
75
            var firstTime = true;            
76
            var originalOrder = new Array();   
77
            var blankSeparatorStart = "'.$blankSeparatorStart.'";
78
            var blankSeparatorEnd = "'.$blankSeparatorEnd.'";
79
            var blankSeparatorStartRegexp = getBlankSeparatorRegexp(blankSeparatorStart);
80
            var blankSeparatorEndRegexp = getBlankSeparatorRegexp(blankSeparatorEnd);
81
            var blanksRegexp = "/"+blankSeparatorStartRegexp+"[^"+blankSeparatorStartRegexp+"]*"+blankSeparatorEndRegexp+"/g";
82
            
83
            CKEDITOR.on("instanceCreated", function(e) {
84
                if (e.editor.name === "answer") {                  
85
                    //e.editor.on("change", updateBlanks);
86
                    e.editor.on("change", function(){
87
                        updateBlanks();
88
                    });
89
                }
90
            });                        
91
            
92
            function updateBlanks()
93
            {
94
                
95
                var answer;                
96
                if (firstTime) {
97
                    var field = document.getElementById("answer");
98
                    answer = field.value;
99
                } else {
100
                    answer = CKEDITOR.instances["answer"].getData();
101
                }
102
                                
103
                // disable the save button, if not blanks have been created
104
                $("button").attr("disabled", "disabled");
105
                $("#defineoneblank").show();                
106
                var blanks = answer.match(eval(blanksRegexp));             
107
                var fields = "<div class=\"form-group \">";                
108
                fields += "<label class=\"col-sm-2 control-label\">'.get_lang('Weighting').'</label>";
109
                fields += "<div class=\"col-sm-8\">";
110
                fields += "<table>";
111
                fields += "<tr><th style=\"padding:0 20px\">'.get_lang("WordTofind").'</th><th style=\"padding:0 20px\">'.get_lang("QuestionWeighting").'</th><th style=\"padding:0 20px\">'.get_lang("BlankInputSize").'</th></tr>";
112
113
                if (blanks != null) {
114
                    for (var i=0; i < blanks.length; i++) {
115
                        // remove forbidden characters that causes bugs
116
                        blanks[i] = removeForbiddenChars(blanks[i]);                        
117
                        // trim blanks between brackets
118
                        blanks[i] = trimBlanksBetweenSeparator(blanks[i], blankSeparatorStart, blankSeparatorEnd);
119
                        
120
                        // if the word is empty []
121
                        if (blanks[i] == blankSeparatorStartRegexp+blankSeparatorEndRegexp) {
122
                            break;
123
                        }
124
                        
125
                        // get input size
126
                        var inputSize = 200;                        
127
                        var textValue = blanks[i].substr(1, blanks[i].length - 2);
128
                        var btoaValue = textValue.hashCode();
129
                                                                      
130
                        if (firstTime == false) {
131
                            var element = document.getElementById("samplesize["+i+"]");                                
132
                            if (element) {
133
                                inputSize = document.getElementById("sizeofinput["+i+"]").value;                                
134
                            }
135
                        }                                                                    
136
137
                        if (document.getElementById("weighting["+i+"]")) {
138
                            var value = document.getElementById("weighting["+i+"]").value;
139
                        } else {
140
                            var value = "10";    
141
                        }                                            
142
                        
143
                        fields += "<tr>";
144
                        fields += "<td>"+blanks[i]+"</td>";
145
                        fields += "<td><input style=\"width:35px\" value=\""+value+"\" type=\"text\" id=\"weighting["+i+"]\" name=\"weighting["+i+"]\" /></td>";
146
                        fields += "<td>";
147
                        fields += "<input class=\"btn btn-default\" type=\"button\" value=\"-\" onclick=\"changeInputSize(-1, "+i+")\">&nbsp;";
148
                        fields += "<input class=\"btn btn-default\" type=\"button\" value=\"+\" onclick=\"changeInputSize(1, "+i+")\">&nbsp;";
149
                        fields += "<input class=\"sample\" id=\"samplesize["+i+"]\" data-btoa=\""+btoaValue+"\"   type=\"text\" value=\""+textValue+"\" style=\"width:"+inputSize+"px\" disabled=disabled />";
150
                        fields += "<input id=\"sizeofinput["+i+"]\" type=\"hidden\" value=\""+inputSize+"\" name=\"sizeofinput["+i+"]\"  />";
151
                        fields += "</td>";
152
                        fields += "</tr>";
153
                        
154
                        // enable the save button
155
                        $("button").removeAttr("disabled");
156
                        $("#defineoneblank").hide();
157
                    }
158
                }                         
159
                
160
                document.getElementById("blanks_weighting").innerHTML = fields + "</table></div></div>";                                
161
                $(originalOrder).each(function(i, data) {
162
                     if (firstTime == false) {
163
                        value = data.value;                        
164
                        var d = $("input.sample[data-btoa=\'"+value+"\']");                        
165
                        var id = d.attr("id");   
166
                        if (id) {
167
                            var sizeInputId = id.replace("samplesize", "sizeofinput");                            
168
                            var sizeInputId = sizeInputId.replace("[", "\\\[");
169
                            var sizeInputId = sizeInputId.replace("]", "\\\]");                       
170
                                                         
171
                            $("#"+sizeInputId).val(data.width);                        
172
                            d.outerWidth(data.width+"px");
173
                        }
174
                    }
175
                });
176
                
177
                updateOrder(blanks);               
178
179
                if (firstTime) {
180
                    firstTime = false;
181
                    '.$setWeightAndSize.'
182
                }
183
            }
184
185
            window.onload = updateBlanks;
186
            
187
            String.prototype.hashCode = function() {
188
  var hash = 0, i, chr, len;
189
  if (this.length === 0) return hash;
190
  for (i = 0, len = this.length; i < len; i++) {
191
    chr   = this.charCodeAt(i);
192
    hash  = ((hash << 5) - hash) + chr;
193
    hash |= 0; // Convert to 32bit integer
194
  }
195
  return hash;
196
};
197
            
198
            function updateOrder(blanks) 
199
            {
200
                originalOrder = new Array();                
201
                 if (blanks != null) {
202
                    for (var i=0; i < blanks.length; i++) {
203
                        // remove forbidden characters that causes bugs
204
                        blanks[i] = removeForbiddenChars(blanks[i]);                        
205
                        // trim blanks between brackets
206
                        blanks[i] = trimBlanksBetweenSeparator(blanks[i], blankSeparatorStart, blankSeparatorEnd);
207
                        
208
                        // if the word is empty []
209
                        if (blanks[i] == blankSeparatorStartRegexp+blankSeparatorEndRegexp) {
210
                            break;
211
                        }                        
212
                        var textValue = blanks[i].substr(1, blanks[i].length - 2);
213
                        var btoaValue = textValue.hashCode();
214
                        
215
                        if (firstTime == false) {
216
                            var element = document.getElementById("samplesize["+i+"]");                                
217
                            if (element) {
218
                                inputSize = document.getElementById("sizeofinput["+i+"]").value;
219
                                originalOrder.push({ "width" : inputSize, "value": btoaValue });                                                                               
220
                            }
221
                        }
222
                    }
223
                }
224
            }
225
            
226
            function changeInputSize(coef, inIdNum)
227
            {
228
                if (firstTime) {
229
                    var field = document.getElementById("answer");
230
                    answer = field.value;
231
                } else {
232
                    answer = CKEDITOR.instances["answer"].getData();
233
                }
234
                
235
                var blanks = answer.match(eval(blanksRegexp));
236
                var currentWidth = $("#samplesize\\\["+inIdNum+"\\\]").width();
237
                var newWidth = currentWidth + coef * 20;
238
                newWidth = Math.max(20, newWidth);
239
                newWidth = Math.min(newWidth, 600);
240
                $("#samplesize\\\["+inIdNum+"\\\]").outerWidth(newWidth);
241
                $("#sizeofinput\\\["+inIdNum+"\\\]").attr("value", newWidth);
242
                
243
                updateOrder(blanks); 
244
            }
245
246
            function removeForbiddenChars(inTxt)
247
            {
248
                outTxt = inTxt;
249
                outTxt = outTxt.replace(/&quot;/g, ""); // remove the   char
250
                outTxt = outTxt.replace(/\x22/g, ""); // remove the   char
251
                outTxt = outTxt.replace(/"/g, ""); // remove the   char
252
                outTxt = outTxt.replace(/\\\\/g, ""); // remove the \ char
253
                outTxt = outTxt.replace(/&nbsp;/g, " ");
254
                outTxt = outTxt.replace(/^ +/, "");
255
                outTxt = outTxt.replace(/ +$/, "");
256
                return outTxt;
257
            }
258
259
            function changeBlankSeparator()
260
            {
261
                var separatorNumber = $("#select_separator").val();
262
                var tabSeparator = getSeparatorFromNumber(separatorNumber);
263
                blankSeparatorStart = tabSeparator[0];
264
                blankSeparatorEnd = tabSeparator[1];
265
                blankSeparatorStartRegexp = getBlankSeparatorRegexp(blankSeparatorStart);
266
                blankSeparatorEndRegexp = getBlankSeparatorRegexp(blankSeparatorEnd);
267
                blanksRegexp = "/"+blankSeparatorStartRegexp+"[^"+blankSeparatorStartRegexp+"]*"+blankSeparatorEndRegexp+"/g";
268
                updateBlanks();
269
            }
270
271
            // this function is the same than the PHP one
272
            // if modify it modify the php one escapeForRegexp
273
            function getBlankSeparatorRegexp(inTxt)
274
            {
275
                var tabSpecialChar = new Array(".", "+", "*", "?", "[", "^", "]", "$", "(", ")",
276
                    "{", "}", "=", "!", "<", ">", "|", ":", "-", ")");
277
                for (var i=0; i < tabSpecialChar.length; i++) {
278
                    if (inTxt == tabSpecialChar[i]) {
279
                        return "\\\"+inTxt;
280
                    }
281
                }
282
                return inTxt;
283
            }
284
285
            // this function is the same than the PHP one
286
            // if modify it modify the php one getAllowedSeparator
287
            function getSeparatorFromNumber(innumber)
288
            {
289
                tabSeparator = new Array();
290
                tabSeparator[0] = new Array("[", "]");
291
                tabSeparator[1] = new Array("{", "}");
292
                tabSeparator[2] = new Array("(", ")");
293
                tabSeparator[3] = new Array("*", "*");
294
                tabSeparator[4] = new Array("#", "#");
295
                tabSeparator[5] = new Array("%", "%");
296
                tabSeparator[6] = new Array("$", "$");
297
                return tabSeparator[innumber];
298
            }
299
300
            function trimBlanksBetweenSeparator(inTxt, inSeparatorStart, inSeparatorEnd)
301
            {
302
                var result = inTxt
303
                result = result.replace(inSeparatorStart, "");
304
                result = result.replace(inSeparatorEnd, "");
305
                result = result.trim();
306
                return inSeparatorStart+result+inSeparatorEnd;
307
            }
308
        </script>';
309
310
        // answer
311
        $form->addLabel(
312
            null,
313
            '<br /><br />'.get_lang('TypeTextBelow').', '.get_lang('And').' '.get_lang('UseTagForBlank')
314
        );
315
        $form->addElement(
316
            'html_editor',
317
            'answer',
318
            Display::return_icon('fill_field.png'),
319
            ['id' => 'answer'],
320
            array('ToolbarSet' => 'TestQuestionDescription')
321
        );
322
        $form->addRule('answer', get_lang('GiveText'), 'required');
323
324
        //added multiple answers
325
        $form->addElement('checkbox', 'multiple_answer', '', get_lang('FillInBlankSwitchable'));
326
        $form->addElement(
327
            'select',
328
            'select_separator',
329
            get_lang("SelectFillTheBlankSeparator"),
330
            self::getAllowedSeparatorForSelect(),
331
            ' id="select_separator" style="width:150px" onchange="changeBlankSeparator()" '
332
        );
333
        $form->addLabel(
334
            null,
335
            '<input type="button" onclick="updateBlanks()" value="'.get_lang('RefreshBlanks').'" class="btn btn-default" />'
336
        );
337
        $form->addHtml('<div id="blanks_weighting"></div>');
338
339
        global $text;
340
        // setting the save button here and not in the question class.php
341
        $form->addHtml('<div id="defineoneblank" style="color:#D04A66; margin-left:160px">'.get_lang('DefineBlanks').'</div>');
342
        $form->addButtonSave($text, 'submitQuestion');
343
344
        if (!empty($this->id)) {
345
            $form->setDefaults($defaults);
346
        } else {
347
            if ($this->isContent == 1) {
348
                $form->setDefaults($defaults);
349
            }
350
        }
351
    }
352
353
    /**
354
     * Function which creates the form to create/edit the answers of the question
355
     * @param FormValidator $form
356
     */
357
    public function processAnswersCreation($form)
358
    {
359
        $answer = $form->getSubmitValue('answer');
360
        // Due the ckeditor transform the elements to their HTML value
361
362
        //$answer = api_html_entity_decode($answer, ENT_QUOTES, $charset);
363
        //$answer = htmlentities(api_utf8_encode($answer));
364
365
        // remove the :: eventually written by the user
366
        $answer = str_replace('::', '', $answer);
367
368
        // remove starting and ending space and &nbsp;
369
        $answer = api_preg_replace("/\xc2\xa0/", " ", $answer);
370
371
        // start and end separator
372
        $blankStartSeparator = self::getStartSeparator($form->getSubmitValue('select_separator'));
373
        $blankEndSeparator = self::getEndSeparator($form->getSubmitValue('select_separator'));
374
        $blankStartSeparatorRegexp = self::escapeForRegexp($blankStartSeparator);
375
        $blankEndSeparatorRegexp = self::escapeForRegexp($blankEndSeparator);
376
377
        // remove spaces at the beginning and the end of text in square brackets
378
        $answer = preg_replace_callback(
379
            "/".$blankStartSeparatorRegexp."[^]]+".$blankEndSeparatorRegexp."/",
380
            function ($matches) use ($blankStartSeparator, $blankEndSeparator) {
381
                $matchingResult = $matches[0];
382
                $matchingResult = trim($matchingResult, $blankStartSeparator);
383
                $matchingResult = trim($matchingResult, $blankEndSeparator);
384
                $matchingResult = trim($matchingResult);
385
                // remove forbidden chars
386
                $matchingResult = str_replace("/\\/", "", $matchingResult);
387
                $matchingResult = str_replace('/"/', "", $matchingResult);
388
389
                return $blankStartSeparator.$matchingResult.$blankEndSeparator;
390
            },
391
            $answer
392
        );
393
394
        // get the blanks weightings
395
        $nb = preg_match_all(
396
            '/'.$blankStartSeparatorRegexp.'[^'.$blankStartSeparatorRegexp.']*'.$blankEndSeparatorRegexp.'/',
397
            $answer,
398
            $blanks
399
        );
400
401
        if (isset($_GET['editQuestion'])) {
402
            $this->weighting = 0;
403
        }
404
405
        /* if we have some [tobefound] in the text
406
        build the string to save the following in the answers table
407
        <p>I use a [computer] and a [pen].</p>
408
        becomes
409
        <p>I use a [computer] and a [pen].</p>::100,50:100,50@1
410
            ++++++++-------**
411
            --- -- --- -- -
412
            A B  (C) (D)(E)
413
        +++++++ : required, weighting of each words
414
        ------- : optional, input width to display, 200 if not present
415
        ** : equal @1 if "Allow answers order switches" has been checked, @ otherwise
416
        A : weighting for the word [computer]
417
        B : weighting for the word [pen]
418
        C : input width for the word [computer]
419
        D : input width for the word [pen]
420
        E : equal @1 if "Allow answers order switches" has been checked, @ otherwise
421
        */
422
        if ($nb > 0) {
423
            $answer .= '::';
424
            // weighting
425
            for ($i=0; $i < $nb; ++$i) {
426
                // enter the weighting of word $i
427
                $answer .= $form->getSubmitValue('weighting['.$i.']');
428
                // not the last word, add ","
429
                if ($i != $nb - 1) {
430
                    $answer .= ",";
431
                }
432
                // calculate the global weighting for the question
433
                $this -> weighting += $form->getSubmitValue('weighting['.$i.']');
434
            }
435
436
            // input width
437
            $answer .= ":";
438
            for ($i=0; $i < $nb; ++$i) {
439
                // enter the width of input for word $i
440
                $answer .= $form->getSubmitValue('sizeofinput['.$i.']');
441
                // not the last word, add ","
442
                if ($i != $nb - 1) {
443
                    $answer .= ",";
444
                }
445
            }
446
        }
447
448
        // write the blank separator code number
449
        // see function getAllowedSeparator
450
        /*
451
            0 [...]
452
            1 {...}
453
            2 (...)
454
            3 *...*
455
            4 #...#
456
            5 %...%
457
            6 $...$
458
         */
459
        $answer .= ":".$form->getSubmitValue('select_separator');
460
461
        // Allow answers order switches
462
        $is_multiple = $form -> getSubmitValue('multiple_answer');
463
        $answer.= '@'.$is_multiple;
464
465
        $this->save();
466
        $objAnswer = new Answer($this->id);
467
        $objAnswer->createAnswer($answer, 0, '', 0, 1);
468
        $objAnswer->save();
469
    }
470
471
    /**
472
     * @param null $feedback_type
473
     * @param null $counter
474
     * @param null $score
475
     * @return string
476
     */
477 View Code Duplication
    public function return_header($feedback_type = null, $counter = null, $score = null)
478
    {
479
        $header = parent::return_header($feedback_type, $counter, $score);
480
        $header .= '<table class="'.$this->question_table_class .'">
481
            <tr>
482
                <th>'.get_lang("Answer").'</th>
483
            </tr>';
484
485
        return $header;
486
    }
487
488
    /**
489
     * @param string $separatorStartRegexp
490
     * @param string $separatorEndRegexp
491
     * @param string $correctItemRegexp
492
     * @param integer $questionId
493
     * @param $correctItem
494
     * @param $attributes
495
     * @param string $answer
496
     * @param $listAnswersInfo
497
     * @param boolean $displayForStudent
498
     * @param integer $inBlankNumber
499
     * @return string
500
     */
501
    public static function getFillTheBlankHtml(
502
        $separatorStartRegexp,
503
        $separatorEndRegexp,
504
        $correctItemRegexp,
505
        $questionId,
506
        $correctItem,
507
        $attributes,
508
        $answer,
509
        $listAnswersInfo,
510
        $displayForStudent,
511
        $inBlankNumber
512
    ) {
513
        $result = "";
514
        $inTabTeacherSolution = $listAnswersInfo['tabwords'];
515
        $inTeacherSolution = $inTabTeacherSolution[$inBlankNumber];
516
        switch (self::getFillTheBlankAnswerType($inTeacherSolution)) {
517
            case self::FILL_THE_BLANK_MENU:
518
                $selected = '';
519
                // the blank menu
520
                $optionMenu = '';
521
                // display a menu from answer separated with |
522
                // if display for student, shuffle the correct answer menu
523
                $listMenu = self::getFillTheBlankMenuAnswers($inTeacherSolution, $displayForStudent);
524
                $result .= '<select name="choice['.$questionId.'][]">';
525
                for ($k=0; $k < count($listMenu); $k++) {
526
                    $selected = "";
527
                    if ($correctItem == $listMenu[$k]) {
528
                        $selected = " selected=selected ";
529
                    }
530
                    // if in teacher view, display the first item by default, which is the right answer
531
                    if ($k==0 && !$displayForStudent) {
532
                        $selected = " selected=selected ";
533
                    }
534
                    $optionMenu .= '<option '.$selected.' value="'.$listMenu[$k].'">'.$listMenu[$k].'</option>';
535
                }
536
                if ($selected == "") {
537
                    // no good answer have been found...
538
                    $selected = " selected=selected ";
539
                }
540
                $result .= "<option $selected value=''>--</option>";
541
                $result .= $optionMenu;
542
                $result .= '</select>';
543
                break;
544
            case self::FILL_THE_BLANK_SEVERAL_ANSWER:
545
                //no break
546
            case self::FILL_THE_BLANK_STANDARD:
547
            default:
548
                $result = Display::input('text', "choice[$questionId][]", $correctItem, $attributes);
549
                break;
550
        }
551
552
        return $result;
553
    }
554
555
    /**
556
     * Return an array with the different choices available
557
     * when the answers between bracket show as a menu
558
     * @param string $correctAnswer
559
     * @param bool $displayForStudent true if we want to shuffle the choices of the menu for students
560
     *
561
     * @return array
562
     */
563
    public static function getFillTheBlankMenuAnswers($correctAnswer, $displayForStudent)
564
    {
565
        // if $inDisplayForStudent, then shuffle the result array
566
        $listChoises = api_preg_split("/\|/", $correctAnswer);
567
        if ($displayForStudent) {
568
            shuffle($listChoises);
569
        }
570
571
        return $listChoises;
572
    }
573
574
    /**
575
     * Return the array index of the student answer
576
     * @param string $correctAnswer the menu Choice1|Choice2|Choice3
577
     * @param string $studentAnswer the student answer must be Choice1 or Choice2 or Choice3
578
     *
579
     * @return int  in the example 0 1 or 2 depending of the choice of the student
580
     */
581
    public static function getFillTheBlankMenuAnswerNum($correctAnswer, $studentAnswer)
582
    {
583
        $listChoices = self::getFillTheBlankMenuAnswers($correctAnswer, false);
584
        foreach ($listChoices as $num => $value) {
585
            if ($value == $studentAnswer) {
586
                return $num;
587
            }
588
        }
589
590
        // should not happened, because student choose the answer in a menu of possible answers
591
        return -1;
592
    }
593
594
595
    /**
596
     * Return the possible answer if the answer between brackets is a multiple choice menu
597
     * @param string $correctAnswer
598
     *
599
     * @return array
600
     */
601
    public static function getFillTheBlankSeveralAnswers($correctAnswer)
602
    {
603
        // is answer||Answer||response||Response , mean answer or Answer ...
604
        $listSeveral = api_preg_split("/\|\|/", $correctAnswer);
605
606
        return $listSeveral;
607
    }
608
609
    /**
610
     * Return true if student answer is right according to the correctAnswer
611
     * it is not as simple as equality, because of the type of Fill The Blank question
612
     * eg : studentAnswer = 'Un' and correctAnswer = 'Un||1||un'
613
     * @param string $studentAnswer [studentanswer] of the info array of the answer field
614
     * @param string $correctAnswer [tabwords] of the info array of the answer field
615
     *
616
     * @return bool
617
     */
618
    public static function isGoodStudentAnswer($studentAnswer, $correctAnswer)
619
    {
620
        switch (self::getFillTheBlankAnswerType($correctAnswer)) {
621
            case self::FILL_THE_BLANK_MENU:
622
                $listMenu = self::getFillTheBlankMenuAnswers($correctAnswer, false);
623
                $result = $listMenu[0] == $studentAnswer;
624
                break;
625
            case self::FILL_THE_BLANK_SEVERAL_ANSWER:
626
                // the answer must be one of the choice made
627
                $listSeveral = self::getFillTheBlankSeveralAnswers($correctAnswer);
628
                $result = in_array($studentAnswer, $listSeveral);
629
                break;
630
            case self::FILL_THE_BLANK_STANDARD:
631
            default:
632
                $result = $studentAnswer == $correctAnswer;
633
                break;
634
        }
635
636
        return $result;
637
    }
638
639
    /**
640
     * @param string $correctAnswer
641
     *
642
     * @return int
643
     */
644
    public static function getFillTheBlankAnswerType($correctAnswer)
645
    {
646
        if (api_strpos($correctAnswer, "|") && !api_strpos($correctAnswer, "||")) {
647
            return self::FILL_THE_BLANK_MENU;
648
        } elseif (api_strpos($correctAnswer, "||")) {
649
            return self::FILL_THE_BLANK_SEVERAL_ANSWER;
650
        } else {
651
            return self::FILL_THE_BLANK_STANDARD;
652
        }
653
    }
654
655
    /**
656
     * Return information about the answer
657
     * @param string $userAnswer the text of the answer of the question
658
     * @param bool   $isStudentAnswer true if it's a student answer false the empty question model
659
     *
660
     * @return array of information about the answer
661
     */
662
    public static function getAnswerInfo($userAnswer = "", $isStudentAnswer = false)
663
    {
664
        $listAnswerResults = array();
665
        $listAnswerResults['text'] = '';
666
        $listAnswerResults['wordsCount'] = 0;
667
        $listAnswerResults['tabwordsbracket'] = array();
668
        $listAnswerResults['tabwords'] = array();
669
        $listAnswerResults['tabweighting'] = array();
670
        $listAnswerResults['tabinputsize'] = array();
671
        $listAnswerResults['switchable'] = '';
672
        $listAnswerResults['studentanswer'] = array();
673
        $listAnswerResults['studentscore'] = array();
674
        $listAnswerResults['blankseparatornumber'] = 0;
675
        $listDoubleColon = array();
676
677
        api_preg_match("/(.*)::(.*)$/s", $userAnswer, $listResult);
678
679
        if (count($listResult) < 2) {
680
            $listDoubleColon[] = '';
681
            $listDoubleColon[] = '';
682
        } else {
683
            $listDoubleColon[] = $listResult[1];
684
            $listDoubleColon[] = $listResult[2];
685
        }
686
687
        $listAnswerResults['systemstring'] = $listDoubleColon[1];
688
689
        // make sure we only take the last bit to find special marks
690
        $listArobaseSplit = explode('@', $listDoubleColon[1]);
691
692
        if (count($listArobaseSplit) < 2) {
693
            $listArobaseSplit[1] = '';
694
        }
695
696
        // take the complete string except after the last '::'
697
        $listDetails = explode(":", $listArobaseSplit[0]);
698
699
        // < number of item after the ::[score]:[size]:[separator_id]@ , here there are 3
700
        if (count($listDetails) < 3) {
701
            $listWeightings = explode(',', $listDetails[0]);
702
            $listSizeOfInput = array();
703
            for ($i=0; $i < count($listWeightings); $i++) {
704
                $listSizeOfInput[] = 200;
705
            }
706
            $blankSeparatorNumber = 0;    // 0 is [...]
707
        } else {
708
            $listWeightings = explode(',', $listDetails[0]);
709
            $listSizeOfInput = explode(',', $listDetails[1]);
710
            $blankSeparatorNumber = $listDetails[2];
711
        }
712
713
        $listAnswerResults['text'] = $listDoubleColon[0];
714
        $listAnswerResults['tabweighting'] = $listWeightings;
715
        $listAnswerResults['tabinputsize'] = $listSizeOfInput;
716
        $listAnswerResults['switchable'] = $listArobaseSplit[1];
717
        $listAnswerResults['blankseparatorstart'] = self::getStartSeparator($blankSeparatorNumber);
718
        $listAnswerResults['blankseparatorend'] = self::getEndSeparator($blankSeparatorNumber);
719
        $listAnswerResults['blankseparatornumber'] = $blankSeparatorNumber;
720
721
        $blankCharStart = self::getStartSeparator($blankSeparatorNumber);
722
        $blankCharEnd = self::getEndSeparator($blankSeparatorNumber);
723
        $blankCharStartForRegexp = self::escapeForRegexp($blankCharStart);
724
        $blankCharEndForRegexp = self::escapeForRegexp($blankCharEnd);
725
726
        // get all blanks words
727
        $listAnswerResults['wordsCount'] = api_preg_match_all(
728
            '/'.$blankCharStartForRegexp.'[^'.$blankCharEndForRegexp.']*'.$blankCharEndForRegexp.'/',
729
            $listDoubleColon[0],
730
            $listWords
731
        );
732
733
        if ($listAnswerResults['wordsCount'] > 0) {
734
            $listAnswerResults['tabwordsbracket'] = $listWords[0];
735
            // remove [ and ] in string
736
            array_walk(
737
                $listWords[0],
738
                function (&$value, $key, $tabBlankChar) {
739
                    $trimChars = "";
740
                    for ($i=0; $i < count($tabBlankChar); $i++) {
741
                        $trimChars .= $tabBlankChar[$i];
742
                    }
743
                    $value = trim($value, $trimChars);
744
                },
745
                array($blankCharStart, $blankCharEnd)
746
            );
747
            $listAnswerResults['tabwords'] = $listWords[0];
748
        }
749
750
        // get all common words
751
        $commonWords = api_preg_replace(
752
            '/'.$blankCharStartForRegexp.'[^'.$blankCharEndForRegexp.']*'.$blankCharEndForRegexp.'/',
753
            "::",
754
            $listDoubleColon[0]
755
        );
756
757
        // if student answer, the second [] is the student answer,
758
        // the third is if student scored or not
759
        $listBrackets = array();
760
        $listWords =  array();
761
762
        if ($isStudentAnswer) {
763
            for ($i=0; $i < count($listAnswerResults['tabwords']); $i++) {
764
                $listBrackets[] = $listAnswerResults['tabwordsbracket'][$i];
765
                $listWords[] = $listAnswerResults['tabwords'][$i];
766
                if ($i+1 < count($listAnswerResults['tabwords'])) {
767
                    // should always be
768
                    $i++;
769
                }
770
                $listAnswerResults['studentanswer'][] = $listAnswerResults['tabwords'][$i];
771
                if ($i+1 < count($listAnswerResults['tabwords'])) {
772
                    // should always be
773
                    $i++;
774
                }
775
                $listAnswerResults['studentscore'][] = $listAnswerResults['tabwords'][$i];
776
            }
777
            $listAnswerResults['tabwords'] = $listWords;
778
            $listAnswerResults['tabwordsbracket'] = $listBrackets;
779
780
            // if we are in student view, we've got 3 times :::::: for common words
781
            $commonWords = api_preg_replace("/::::::/", "::", $commonWords);
782
        }
783
784
        $listAnswerResults['commonwords'] = explode("::", $commonWords);
785
786
        return $listAnswerResults;
787
    }
788
789
    /**
790
    * Return an array of student state answers for fill the blank questions
791
    * for each students that answered the question
792
    * -2  : didn't answer
793
    * -1  : student answer is wrong
794
    *  0  : student answer is correct
795
    * >0  : for fill the blank question with choice menu, is the index of the student answer (right answer indice is 0)
796
    *
797
    * @param integer $testId
798
    * @param integer $questionId
799
    * @param $studentsIdList
800
    * @param string $startDate
801
    * @param string $endDate
802
    * @param bool $useLastAnswerredAttempt
803
    * @return array
804
    * (
805
    *     [student_id] => Array
806
    *         (
807
    *             [first fill the blank for question] => -1
808
    *             [second fill the blank for question] => 2
809
    *             [third fill the blank for question] => -1
810
    *         )
811
    * )
812
    */
813
    public static function getFillTheBlankTabResult(
814
        $testId,
815
        $questionId,
816
        $studentsIdList,
817
        $startDate,
818
        $endDate,
819
        $useLastAnswerredAttempt = true
820
    ) {
821
        $tblTrackEAttempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
822
        $tblTrackEExercise = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
823
        $courseId = api_get_course_int_id();
824
        // request to have all the answers of student for this question
825
        // student may have doing it several time
826
        // student may have not answered the bracket id, in this case, is result of the answer is empty
827
        // we got the less recent attempt first
828
        $sql = 'SELECT * FROM '.$tblTrackEAttempt.' tea
829
               LEFT JOIN '.$tblTrackEExercise.' tee
830
               ON tee.exe_id = tea.exe_id
831
               AND tea.c_id = '.$courseId.'
832
               AND exe_exo_id = '.$testId.'    
833
               WHERE 
834
                tee.c_id = '.$courseId.' AND 
835
                question_id = '.$questionId.' AND 
836
                tea.user_id IN ('.implode(',', $studentsIdList).')  AND 
837
                tea.tms >= "'.$startDate.'" AND 
838
                tea.tms <= "'.$endDate.'"
839
               ORDER BY user_id, tea.exe_id;
840
        ';
841
842
        $res = Database::query($sql);
843
        $tabUserResult = array();
844
        $bracketNumber = 0;
845
        // foreach attempts for all students starting with his older attempt
846
        while ($data = Database::fetch_array($res)) {
847
            $tabAnswer = FillBlanks::getAnswerInfo($data['answer'], true);
848
849
            // for each bracket to find in this question
850
            foreach ($tabAnswer['studentanswer'] as $bracketNumber => $studentAnswer) {
851
                if ($tabAnswer['studentanswer'][$bracketNumber] != '') {
852
                    // student has answered this bracket, cool
853
                    switch (FillBlanks::getFillTheBlankAnswerType($tabAnswer['tabwords'][$bracketNumber])) {
854
                        case self::FILL_THE_BLANK_MENU:
855
                            // get the indice of the choosen answer in the menu
856
                            // we know that the right answer is the first entry of the menu, ie 0
857
                            // (remember, menu entries are shuffled when taking the test)
858
                            $tabUserResult[$data['user_id']][$bracketNumber] = FillBlanks::getFillTheBlankMenuAnswerNum(
859
                                $tabAnswer['tabwords'][$bracketNumber],
860
                                $tabAnswer['studentanswer'][$bracketNumber]
861
                            );
862
                            break;
863
                        default:
864
                            if (FillBlanks::isGoodStudentAnswer(
865
                                $tabAnswer['studentanswer'][$bracketNumber],
866
                                $tabAnswer['tabwords'][$bracketNumber]
867
                            )
868
                            ) {
869
                                $tabUserResult[$data['user_id']][$bracketNumber] = 0;   //  right answer
870
                            } else {
871
                                $tabUserResult[$data['user_id']][$bracketNumber] = -1;  // wrong answer
872
                            }
873
                    }
874
                } else {
875
                    // student didn't answer this bracket
876
                    if ($useLastAnswerredAttempt) {
877
                        // if we take into account the last answered attempt
878
                        if (!isset($tabUserResult[$data['user_id']][$bracketNumber])) {
879
                            $tabUserResult[$data['user_id']][$bracketNumber] = -2;      // not answered
880
                        }
881
                    } else {
882
                        // we take the last attempt, even if the student answer the question before
883
                        $tabUserResult[$data['user_id']][$bracketNumber] = -2;      // not answered
884
                    }
885
                }
886
            }
887
        }
888
889
        return $tabUserResult;
890
    }
891
892
    /**
893
     * Return the number of student that give at leat an answer in the fill the blank test
894
     * @param $resultList
895
     * @return int
896
     */
897
    public static function getNbResultFillBlankAll($resultList)
898
    {
899
        $outRes = 0;
900
        // for each student in group
901
        foreach ($resultList as $userId => $tabValue) {
902
            $found = false;
903
            // for each bracket, if student has at least one answer ( choice > -2) then he pass the question
904
            foreach ($tabValue as $i => $choice) {
905
                if ($choice > -2 && !$found) {
906
                    $outRes++;
907
                    $found = true;
908
                }
909
            }
910
        }
911
912
        return $outRes;
913
    }
914
915
    /**
916
     * Replace the occurrence of blank word with [correct answer][student answer][answer is correct]
917
     * @param array $listWithStudentAnswer
918
     *
919
     * @return string
920
     */
921
    public static function getAnswerInStudentAttempt($listWithStudentAnswer)
922
    {
923
        $separatorStart = $listWithStudentAnswer['blankseparatorstart'];
924
        $separatorEnd = $listWithStudentAnswer['blankseparatorend'];
925
        // lets rebuild the sentence with [correct answer][student answer][answer is correct]
926
        $result = "";
927
        for ($i=0; $i < count($listWithStudentAnswer['commonwords']) - 1; $i++) {
928
            $result .= $listWithStudentAnswer['commonwords'][$i];
929
            $result .= $listWithStudentAnswer['tabwordsbracket'][$i];
930
            $result .= $separatorStart.$listWithStudentAnswer['studentanswer'][$i].$separatorEnd;
931
            $result .= $separatorStart.$listWithStudentAnswer['studentscore'][$i].$separatorEnd;
932
        }
933
        $result .= $listWithStudentAnswer['commonwords'][$i];
934
        $result .= "::";
935
        // add the system string
936
        $result .= $listWithStudentAnswer['systemstring'];
937
938
        return $result;
939
    }
940
941
    /**
942
     * This function is the same than the js one above getBlankSeparatorRegexp
943
     * @param string $inChar
944
     *
945
     * @return string
946
     */
947
    public static function escapeForRegexp($inChar)
948
    {
949
        $listChars = [
950
            ".",
951
            "+",
952
            "*",
953
            "?",
954
            "[",
955
            "^",
956
            "]",
957
            "$",
958
            "(",
959
            ")",
960
            "{",
961
            "}",
962
            "=",
963
            "!",
964
            ">",
965
            "|",
966
            ":",
967
            "-",
968
            ")",
969
        ];
970
971
        if (in_array($inChar, $listChars)) {
972
            return "\\".$inChar;
973
        } else {
974
            return $inChar;
975
        }
976
    }
977
978
    /**
979
     * return $text protected for use in regexp
980
     * @param string $text
981
     *
982
     * @return string
983
     */
984
    public static function getRegexpProtected($text)
985
    {
986
        $listRegexpCharacters = [
987
            "/",
988
            ".",
989
            "+",
990
            "*",
991
            "?",
992
            "[",
993
            "^",
994
            "]",
995
            "$",
996
            "(",
997
            ")",
998
            "{",
999
            "}",
1000
            "=",
1001
            "!",
1002
            ">",
1003
            "|",
1004
            ":",
1005
            "-",
1006
            ")",
1007
        ];
1008
        $result = $text;
1009
        for ($i=0; $i < count($listRegexpCharacters); $i++) {
1010
            $result = str_replace($listRegexpCharacters[$i], "\\".$listRegexpCharacters[$i], $result);
1011
        }
1012
1013
        return $result;
1014
    }
1015
1016
1017
    /**
1018
     * This function must be the same than the js one getSeparatorFromNumber above
1019
     * @return array
1020
     */
1021
    public static function getAllowedSeparator()
1022
    {
1023
        $fillBlanksAllowedSeparator = array(
1024
            array('[', ']'),
1025
            array('{', '}'),
1026
            array('(', ')'),
1027
            array('*', '*'),
1028
            array('#', '#'),
1029
            array('%', '%'),
1030
            array('$', '$'),
1031
        );
1032
1033
        return $fillBlanksAllowedSeparator;
1034
    }
1035
1036
    /**
1037
     * return the start separator for answer
1038
     * @param string $number
1039
     *
1040
     * @return string
1041
     */
1042
    public static function getStartSeparator($number)
1043
    {
1044
        $listSeparators = self::getAllowedSeparator();
1045
1046
        return $listSeparators[$number][0];
1047
    }
1048
1049
    /**
1050
     * return the end separator for answer
1051
     * @param string $number
1052
     *
1053
     * @return string
1054
     */
1055
    public static function getEndSeparator($number)
1056
    {
1057
        $listSeparators = self::getAllowedSeparator();
1058
1059
        return $listSeparators[$number][1];
1060
    }
1061
1062
    /**
1063
     * Return as a description text, array of allowed separators for question
1064
     * eg: array("[...]", "(...)")
1065
     * @return array
1066
     */
1067
    public static function getAllowedSeparatorForSelect()
1068
    {
1069
        $listResults = array();
1070
        $fillBlanksAllowedSeparator = self::getAllowedSeparator();
1071
        for ($i=0; $i < count($fillBlanksAllowedSeparator); $i++) {
1072
            $listResults[] = $fillBlanksAllowedSeparator[$i][0]."...".$fillBlanksAllowedSeparator[$i][1];
1073
        }
1074
1075
        return $listResults;
1076
    }
1077
1078
    /**
1079
     * return the code number of the separator for the question
1080
     * @param string $startSeparator
1081
     * @param string $endSeparator
1082
     *
1083
     * @return int
1084
     */
1085
    public function getDefaultSeparatorNumber($startSeparator, $endSeparator)
1086
    {
1087
        $listSeparators = self::getAllowedSeparator();
1088
        $result = 0;
1089
        for ($i=0; $i < count($listSeparators); $i++) {
1090
            if ($listSeparators[$i][0] == $startSeparator &&
1091
                $listSeparators[$i][1] == $endSeparator
1092
            ) {
1093
                $result = $i;
1094
            }
1095
        }
1096
1097
        return $result;
1098
    }
1099
1100
    /**
1101
     * return the HTML display of the answer
1102
     * @param string $answer
1103
     * @param bool   $resultsDisabled
1104
     * @param bool $showTotalScoreAndUserChoices
1105
     *
1106
     * @return string
1107
     */
1108
    public static function getHtmlDisplayForAnswer(
1109
        $answer,
1110
        $resultsDisabled = false,
1111
        $showTotalScoreAndUserChoices = false
1112
    ) {
1113
        $result = '';
1114
        $listStudentAnswerInfo = self::getAnswerInfo($answer, true);
1115
1116 View Code Duplication
        if ($resultsDisabled == RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT) {
1117
            if ($showTotalScoreAndUserChoices) {
1118
                $resultsDisabled = false;
1119
            } else {
1120
                $resultsDisabled = true;
1121
            }
1122
        }
1123
1124
        // rebuild the answer with good HTML style
1125
        // this is the student answer, right or wrong
1126
        for ($i=0; $i < count($listStudentAnswerInfo['studentanswer']); $i++) {
1127
            if ($listStudentAnswerInfo['studentscore'][$i] == 1) {
1128
                $listStudentAnswerInfo['studentanswer'][$i] = self::getHtmlRightAnswer(
1129
                    $listStudentAnswerInfo['studentanswer'][$i],
1130
                    $listStudentAnswerInfo['tabwords'][$i],
1131
                    $resultsDisabled
1132
                );
1133
            } else {
1134
                $listStudentAnswerInfo['studentanswer'][$i] = self::getHtmlWrongAnswer(
1135
                    $listStudentAnswerInfo['studentanswer'][$i],
1136
                    $listStudentAnswerInfo['tabwords'][$i],
1137
                    $resultsDisabled
1138
                );
1139
            }
1140
        }
1141
1142
        // rebuild the sentence with student answer inserted
1143
        for ($i=0; $i < count($listStudentAnswerInfo['commonwords']); $i++) {
1144
            $result .= isset($listStudentAnswerInfo['commonwords'][$i]) ? $listStudentAnswerInfo['commonwords'][$i] : '';
1145
            $result .= isset($listStudentAnswerInfo['studentanswer'][$i]) ? $listStudentAnswerInfo['studentanswer'][$i] : '';
1146
        }
1147
1148
        // the last common word (should be </p>)
1149
        $result .= isset($listStudentAnswerInfo['commonwords'][$i]) ? $listStudentAnswerInfo['commonwords'][$i] : '';
1150
1151
        return $result;
1152
    }
1153
1154
    /**
1155
     * return the HTML code of answer for correct and wrong answer
1156
     * @param string $answer
1157
     * @param string $correct
1158
     * @param string $right
1159
     * @param bool   $resultsDisabled
1160
     *
1161
     * @return string
1162
     */
1163
    public static function getHtmlAnswer($answer, $correct, $right, $resultsDisabled = false)
1164
    {
1165
        $style = "color: green";
1166
        if (!$right) {
1167
            $style = "color: red; text-decoration: line-through;";
1168
        }
1169
        $type = FillBlanks::getFillTheBlankAnswerType($correct);
1170
        switch ($type) {
1171
            case self::FILL_THE_BLANK_MENU:
1172
                $correctAnswerHtml = '';
1173
                $listPossibleAnswers = FillBlanks::getFillTheBlankMenuAnswers($correct, false);
1174
                $correctAnswerHtml .= "<span style='color: green'>".$listPossibleAnswers[0]."</span>";
1175
                $correctAnswerHtml .= " <span style='font-weight:normal'>(";
1176
                for ($i=1; $i < count($listPossibleAnswers); $i++) {
1177
                    $correctAnswerHtml .= $listPossibleAnswers[$i];
1178
                    if ($i != count($listPossibleAnswers) - 1) {
1179
                        $correctAnswerHtml .= " | ";
1180
                    }
1181
                }
1182
                $correctAnswerHtml .= ")</span>";
1183
                break;
1184
            case self::FILL_THE_BLANK_SEVERAL_ANSWER:
1185
                $listCorrects = explode("||", $correct);
1186
                $firstCorrect = $correct;
1187
                if (count($listCorrects) > 0) {
1188
                    $firstCorrect = $listCorrects[0];
1189
                }
1190
                $correctAnswerHtml = "<span style='color: green'>".$firstCorrect."</span>";
1191
                break;
1192
            case self::FILL_THE_BLANK_STANDARD:
1193
            default:
1194
                $correctAnswerHtml = "<span style='color: green'>".$correct."</span>";
1195
        }
1196
1197
        if ($resultsDisabled) {
1198
            $correctAnswerHtml = "<span title='".get_lang("ExerciseWithFeedbackWithoutCorrectionComment")."'> - </span>";
1199
        }
1200
1201
        $result = "<span style='border:1px solid black; border-radius:5px; padding:2px; font-weight:bold;'>";
1202
        $result .= "<span style='$style'>".$answer."</span>";
1203
        $result .= "&nbsp;<span style='font-size:120%;'>/</span>&nbsp;";
1204
        $result .= $correctAnswerHtml;
1205
        $result .= "</span>";
1206
1207
        return $result;
1208
    }
1209
1210
    /**
1211
     * return HTML code for correct answer
1212
     * @param string $answer
1213
     * @param string $correct
1214
     * @param bool   $resultsDisabled
1215
     *
1216
     * @return string
1217
     */
1218
    public static function getHtmlRightAnswer($answer, $correct, $resultsDisabled = false)
1219
    {
1220
        return self::getHtmlAnswer($answer, $correct, true, $resultsDisabled);
1221
    }
1222
1223
    /**
1224
     * return HTML code for wrong answer
1225
     * @param string $answer
1226
     * @param string $correct
1227
     * @param bool   $resultsDisabled
1228
     *
1229
     * @return string
1230
     */
1231
    public static function getHtmlWrongAnswer($answer, $correct, $resultsDisabled = false)
1232
    {
1233
        return self::getHtmlAnswer($answer, $correct, false, $resultsDisabled);
1234
    }
1235
1236
    /**
1237
     * Check if a answer is correct by its text
1238
     * @param string $answerText
1239
     * @return bool
1240
     */
1241
    public static function isCorrect($answerText)
1242
    {
1243
        $answerInfo = FillBlanks::getAnswerInfo($answerText, true);
1244
        $correctAnswerList = $answerInfo['tabwords'];
1245
        $studentAnswer = $answerInfo['studentanswer'];
1246
1247
        $isCorrect = true;
1248
1249
        foreach ($correctAnswerList as $i => $correctAnswer) {
1250
            $isGoodStudentAnswer = FillBlanks::isGoodStudentAnswer($studentAnswer[$i], $correctAnswer);
1251
1252
            $isCorrect = $isCorrect && $isGoodStudentAnswer;
1253
        }
1254
1255
        return $isCorrect;
1256
    }
1257
}
1258