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
defined('MOODLE_INTERNAL') OR die('not allowed');
18
require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_class.php');
19
 
20
define('FEEDBACK_RADIORATED_ADJUST_SEP', '<<<<<');
21
 
22
define('FEEDBACK_MULTICHOICERATED_MAXCOUNT', 10); //count of possible items
23
define('FEEDBACK_MULTICHOICERATED_VALUE_SEP', '####');
24
define('FEEDBACK_MULTICHOICERATED_VALUE_SEP2', '/');
25
define('FEEDBACK_MULTICHOICERATED_TYPE_SEP', '>>>>>');
26
define('FEEDBACK_MULTICHOICERATED_LINE_SEP', '|');
27
define('FEEDBACK_MULTICHOICERATED_ADJUST_SEP', '<<<<<');
28
define('FEEDBACK_MULTICHOICERATED_IGNOREEMPTY', 'i');
29
define('FEEDBACK_MULTICHOICERATED_HIDENOSELECT', 'h');
30
 
31
class feedback_item_multichoicerated extends feedback_item_base {
32
    protected $type = "multichoicerated";
33
 
34
    public function build_editform($item, $feedback, $cm) {
35
        global $DB, $CFG;
36
        require_once('multichoicerated_form.php');
37
 
38
        //get the lastposition number of the feedback_items
39
        $position = $item->position;
40
        $lastposition = $DB->count_records('feedback_item', array('feedback'=>$feedback->id));
41
        if ($position == -1) {
42
            $i_formselect_last = $lastposition + 1;
43
            $i_formselect_value = $lastposition + 1;
44
            $item->position = $lastposition + 1;
45
        } else {
46
            $i_formselect_last = $lastposition;
47
            $i_formselect_value = $item->position;
48
        }
49
        //the elements for position dropdownlist
50
        $positionlist = array_slice(range(0, $i_formselect_last), 1, $i_formselect_last, true);
51
 
52
        $item->presentation = empty($item->presentation) ? '' : $item->presentation;
53
        $info = $this->get_info($item);
54
 
55
        $item->ignoreempty = $this->ignoreempty($item);
56
        $item->hidenoselect = $this->hidenoselect($item);
57
 
58
        //all items for dependitem
59
        $feedbackitems = feedback_get_depend_candidates_for_item($feedback, $item);
60
        $commonparams = array('cmid'=>$cm->id,
61
                             'id'=>isset($item->id) ? $item->id : null,
62
                             'typ'=>$item->typ,
63
                             'items'=>$feedbackitems,
64
                             'feedback'=>$feedback->id);
65
 
66
        //build the form
67
        $customdata = array('item' => $item,
68
                            'common' => $commonparams,
69
                            'positionlist' => $positionlist,
70
                            'position' => $position,
71
                            'info' => $info);
72
 
73
        $this->item_form = new feedback_multichoicerated_form('edit_item.php', $customdata);
74
    }
75
 
76
    /**
77
     * Saves item
78
     *
79
     * @return stdClass
80
     */
81
    public function save_item() {
82
        global $DB;
83
 
84
        if (!$this->get_data()) {
85
            return false;
86
        }
87
        $item = $this->item;
88
 
89
        if (isset($item->clone_item) AND $item->clone_item) {
90
            $item->id = ''; //to clone this item
91
            $item->position++;
92
        }
93
 
94
        $this->set_ignoreempty($item, $item->ignoreempty);
95
        $this->set_hidenoselect($item, $item->hidenoselect);
96
 
97
        $item->hasvalue = $this->get_hasvalue();
98
        if (!$item->id) {
99
            $item->id = $DB->insert_record('feedback_item', $item);
100
        } else {
101
            $DB->update_record('feedback_item', $item);
102
        }
103
 
104
        return $DB->get_record('feedback_item', array('id'=>$item->id));
105
    }
106
 
107
 
108
    /**
109
     * Helper function for collected data, both for analysis page and export to excel
110
     *
111
     * @param stdClass $item the db-object from feedback_item
112
     * @param int $groupid
113
     * @param int $courseid
114
     * @return array|null
115
     */
116
    protected function get_analysed($item, $groupid = false, $courseid = false) {
117
        $analysed_item = array();
118
        $analysed_item[] = $item->typ;
119
        $analysed_item[] = $item->name;
120
 
121
        //die moeglichen Antworten extrahieren
122
        $info = $this->get_info($item);
123
        $lines = null;
124
        $lines = explode (FEEDBACK_MULTICHOICERATED_LINE_SEP, $info->presentation);
125
        if (!is_array($lines)) {
126
            return null;
127
        }
128
 
129
        //die Werte holen
130
        $values = feedback_get_group_values($item, $groupid, $courseid, $this->ignoreempty($item));
131
        if (!$values) {
132
            return null;
133
        }
134
        //schleife ueber den Werten und ueber die Antwortmoeglichkeiten
135
 
136
        $analysed_answer = array();
137
        $sizeoflines = count($lines);
138
        for ($i = 1; $i <= $sizeoflines; $i++) {
139
            $item_values = explode(FEEDBACK_MULTICHOICERATED_VALUE_SEP, $lines[$i-1]);
140
            $ans = new stdClass();
141
            $ans->answertext = $item_values[1];
142
            $avg = 0.0;
143
            $anscount = 0;
144
            foreach ($values as $value) {
145
                //ist die Antwort gleich dem index der Antworten + 1?
146
                if ($value->value == $i) {
147
                    $avg += $item_values[0]; //erst alle Werte aufsummieren
148
                    $anscount++;
149
                }
150
            }
151
            $ans->answercount = $anscount;
152
            $ans->avg = doubleval($avg) / doubleval(count($values));
153
            $ans->value = $item_values[0];
154
            $ans->quotient = $ans->answercount / count($values);
155
            $analysed_answer[] = $ans;
156
        }
157
        $analysed_item[] = $analysed_answer;
158
        return $analysed_item;
159
    }
160
 
161
    public function get_printval($item, $value) {
162
        $printval = '';
163
 
164
        if (!isset($value->value)) {
165
            return $printval;
166
        }
167
 
168
        $info = $this->get_info($item);
169
 
170
        $presentation = explode (FEEDBACK_MULTICHOICERATED_LINE_SEP, $info->presentation);
171
        $index = 1;
172
        foreach ($presentation as $pres) {
173
            if ($value->value == $index) {
174
                $item_label = explode(FEEDBACK_MULTICHOICERATED_VALUE_SEP, $pres);
175
                $printval = format_string($item_label[1]);
176
                break;
177
            }
178
            $index++;
179
        }
180
        return $printval;
181
    }
182
 
183
    public function print_analysed($item, $itemnr = '', $groupid = false, $courseid = false) {
184
        global $OUTPUT;
185
        $analysed_item = $this->get_analysed($item, $groupid, $courseid);
186
        if ($analysed_item) {
187
            echo "<table class=\"analysis itemtype_{$item->typ}\">";
188
            echo '<tr><th class="text-left">';
189
            echo $itemnr . ' ';
190
            if (strval($item->label) !== '') {
191
                echo '('. format_string($item->label).') ';
192
            }
193
            echo format_string($analysed_item[1]);
194
            echo '</th></tr>';
195
            $analysed_vals = $analysed_item[2];
196
            $avg = 0.0;
197
            $count = 0;
198
            $data = [];
199
            foreach ($analysed_vals as $val) {
200
                $avg += $val->avg;
201
                $quotient = format_float($val->quotient * 100, 2);
202
                $answertext = '('.$val->value.') ' . format_text(trim($val->answertext), FORMAT_HTML,
203
                        array('noclean' => true, 'para' => false));
204
 
205
                if ($val->quotient > 0) {
206
                    $strquotient = ' ('.$quotient.' %)';
207
                } else {
208
                    $strquotient = '';
209
                }
210
 
211
                $data['labels'][$count] = $answertext;
212
                $data['series'][$count] = $val->answercount;
213
                $data['series_labels'][$count] = $val->answercount . $strquotient;
214
                $count++;
215
            }
216
            $chart = new \core\chart_bar();
217
            $chart->set_horizontal(true);
218
            $series = new \core\chart_series(format_string(get_string("responses", "feedback")), $data['series']);
219
            $series->set_labels($data['series_labels']);
220
            $chart->add_series($series);
221
            $chart->set_labels($data['labels']);
222
            echo '<tr><td>'. $OUTPUT->render($chart) . '</td></tr>';
223
            $avg = format_float($avg, 2);
224
            echo '<tr><td class="text-left"><b>';
225
            echo get_string('average', 'feedback').': '.$avg.'</b>';
226
            echo '</td></tr>';
227
            echo '</table>';
228
        }
229
    }
230
 
231
    public function excelprint_item(&$worksheet, $row_offset,
232
                             $xls_formats, $item,
233
                             $groupid, $courseid = false) {
234
 
235
        $analysed_item = $this->get_analysed($item, $groupid, $courseid);
236
        if (!$analysed_item) {
237
            return $row_offset;
238
        }
239
 
240
        $data = $analysed_item[2];
241
 
242
        //write the item
243
        $worksheet->write_string($row_offset, 0, $item->label, $xls_formats->head2);
244
        $worksheet->write_string($row_offset, 1, $analysed_item[1], $xls_formats->head2);
245
        if (is_array($data)) {
246
            $avg = 0.0;
247
            $sizeofdata = count($data);
248
            for ($i = 0; $i < $sizeofdata; $i++) {
249
                $analysed_data = $data[$i];
250
 
251
                $worksheet->write_string($row_offset,
252
                                $i + 2,
253
                                trim($analysed_data->answertext).' ('.$analysed_data->value.')',
254
                                $xls_formats->value_bold);
255
 
256
                $worksheet->write_number($row_offset + 1,
257
                                $i + 2,
258
                                $analysed_data->answercount,
259
                                $xls_formats->default);
260
 
261
                $avg += $analysed_data->avg;
262
            }
263
            //mittelwert anzeigen
264
            $worksheet->write_string($row_offset,
265
                                count($data) + 2,
266
                                get_string('average', 'feedback'),
267
                                $xls_formats->value_bold);
268
 
269
            $worksheet->write_number($row_offset + 1,
270
                                count($data) + 2,
271
                                $avg,
272
                                $xls_formats->value_bold);
273
        }
274
        $row_offset +=2;
275
        return $row_offset;
276
    }
277
 
278
    /**
279
     * Options for the multichoice element
280
     * @param stdClass $item
281
     * @return array
282
     */
283
    protected function get_options($item) {
284
        $info = $this->get_info($item);
285
        $lines = explode(FEEDBACK_MULTICHOICERATED_LINE_SEP, $info->presentation);
286
        $options = array();
287
        foreach ($lines as $idx => $line) {
288
            list($weight, $optiontext) = explode(FEEDBACK_MULTICHOICERATED_VALUE_SEP, $line);
289
            $a = new stdclass();
290
            $a->weight = $weight;
291
            $a->name = format_text($optiontext, FORMAT_HTML, array('noclean' => true, 'para' => false));
292
            $options[$idx + 1] = get_string('multichoiceoption', 'feedback', $a);
293
        }
294
        if ($info->subtype === 'r' && !$this->hidenoselect($item)) {
295
            $options = array(0 => get_string('not_selected', 'feedback')) + $options;
296
        }
297
 
298
        return $options;
299
    }
300
 
301
    /**
302
     * Adds an input element to the complete form
303
     *
304
     * @param stdClass $item
305
     * @param mod_feedback_complete_form $form
306
     */
307
    public function complete_form_element($item, $form) {
308
        $info = $this->get_info($item);
309
        $name = $this->get_display_name($item);
310
        $class = 'multichoicerated-' . $info->subtype;
311
        $inputname = $item->typ . '_' . $item->id;
312
        $options = $this->get_options($item);
313
        if ($info->subtype === 'd' || $form->is_frozen()) {
314
            $el = $form->add_form_element($item,
315
                    ['select', $inputname, $name, array('' => '') + $options, array('class' => $class)]);
316
        } else {
317
            $objs = array();
318
            if (!array_key_exists(0, $options)) {
319
                // Always add '0' as hidden element, otherwise form submit data may not have this element.
320
                $objs[] = ['hidden', $inputname];
321
            }
322
            foreach ($options as $idx => $label) {
323
                $objs[] = ['radio', $inputname, '', $label, $idx];
324
            }
325
            // Span to hold the element id. The id is used for drag and drop reordering.
326
            $objs[] = ['static', '', '', html_writer::span('', '', ['id' => 'feedback_item_' . $item->id])];
327
            $separator = $info->horizontal ? ' ' : '<br>';
328
            $class .= ' multichoicerated-' . ($info->horizontal ? 'horizontal' : 'vertical');
329
            $el = $form->add_form_group_element($item, 'group_'.$inputname, $name, $objs, $separator, $class);
330
            $form->set_element_type($inputname, PARAM_INT);
331
 
332
            // Set previously input values.
333
            $form->set_element_default($inputname, $form->get_item_value($item));
334
 
335
            // Process "required" rule.
336
            if ($item->required) {
337
                $form->add_validation_rule(function($values, $files) use ($item) {
338
                    $inputname = $item->typ . '_' . $item->id;
339
                    return empty($values[$inputname]) ? array('group_' . $inputname => get_string('required')) : true;
340
                });
341
            }
342
        }
343
    }
344
 
345
    /**
346
     * Compares the dbvalue with the dependvalue
347
     *
348
     * @param stdClass $item
349
     * @param string $dbvalue is the value input by user in the format as it is stored in the db
350
     * @param string $dependvalue is the value that it needs to be compared against
351
     */
352
    public function compare_value($item, $dbvalue, $dependvalue) {
353
 
354
        if (is_array($dbvalue)) {
355
            $dbvalues = $dbvalue;
356
        } else {
357
            $dbvalues = explode(FEEDBACK_MULTICHOICERATED_LINE_SEP, $dbvalue);
358
        }
359
 
360
        $info = $this->get_info($item);
361
        $presentation = explode (FEEDBACK_MULTICHOICERATED_LINE_SEP, $info->presentation);
362
        $index = 1;
363
        foreach ($presentation as $pres) {
364
            $presvalues = explode(FEEDBACK_MULTICHOICERATED_VALUE_SEP, $pres);
365
 
366
            foreach ($dbvalues as $dbval) {
367
                if ($dbval == $index AND trim($presvalues[1]) == $dependvalue) {
368
                    return true;
369
                }
370
            }
371
            $index++;
372
        }
373
        return false;
374
    }
375
 
376
    public function get_info($item) {
377
        $presentation = empty($item->presentation) ? '' : $item->presentation;
378
 
379
        $info = new stdClass();
380
        //check the subtype of the multichoice
381
        //it can be check(c), radio(r) or dropdown(d)
382
        $info->subtype = '';
383
        $info->presentation = '';
384
        $info->horizontal = false;
385
 
386
        $parts = explode(FEEDBACK_MULTICHOICERATED_TYPE_SEP, $item->presentation);
387
        $info->subtype = $parts[0];
388
        if (count($parts) > 1) {
389
            $info->presentation = $parts[1];
390
        }
391
 
392
        if (!isset($info->subtype)) {
393
            $info->subtype = 'r';
394
        }
395
 
396
        if ($info->subtype != 'd') {
397
            $parts = explode(FEEDBACK_MULTICHOICERATED_ADJUST_SEP, $info->presentation);
398
            $info->presentation = $parts[0];
399
            if (count($parts) > 1) {
400
                $info->horizontal = $parts[1];
401
            }
402
 
403
            if (isset($info->horizontal) AND $info->horizontal == 1) {
404
                $info->horizontal = true;
405
            } else {
406
                $info->horizontal = false;
407
            }
408
        }
409
 
410
        $info->values = $this->prepare_presentation_values_print($info->presentation,
411
                                                    FEEDBACK_MULTICHOICERATED_VALUE_SEP,
412
                                                    FEEDBACK_MULTICHOICERATED_VALUE_SEP2);
413
        return $info;
414
    }
415
 
416
    public function prepare_presentation_values($linesep1,
417
                                         $linesep2,
418
                                         $valuestring,
419
                                         $valuesep1,
420
                                         $valuesep2) {
421
 
422
        $lines = explode($linesep1, $valuestring);
423
        $newlines = array();
424
        foreach ($lines as $line) {
425
            $value = '';
426
            $text = '';
427
            if (strpos($line, $valuesep1) === false) {
428
                $value = 0;
429
                $text = $line;
430
            } else {
431
                @list($value, $text) = explode($valuesep1, $line, 2);
432
            }
433
 
434
            $value = intval($value);
435
            $newlines[] = $value.$valuesep2.$text;
436
        }
437
        $newlines = implode($linesep2, $newlines);
438
        return $newlines;
439
    }
440
 
441
    public function prepare_presentation_values_print($valuestring, $valuesep1, $valuesep2) {
442
        $valuestring = str_replace(array("\n","\r"), "", $valuestring);
443
        return $this->prepare_presentation_values(FEEDBACK_MULTICHOICERATED_LINE_SEP,
444
                                                  "\n",
445
                                                  $valuestring,
446
                                                  $valuesep1,
447
                                                  $valuesep2);
448
    }
449
 
450
    public function prepare_presentation_values_save($valuestring, $valuesep1, $valuesep2) {
451
        $valuestring = str_replace("\r", "\n", $valuestring);
452
        $valuestring = str_replace("\n\n", "\n", $valuestring);
453
        return $this->prepare_presentation_values("\n",
454
                        FEEDBACK_MULTICHOICERATED_LINE_SEP,
455
                        $valuestring,
456
                        $valuesep1,
457
                        $valuesep2);
458
    }
459
 
460
    public function set_ignoreempty($item, $ignoreempty=true) {
461
        $item->options = str_replace(FEEDBACK_MULTICHOICERATED_IGNOREEMPTY, '', $item->options);
462
        if ($ignoreempty) {
463
            $item->options .= FEEDBACK_MULTICHOICERATED_IGNOREEMPTY;
464
        }
465
    }
466
 
467
    public function ignoreempty($item) {
468
        if (strstr($item->options, FEEDBACK_MULTICHOICERATED_IGNOREEMPTY)) {
469
            return true;
470
        }
471
        return false;
472
    }
473
 
474
    public function set_hidenoselect($item, $hidenoselect=true) {
475
        $item->options = str_replace(FEEDBACK_MULTICHOICERATED_HIDENOSELECT, '', $item->options);
476
        if ($hidenoselect) {
477
            $item->options .= FEEDBACK_MULTICHOICERATED_HIDENOSELECT;
478
        }
479
    }
480
 
481
    public function hidenoselect($item) {
482
        if (strstr($item->options, FEEDBACK_MULTICHOICERATED_HIDENOSELECT)) {
483
            return true;
484
        }
485
        return false;
486
    }
487
 
488
    /**
489
     * Return the analysis data ready for external functions.
490
     *
491
     * @param stdClass $item     the item (question) information
492
     * @param int      $groupid  the group id to filter data (optional)
493
     * @param int      $courseid the course id (optional)
494
     * @return array an array of data with non scalar types json encoded
495
     * @since  Moodle 3.3
496
     */
497
    public function get_analysed_for_external($item, $groupid = false, $courseid = false) {
498
 
499
        $externaldata = array();
500
        $data = $this->get_analysed($item, $groupid, $courseid);
501
 
502
        if ($data && !empty($data[2]) && is_array($data[2])) {
503
            foreach ($data[2] as $d) {
504
                $externaldata[] = json_encode($d);
505
            }
506
        }
507
        return $externaldata;
508
    }
509
}