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