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

MultipleAnswerTrueFalse   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 331
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 205
c 0
b 0
f 0
dl 0
loc 331
rs 8.72
wmc 46

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B processAnswersCreation() 0 64 9
F createAnswersForm() 0 210 29
B return_header() 0 36 7

How to fix   Complexity   

Complex Class

Complex classes like MultipleAnswerTrueFalse often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MultipleAnswerTrueFalse, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use ChamiloSession as Session;
6
7
/**
8
 * Class MultipleAnswerTrueFalse
9
 * This class allows to instantiate an object of type MULTIPLE_ANSWER
10
 * (MULTIPLE CHOICE, MULTIPLE ANSWER), extending the class question.
11
 *
12
 * @author Julio Montoya
13
 */
14
class MultipleAnswerTrueFalse extends Question
15
{
16
    public $typePicture = 'mcmao.png';
17
    public $explanationLangVar = 'Multiple answer true/false/don\'t know';
18
    public $options;
19
20
    /**
21
     * Constructor.
22
     */
23
    public function __construct()
24
    {
25
        parent::__construct();
26
        $this->type = MULTIPLE_ANSWER_TRUE_FALSE;
27
        $this->isContent = $this->getIsContent();
28
        $this->options = [1 => 'True', 2 => 'False', 3 => 'DoubtScore'];
29
    }
30
31
    public function createAnswersForm($form)
32
    {
33
        $nb_answers = isset($_POST['nb_answers']) ? $_POST['nb_answers'] : 4;
34
        // The previous default value was 2. See task #1759.
35
        $nb_answers += (isset($_POST['lessAnswers']) ? -1 : (isset($_POST['moreAnswers']) ? 1 : 0));
36
37
        $course_id = api_get_course_int_id();
38
        $obj_ex = Session::read('objExercise');
39
        $renderer = &$form->defaultRenderer();
40
        $defaults = [];
41
42
        $html = '<table class="table table-striped table-hover">';
43
        $html .= '<thead>';
44
        $html .= '<tr>';
45
        $html .= '<th>'.get_lang('N°').'</th>';
46
        $html .= '<th>'.get_lang('True').'</th>';
47
        $html .= '<th>'.get_lang('False').'</th>';
48
        $html .= '<th>'.get_lang('Answer').'</th>';
49
50
        // show column comment when feedback is enable
51
        if (EXERCISE_FEEDBACK_TYPE_EXAM != $obj_ex->getFeedbackType()) {
52
            $html .= '<th>'.get_lang('Comment').'</th>';
53
        }
54
55
        $html .= '</tr>';
56
        $html .= '</thead>';
57
        $html .= '<tbody>';
58
59
        $form->addHeader(get_lang('Answers'));
60
        $form->addHtml($html);
61
62
        $answer = null;
63
64
        if (!empty($this->id)) {
65
            $answer = new Answer($this->id);
66
            $answer->read();
67
68
            if ($answer->nbrAnswers > 0 && !$form->isSubmitted()) {
69
                $nb_answers = $answer->nbrAnswers;
70
            }
71
        }
72
73
        $form->addElement('hidden', 'nb_answers');
74
        if ($nb_answers < 1) {
75
            $nb_answers = 1;
76
            echo Display::return_message(get_lang('You have to create at least one answer'));
77
        }
78
79
        // Can be more options
80
        $optionData = Question::readQuestionOption($this->id, $course_id);
81
82
        for ($i = 1; $i <= $nb_answers; $i++) {
83
            $form->addHtml('<tr>');
84
85
            $renderer->setElementTemplate(
86
                '<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>',
87
                'correct['.$i.']'
88
            );
89
            $renderer->setElementTemplate(
90
                '<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>',
91
                'counter['.$i.']'
92
            );
93
            $renderer->setElementTemplate(
94
                '<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>',
95
                'answer['.$i.']'
96
            );
97
            $renderer->setElementTemplate(
98
                '<td><!-- BEGIN error --><span class="form_error">{error}</span><!-- END error --><br/>{element}</td>',
99
                'comment['.$i.']'
100
            );
101
102
            $answer_number = $form->addElement(
103
                'text',
104
                'counter['.$i.']',
105
                null,
106
                'value="'.$i.'"'
107
            );
108
109
            $answer_number->freeze();
110
111
            if (is_object($answer)) {
112
                $defaults['answer['.$i.']'] = $answer->answer[$i];
113
                $defaults['comment['.$i.']'] = $answer->comment[$i];
114
                $correct = $answer->correct[$i];
115
                $defaults['correct['.$i.']'] = $correct;
116
117
                $j = 1;
118
                if (!empty($optionData)) {
119
                    foreach ($optionData as $id => $data) {
120
                        $rdoCorrect = $form->addElement('radio', 'correct['.$i.']', null, null, $id);
121
122
                        if (isset($_POST['correct']) && isset($_POST['correct'][$i]) && $id == $_POST['correct'][$i]) {
123
                            $rdoCorrect->setValue(Security::remove_XSS($_POST['correct'][$i]));
124
                        }
125
                        $j++;
126
                        if (3 == $j) {
127
                            break;
128
                        }
129
                    }
130
                }
131
            } else {
132
                $form->addElement('radio', 'correct['.$i.']', null, null, 1);
133
                $form->addElement('radio', 'correct['.$i.']', null, null, 2);
134
135
                $defaults['answer['.$i.']'] = '';
136
                $defaults['comment['.$i.']'] = '';
137
                $defaults['correct['.$i.']'] = '';
138
            }
139
140
            $form->addHtmlEditor(
141
                "answer[$i]",
142
                get_lang('Required field'),
143
                true,
144
                false,
145
                ['ToolbarSet' => 'TestProposedAnswer', 'Width' => '100%', 'Height' => '100']
146
            );
147
148
            if (isset($_POST['answer']) && isset($_POST['answer'][$i])) {
149
                $form->getElement("answer[$i]")->setValue(Security::remove_XSS($_POST['answer'][$i]));
150
            }
151
            // show comment when feedback is enable
152
            if (EXERCISE_FEEDBACK_TYPE_EXAM != $obj_ex->getFeedbackType()) {
153
               $txtComment = $form->addElement(
154
                    'html_editor',
155
                    'comment['.$i.']',
156
                    null,
157
                    [],
158
                    [
159
                        'ToolbarSet' => 'TestProposedAnswer',
160
                        'Width' => '100%',
161
                        'Height' => '100',
162
                    ]
163
                );
164
                if (isset($_POST['comment']) && isset($_POST['comment'][$i])) {
165
                    $txtComment->setValue(Security::remove_XSS($_POST['comment'][$i]));
166
                }
167
            }
168
169
            $form->addHtml('</tr>');
170
        }
171
172
        $form->addHtml('</tbody></table>');
173
174
        $correctInputTemplate = '<div class="form-group">';
175
        $correctInputTemplate .= '<label class="col-sm-2 control-label">';
176
        $correctInputTemplate .= '<span class="form_required">*</span>'.get_lang('Score');
177
        $correctInputTemplate .= '</label>';
178
        $correctInputTemplate .= '<div class="col-sm-8">';
179
        $correctInputTemplate .= '<table>';
180
        $correctInputTemplate .= '<tr>';
181
        $correctInputTemplate .= '<td>';
182
        $correctInputTemplate .= get_lang('Correct').'{element}';
183
        $correctInputTemplate .= '<!-- BEGIN error --><span class="form_error">{error}</span><!-- END error -->';
184
        $correctInputTemplate .= '</td>';
185
186
        $wrongInputTemplate = '<td>';
187
        $wrongInputTemplate .= get_lang('Wrong').'{element}';
188
        $wrongInputTemplate .= '<!-- BEGIN error --><span class="form_error">{error}</span><!-- END error -->';
189
        $wrongInputTemplate .= '</td>';
190
191
        $doubtScoreInputTemplate = '<td>'.get_lang('Don\'t know').'<br>{element}';
192
        $doubtScoreInputTemplate .= '<!-- BEGIN error --><span class="form_error">{error}</span><!-- END error -->';
193
        $doubtScoreInputTemplate .= '</td>';
194
        $doubtScoreInputTemplate .= '</tr>';
195
        $doubtScoreInputTemplate .= '</table>';
196
        $doubtScoreInputTemplate .= '</div>';
197
        $doubtScoreInputTemplate .= '</div>';
198
199
        $renderer->setElementTemplate($correctInputTemplate, 'option[1]');
200
        $renderer->setElementTemplate($wrongInputTemplate, 'option[2]');
201
        $renderer->setElementTemplate($doubtScoreInputTemplate, 'option[3]');
202
203
        // 3 scores
204
        $form->addElement('text', 'option[1]', get_lang('Correct'), ['class' => 'span1', 'value' => '1']);
205
        $form->addElement('text', 'option[2]', get_lang('Wrong'), ['class' => 'span1', 'value' => '-0.5']);
206
        $form->addElement('text', 'option[3]', get_lang('Don\'t know'), ['class' => 'span1', 'value' => '0']);
207
208
        $form->addRule('option[1]', get_lang('Required field'), 'required');
209
        $form->addRule('option[2]', get_lang('Required field'), 'required');
210
        $form->addRule('option[3]', get_lang('Required field'), 'required');
211
212
        $form->addElement('hidden', 'options_count', 3);
213
214
        // Extra values True, false,  Dont known
215
        if (!empty($this->extra)) {
216
            $scores = explode(':', $this->extra);
217
218
            if (!empty($scores)) {
219
                $txtOption1->setValue($scores[0]);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $txtOption1 seems to be never defined.
Loading history...
220
                $txtOption2->setValue($scores[1]);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $txtOption2 seems to be never defined.
Loading history...
221
                $txtOption3->setValue($scores[2]);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $txtOption3 seems to be never defined.
Loading history...
222
            }
223
        }
224
225
        global $text;
226
        if (true == $obj_ex->edit_exercise_in_lp ||
227
            (empty($this->exerciseList) && empty($obj_ex->id))
228
        ) {
229
            // setting the save button here and not in the question class.php
230
            $buttonGroup[] = $form->addButtonDelete(get_lang('Remove answer option'), 'lessAnswers', true);
0 ignored issues
show
Comprehensibility Best Practice introduced by
$buttonGroup was never initialized. Although not strictly required by PHP, it is generally a good practice to add $buttonGroup = array(); before regardless.
Loading history...
231
            $buttonGroup[] = $form->addButtonCreate(get_lang('Add answer option'), 'moreAnswers', true);
232
            $buttonGroup[] = $form->addButtonSave($text, 'submitQuestion', true);
233
234
            $form->addGroup($buttonGroup);
235
        }
236
237
        if (!empty($this->id) && !$form->isSubmitted()) {
238
            $form->setDefaults($defaults);
239
        }
240
        $form->setConstants(['nb_answers' => $nb_answers]);
241
    }
242
243
    public function processAnswersCreation($form, $exercise)
244
    {
245
        $questionWeighting = 0;
246
        $objAnswer = new Answer($this->id);
247
        $nb_answers = $form->getSubmitValue('nb_answers');
248
        $course_id = api_get_course_int_id();
249
250
        $correct = [];
251
        $options = Question::readQuestionOption($this->id, $course_id);
252
253
        if (!empty($options)) {
254
            foreach ($options as $optionData) {
255
                $id = $optionData['id'];
256
                unset($optionData['id']);
257
                Question::updateQuestionOption($id, $optionData, $course_id);
258
            }
259
        } else {
260
            for ($i = 1; $i <= 3; $i++) {
261
                $last_id = Question::saveQuestionOption(
262
                    $this->id,
263
                    $this->options[$i],
264
                    $course_id,
265
                    $i
266
                );
267
                $correct[$i] = $last_id;
268
            }
269
        }
270
271
        /* Getting quiz_question_options (true, false, doubt) because
272
        it's possible that there are more options in the future */
273
        $new_options = Question::readQuestionOption($this->id, $course_id);
274
        $sortedByPosition = [];
275
        foreach ($new_options as $item) {
276
            $sortedByPosition[$item['position']] = $item;
277
        }
278
279
        /* Saving quiz_question.extra values that has the correct scores of
280
        the true, false, doubt options registered in this format
281
        XX:YY:ZZZ where XX is a float score value.*/
282
        $extra_values = [];
283
        for ($i = 1; $i <= 3; $i++) {
284
            $score = trim($form->getSubmitValue('option['.$i.']'));
285
            $extra_values[] = $score;
286
        }
287
        $this->setExtra(implode(':', $extra_values));
288
289
        for ($i = 1; $i <= $nb_answers; $i++) {
290
            $answer = trim($form->getSubmitValue('answer['.$i.']'));
291
            $comment = trim($form->getSubmitValue('comment['.$i.']'));
292
            $goodAnswer = trim($form->getSubmitValue('correct['.$i.']'));
293
            if (empty($options)) {
294
                //If this is the first time that the question is created when
295
                // change the default values from the form 1 and 2 by the correct "option id" registered
296
                $goodAnswer = isset($sortedByPosition[$goodAnswer]) ? $sortedByPosition[$goodAnswer]['id'] : '';
297
            }
298
            $questionWeighting += $extra_values[0]; //By default 0 has the correct answers
299
            $objAnswer->createAnswer($answer, $goodAnswer, $comment, '', $i);
300
        }
301
302
        // saves the answers into the database
303
        $objAnswer->save();
304
        // sets the total weighting of the question
305
        $this->updateWeighting($questionWeighting);
306
        $this->save($exercise);
307
    }
308
309
    public function return_header(Exercise $exercise, $counter = null, $score = [])
310
    {
311
        $header = parent::return_header($exercise, $counter, $score);
312
        $header .= '<table class="'.$this->question_table_class.'"><tr>';
313
314
        if (!in_array($exercise->results_disabled, [
315
            RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER,
316
        ])
317
        ) {
318
            $header .= '<th>'.get_lang('Your choice').'</th>';
319
            if ($exercise->showExpectedChoiceColumn()) {
320
                $header .= '<th>'.get_lang('ExpectedYour choice').'</th>';
321
            }
322
        }
323
324
        $header .= '<th>'.get_lang('Answer').'</th>';
325
326
        if ($exercise->showExpectedChoice()) {
327
            $header .= '<th>'.get_lang('Status').'</th>';
328
        }
329
        if (EXERCISE_FEEDBACK_TYPE_EXAM != $exercise->getFeedbackType() ||
330
            in_array(
331
                $exercise->results_disabled,
332
                [
333
                    RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER,
334
                    RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING,
335
                ]
336
            )
337
        ) {
338
            if (false === $exercise->hideComment) {
339
                $header .= '<th>'.get_lang('Comment').'</th>';
340
            }
341
        }
342
        $header .= '</tr>';
343
344
        return $header;
345
    }
346
}
347