Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace mod_questionnaire\question;
18
 
19
/**
20
 * This file contains the parent class for check question types.
21
 *
22
 * @author Mike Churchward
23
 * @copyright  2016 onward Mike Churchward (mike.churchward@poetopensource.org)
24
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
25
 * @package mod_questionnaire
26
 */
27
class check extends question {
28
 
29
    /**
30
     * Return the responseclass used.
31
     * @return string
32
     */
33
    protected function responseclass() {
34
        return '\\mod_questionnaire\\responsetype\\multiple';
35
    }
36
 
37
    /**
38
     * Return the help name.
39
     * @return string
40
     */
41
    public function helpname() {
42
        return 'checkboxes';
43
    }
44
 
45
    /**
46
     * Return true if the question has choices.
47
     */
48
    public function has_choices() {
49
        return true;
50
    }
51
 
52
    /**
53
     * Override and return a form template if provided. Output of question_survey_display is iterpreted based on this.
54
     * @return string
55
     */
56
    public function question_template() {
57
        return 'mod_questionnaire/question_check';
58
    }
59
 
60
    /**
61
     * Override and return a form template if provided. Output of response_survey_display is iterpreted based on this.
62
     * @return string
63
     */
64
    public function response_template() {
65
        return 'mod_questionnaire/response_check';
66
    }
67
 
68
    /**
69
     * Override this and return true if the question type allows dependent questions.
70
     * @return boolean
71
     */
72
    public function allows_dependents() {
73
        return true;
74
    }
75
 
76
    /**
77
     * Return the context tags for the check question template.
78
     * @param \mod_questionnaire\responsetype\response\response $response
79
     * @param array $dependants Array of all questions/choices depending on this question.
80
     * @param boolean $blankquestionnaire
81
     * @return \stdClass The check question context tags.
82
     *
83
     */
84
    protected function question_survey_display($response, $dependants, $blankquestionnaire=false) {
85
        // Check boxes.
86
        $otherempty = false;
87
        if (!empty($response)) {
88
            // Verify that number of checked boxes (nbboxes) is within set limits (length = min; precision = max).
89
            if (!empty($response->answers[$this->id])) {
90
                $otherempty = false;
91
                $nbboxes = count($response->answers[$this->id]);
92
                foreach ($response->answers[$this->id] as $answer) {
93
                    $choice = $this->choices[$answer->choiceid];
94
                    if ($choice->is_other_choice()) {
95
                        $otherempty = empty($answer->value);
96
                    }
97
                }
98
                $nbchoices = count($this->choices);
99
                $min = $this->length;
100
                $max = $this->precise;
101
                if ($max == 0) {
102
                    $max = $nbchoices;
103
                }
104
                if ($min > $max) {
105
                    $min = $max; // Sanity check.
106
                }
107
                $min = min($nbchoices, $min);
108
                if ($nbboxes < $min || $nbboxes > $max) {
109
                    $msg = get_string('boxesnbreq', 'questionnaire');
110
                    if ($min == $max) {
111
                        $msg .= get_string('boxesnbexact', 'questionnaire', $min);
112
                    } else {
113
                        if ($min && ($nbboxes < $min)) {
114
                            $msg .= get_string('boxesnbmin', 'questionnaire', $min);
115
                            if ($nbboxes > $max) {
116
                                $msg .= ' & ' .get_string('boxesnbmax', 'questionnaire', $max);
117
                            }
118
                        } else {
119
                            if ($nbboxes > $max ) {
120
                                $msg .= get_string('boxesnbmax', 'questionnaire', $max);
121
                            }
122
                        }
123
                    }
124
                    $this->add_notification($msg);
125
                }
126
            }
127
        }
128
 
129
        $choicetags = new \stdClass();
130
        $choicetags->qelements = [];
131
        foreach ($this->choices as $id => $choice) {
132
            $checkbox = new \stdClass();
133
            $contents = questionnaire_choice_values($choice->content);
134
            $checked = false;
135
            if (!empty($response->answers[$this->id]) ) {
136
                $checked = isset($response->answers[$this->id][$id]);
137
            }
138
            $checkbox->name = 'q'.$this->id.'['.$id.']';
139
            $checkbox->value = $id;
140
            $checkbox->id = 'checkbox_'.$id;
141
            $checkbox->label = format_text($contents->text, FORMAT_HTML, ['noclean' => true]).$contents->image;
142
            if ($checked) {
143
                $checkbox->checked = $checked;
144
            }
145
            if ($choice->is_other_choice()) {
146
                $checkbox->oname = 'q'.$this->id.'['.$choice->other_choice_name().']';
147
                $checkbox->ovalue = (isset($response->answers[$this->id][$id]) && !empty($response->answers[$this->id][$id]) ?
148
                    format_string(stripslashes($response->answers[$this->id][$id]->value)) : '');
149
                $checkbox->label = format_text($choice->other_choice_display().'', FORMAT_HTML, ['noclean' => true]);
150
            }
151
            $choicetags->qelements[] = (object)['choice' => $checkbox];
152
        }
153
        if ($otherempty) {
154
            $this->add_notification(get_string('otherempty', 'questionnaire'));
155
        }
156
        return $choicetags;
157
    }
158
 
159
    /**
160
     * Return the context tags for the check response template.
161
     * @param \mod_questionnaire\responsetype\response\response $response
162
     * @return \stdClass The check question response context tags.
163
     */
164
    protected function response_survey_display($response) {
165
        static $uniquetag = 0;  // To make sure all radios have unique names.
166
 
167
        $resptags = new \stdClass();
168
        $resptags->choices = [];
169
 
170
        if (!isset($response->answers[$this->id])) {
171
            $response->answers[$this->id][] = new \mod_questionnaire\responsetype\answer\answer();
172
        }
173
 
174
        foreach ($this->choices as $id => $choice) {
175
            $chobj = new \stdClass();
176
            if (!$choice->is_other_choice()) {
177
                $contents = questionnaire_choice_values($choice->content);
178
                $choice->content = $contents->text.$contents->image;
179
                if (isset($response->answers[$this->id][$id])) {
180
                    $chobj->selected = 1;
181
                }
182
                $chobj->name = $id.$uniquetag++;
183
                $chobj->content = (($choice->content === '') ? $id : format_text($choice->content, FORMAT_HTML,
184
                    ['noclean' => true]));
185
            } else {
186
                $othertext = $choice->other_choice_display();
187
                if (isset($response->answers[$this->id][$id])) {
188
                    $oresp = $response->answers[$this->id][$id]->value;
189
                    $chobj->selected = 1;
190
                    $chobj->othercontent = (!empty($oresp) ? htmlspecialchars($oresp) : '&nbsp;');
191
                }
192
                $chobj->name = $id.$uniquetag++;
193
                $chobj->content = (($othertext === '') ? $id : $othertext);
194
            }
195
            $resptags->choices[] = $chobj;
196
        }
197
        return $resptags;
198
    }
199
 
200
    /**
201
     * Check question's form data for complete response.
202
     *
203
     * @param object $responsedata The data entered into the response.
204
     * @return boolean
205
     */
206
    public function response_complete($responsedata) {
207
        if (isset($responsedata->{'q'.$this->id}) && $this->required() &&
208
            is_array($responsedata->{'q'.$this->id})) {
209
            foreach ($responsedata->{'q' . $this->id} as $key => $choice) {
210
                // If only an 'other' choice is selected and empty, question is not completed.
211
                if ((strpos($key, 'o') === 0) && empty($choice)) {
212
                    return false;
213
                } else {
214
                    return true;
215
                }
216
            }
217
        }
218
        return parent::response_complete($responsedata);
219
    }
220
 
221
    /**
222
     * Check question's form data for valid response. Override this is type has specific format requirements.
223
     *
224
     * @param \stdClass $responsedata The data entered into the response.
225
     * @return boolean
226
     */
227
    public function response_valid($responsedata) {
228
        $nbrespchoices = 0;
229
        $valid = true;
230
        if (is_a($responsedata, 'mod_questionnaire\responsetype\response\response')) {
231
            // If $responsedata is a response object, look through the answers.
232
            if (isset($responsedata->answers[$this->id]) && !empty($responsedata->answers[$this->id])) {
233
                foreach ($responsedata->answers[$this->id] as $answer) {
234
                    if (isset($this->choices[$answer->choiceid]) && $this->choices[$answer->choiceid]->is_other_choice()) {
235
                        $valid = !empty($answer->value);
236
                    } else {
237
                        $nbrespchoices++;
238
                    }
239
                }
240
            }
241
        } else if (isset($responsedata->{'q'.$this->id})) {
242
            foreach ($responsedata->{'q'.$this->id} as $key => $answer) {
243
                if (strpos($key, 'o') === 0) {
244
                    // ..."other" choice is checked but text box is empty.
245
                    $okey = substr($key, 1);
246
                    if (isset($responsedata->{'q'.$this->id}[$okey]) && empty(trim($answer))) {
247
                        $valid = false;
248
                        break;
249
                    }
250
                } else if (is_numeric($key)) {
251
                    $nbrespchoices++;
252
                }
253
            }
254
        } else {
255
            return parent::response_valid($responsedata);
256
        }
257
 
258
        $nbquestchoices = count($this->choices);
259
        $min = $this->length;
260
        $max = $this->precise;
261
        if ($max == 0) {
262
            $max = $nbquestchoices;
263
        }
264
        if ($min > $max) {
265
            $min = $max;     // Sanity check.
266
        }
267
        $min = min($nbquestchoices, $min);
268
        if ($nbrespchoices && (($nbrespchoices < $min) || ($nbrespchoices > $max))) {
269
            // Number of ticked boxes is not within min and max set limits.
270
            $valid = false;
271
        }
272
 
273
        return $valid;
274
    }
275
 
276
    /**
277
     * Return the length form element.
278
     * @param \MoodleQuickForm $mform
279
     * @param string $helptext
280
     */
281
    protected function form_length(\MoodleQuickForm $mform, $helptext = '') {
282
        return parent::form_length($mform, 'minforcedresponses');
283
    }
284
 
285
    /**
286
     * Return the precision form element.
287
     * @param \MoodleQuickForm $mform
288
     * @param string $helptext
289
     */
290
    protected function form_precise(\MoodleQuickForm $mform, $helptext = '') {
291
        return parent::form_precise($mform, 'maxforcedresponses');
292
    }
293
 
294
    /**
295
     * True if question provides mobile support.
296
     *
297
     * @return bool
298
     */
299
    public function supports_mobile() {
300
        return true;
301
    }
302
 
303
    /**
304
     * Preprocess choice data.
305
     * @param \stdClass $formdata
306
     * @return bool
307
     */
308
    protected function form_preprocess_choicedata($formdata) {
309
        if (empty($formdata->allchoices)) {
310
            throw new \moodle_exception('enterpossibleanswers', 'mod_questionnaire');
311
        } else {
312
            // Sanity checks for min and max checked boxes.
313
            $allchoices = $formdata->allchoices;
314
            $allchoices = explode("\n", $allchoices);
315
            $nbvalues = count($allchoices);
316
 
317
            if ($formdata->length > $nbvalues) {
318
                $formdata->length = $nbvalues;
319
            }
320
            if ($formdata->precise > $nbvalues) {
321
                $formdata->precise = $nbvalues;
322
            }
323
            if ($formdata->precise != 0) {
324
                $formdata->precise = max($formdata->length, $formdata->precise);
325
            }
326
        }
327
        return true;
328
    }
329
 
330
    /**
331
     * Return the mobile question display.
332
     * @param int $qnum
333
     * @param bool $autonum
334
     * @return \stdClass
335
     */
336
    public function mobile_question_display($qnum, $autonum = false) {
337
        $mobiledata = parent::mobile_question_display($qnum, $autonum);
338
        $mobiledata->ischeckbox = true;
339
        return $mobiledata;
340
    }
341
 
342
    /**
343
     * Return the mobile question choices display.
344
     * @return array
345
     */
346
    public function mobile_question_choices_display() {
347
        $choices = parent::mobile_question_choices_display();
348
        foreach ($choices as $choicenum => $choice) {
349
            // Add a fieldkey for each choice.
350
            $choices[$choicenum]->choicefieldkey = $this->mobile_fieldkey($choice->id);
351
            if ($choice->is_other_choice()) {
352
                $choices[$choicenum]->otherchoicekey = $this->mobile_fieldkey($choice->other_choice_name());
353
                $choices[$choicenum]->content = format_text($choice->other_choice_display(), FORMAT_HTML, ['noclean' => true]);
354
            }
355
        }
356
        return $choices;
357
    }
358
 
359
    /**
360
     * Return the mobile response data.
361
     * @param \stdClass $response
362
     * @return array
363
     */
364
    public function get_mobile_response_data($response) {
365
        $resultdata = [];
366
        if (isset($response->answers[$this->id])) {
367
            foreach ($response->answers[$this->id] as $answer) {
368
                if (isset($this->choices[$answer->choiceid])) {
369
                    // Add a fieldkey for each choice.
370
                    $resultdata[$this->mobile_fieldkey($answer->choiceid)] = 1;
371
                    if ($this->choices[$answer->choiceid]->is_other_choice()) {
372
                        $resultdata[$this->mobile_fieldkey($this->choices[$answer->choiceid]->other_choice_name())] =
373
                            $answer->value;
374
                    }
375
                }
376
            }
377
        }
378
        return $resultdata;
379
    }
380
}