| 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 | class feedback_item_numeric extends feedback_item_base {
 | 
        
           |  |  | 21 |     protected $type = "numeric";
 | 
        
           |  |  | 22 |   | 
        
           |  |  | 23 |     public function build_editform($item, $feedback, $cm) {
 | 
        
           |  |  | 24 |         global $DB, $CFG;
 | 
        
           |  |  | 25 |         require_once('numeric_form.php');
 | 
        
           |  |  | 26 |   | 
        
           |  |  | 27 |         //get the lastposition number of the feedback_items
 | 
        
           |  |  | 28 |         $position = $item->position;
 | 
        
           |  |  | 29 |         $lastposition = $DB->count_records('feedback_item', array('feedback'=>$feedback->id));
 | 
        
           |  |  | 30 |         if ($position == -1) {
 | 
        
           |  |  | 31 |             $i_formselect_last = $lastposition + 1;
 | 
        
           |  |  | 32 |             $i_formselect_value = $lastposition + 1;
 | 
        
           |  |  | 33 |             $item->position = $lastposition + 1;
 | 
        
           |  |  | 34 |         } else {
 | 
        
           |  |  | 35 |             $i_formselect_last = $lastposition;
 | 
        
           |  |  | 36 |             $i_formselect_value = $item->position;
 | 
        
           |  |  | 37 |         }
 | 
        
           |  |  | 38 |         //the elements for position dropdownlist
 | 
        
           |  |  | 39 |         $positionlist = array_slice(range(0, $i_formselect_last), 1, $i_formselect_last, true);
 | 
        
           |  |  | 40 |   | 
        
           |  |  | 41 |         $item->presentation = empty($item->presentation) ? '' : $item->presentation;
 | 
        
           |  |  | 42 |   | 
        
           |  |  | 43 |         $range_from_to = explode('|', $item->presentation);
 | 
        
           |  |  | 44 |         if (isset($range_from_to[0]) AND is_numeric($range_from_to[0])) {
 | 
        
           |  |  | 45 |             $range_from = $this->format_float($range_from_to[0]);
 | 
        
           |  |  | 46 |         } else {
 | 
        
           |  |  | 47 |             $range_from = '-';
 | 
        
           |  |  | 48 |         }
 | 
        
           |  |  | 49 |   | 
        
           |  |  | 50 |         if (isset($range_from_to[1]) AND is_numeric($range_from_to[1])) {
 | 
        
           |  |  | 51 |             $range_to = $this->format_float($range_from_to[1]);
 | 
        
           |  |  | 52 |         } else {
 | 
        
           |  |  | 53 |             $range_to = '-';
 | 
        
           |  |  | 54 |         }
 | 
        
           |  |  | 55 |   | 
        
           |  |  | 56 |         $item->rangefrom = $range_from;
 | 
        
           |  |  | 57 |         $item->rangeto = $range_to;
 | 
        
           |  |  | 58 |   | 
        
           |  |  | 59 |         //all items for dependitem
 | 
        
           |  |  | 60 |         $feedbackitems = feedback_get_depend_candidates_for_item($feedback, $item);
 | 
        
           |  |  | 61 |         $commonparams = array('cmid'=>$cm->id,
 | 
        
           |  |  | 62 |                              'id'=>isset($item->id) ? $item->id : null,
 | 
        
           |  |  | 63 |                              'typ'=>$item->typ,
 | 
        
           |  |  | 64 |                              'items'=>$feedbackitems,
 | 
        
           |  |  | 65 |                              'feedback'=>$feedback->id);
 | 
        
           |  |  | 66 |   | 
        
           |  |  | 67 |         //build the form
 | 
        
           |  |  | 68 |         $customdata = array('item' => $item,
 | 
        
           |  |  | 69 |                             'common' => $commonparams,
 | 
        
           |  |  | 70 |                             'positionlist' => $positionlist,
 | 
        
           |  |  | 71 |                             'position' => $position);
 | 
        
           |  |  | 72 |   | 
        
           |  |  | 73 |         $this->item_form = new feedback_numeric_form('edit_item.php', $customdata);
 | 
        
           |  |  | 74 |     }
 | 
        
           |  |  | 75 |   | 
        
           |  |  | 76 |     public function save_item() {
 | 
        
           |  |  | 77 |         global $DB;
 | 
        
           |  |  | 78 |   | 
        
           |  |  | 79 |         if (!$this->get_data()) {
 | 
        
           |  |  | 80 |             return false;
 | 
        
           |  |  | 81 |         }
 | 
        
           |  |  | 82 |         $item = $this->item;
 | 
        
           |  |  | 83 |   | 
        
           |  |  | 84 |         if (isset($item->clone_item) AND $item->clone_item) {
 | 
        
           |  |  | 85 |             $item->id = ''; //to clone this item
 | 
        
           |  |  | 86 |             $item->position++;
 | 
        
           |  |  | 87 |         }
 | 
        
           |  |  | 88 |   | 
        
           |  |  | 89 |         $item->hasvalue = $this->get_hasvalue();
 | 
        
           |  |  | 90 |         if (!$item->id) {
 | 
        
           |  |  | 91 |             $item->id = $DB->insert_record('feedback_item', $item);
 | 
        
           |  |  | 92 |         } else {
 | 
        
           |  |  | 93 |             $DB->update_record('feedback_item', $item);
 | 
        
           |  |  | 94 |         }
 | 
        
           |  |  | 95 |   | 
        
           |  |  | 96 |         return $DB->get_record('feedback_item', array('id'=>$item->id));
 | 
        
           |  |  | 97 |     }
 | 
        
           |  |  | 98 |   | 
        
           |  |  | 99 |     /**
 | 
        
           |  |  | 100 |      * Helper function for collected data, both for analysis page and export to excel
 | 
        
           |  |  | 101 |      *
 | 
        
           |  |  | 102 |      * @param stdClass $item the db-object from feedback_item
 | 
        
           |  |  | 103 |      * @param int $groupid
 | 
        
           |  |  | 104 |      * @param int $courseid
 | 
        
           |  |  | 105 |      * @return stdClass
 | 
        
           |  |  | 106 |      */
 | 
        
           |  |  | 107 |     protected function get_analysed($item, $groupid = false, $courseid = false) {
 | 
        
           |  |  | 108 |         global $DB;
 | 
        
           |  |  | 109 |   | 
        
           |  |  | 110 |         $analysed = new stdClass();
 | 
        
           |  |  | 111 |         $analysed->data = array();
 | 
        
           |  |  | 112 |         $analysed->name = $item->name;
 | 
        
           |  |  | 113 |         $values = feedback_get_group_values($item, $groupid, $courseid);
 | 
        
           |  |  | 114 |   | 
        
           |  |  | 115 |         $avg = 0.0;
 | 
        
           |  |  | 116 |         $counter = 0;
 | 
        
           |  |  | 117 |         if ($values) {
 | 
        
           |  |  | 118 |             $data = array();
 | 
        
           |  |  | 119 |             foreach ($values as $value) {
 | 
        
           |  |  | 120 |                 if (is_numeric($value->value)) {
 | 
        
           |  |  | 121 |                     $data[] = $value->value;
 | 
        
           |  |  | 122 |                     $avg += $value->value;
 | 
        
           |  |  | 123 |                     $counter++;
 | 
        
           |  |  | 124 |                 }
 | 
        
           |  |  | 125 |             }
 | 
        
           |  |  | 126 |             $avg = $counter > 0 ? $avg / $counter : null;
 | 
        
           |  |  | 127 |             $analysed->data = $data;
 | 
        
           |  |  | 128 |             $analysed->avg = $avg;
 | 
        
           |  |  | 129 |         }
 | 
        
           |  |  | 130 |         return $analysed;
 | 
        
           |  |  | 131 |     }
 | 
        
           |  |  | 132 |   | 
        
           |  |  | 133 |     public function get_printval($item, $value) {
 | 
        
           |  |  | 134 |         if (!isset($value->value)) {
 | 
        
           |  |  | 135 |             return '';
 | 
        
           |  |  | 136 |         }
 | 
        
           |  |  | 137 |   | 
        
           |  |  | 138 |         return $value->value;
 | 
        
           |  |  | 139 |     }
 | 
        
           |  |  | 140 |   | 
        
           |  |  | 141 |     public function print_analysed($item, $itemnr = '', $groupid = false, $courseid = false) {
 | 
        
           |  |  | 142 |   | 
        
           |  |  | 143 |         $values = $this->get_analysed($item, $groupid, $courseid);
 | 
        
           |  |  | 144 |   | 
        
           |  |  | 145 |         if (isset($values->data) AND is_array($values->data)) {
 | 
        
           | 1441 | ariadna | 146 |             echo "<table class=\"analysis itemtype_{$item->typ} table-reboot\">";
 | 
        
           |  |  | 147 |             echo '<tr><th class="text-start">';
 | 
        
           | 1 | efrain | 148 |             echo $itemnr . ' ';
 | 
        
           |  |  | 149 |             if (strval($item->label) !== '') {
 | 
        
           |  |  | 150 |                 echo '('. format_string($item->label).') ';
 | 
        
           |  |  | 151 |             }
 | 
        
           |  |  | 152 |             echo format_text($item->name, FORMAT_HTML, array('noclean' => true, 'para' => false));
 | 
        
           |  |  | 153 |             echo '</th></tr>';
 | 
        
           |  |  | 154 |   | 
        
           |  |  | 155 |             foreach ($values->data as $value) {
 | 
        
           |  |  | 156 |                 echo '<tr><td class="singlevalue">';
 | 
        
           |  |  | 157 |                 echo $this->format_float($value);
 | 
        
           |  |  | 158 |                 echo '</td></tr>';
 | 
        
           |  |  | 159 |             }
 | 
        
           |  |  | 160 |   | 
        
           |  |  | 161 |             if (isset($values->avg)) {
 | 
        
           |  |  | 162 |                 $avg = format_float($values->avg, 2);
 | 
        
           |  |  | 163 |             } else {
 | 
        
           |  |  | 164 |                 $avg = '-';
 | 
        
           |  |  | 165 |             }
 | 
        
           |  |  | 166 |             echo '<tr><td><b>';
 | 
        
           |  |  | 167 |             echo get_string('average', 'feedback').': '.$avg;
 | 
        
           |  |  | 168 |             echo '</b></td></tr>';
 | 
        
           |  |  | 169 |             echo '</table>';
 | 
        
           |  |  | 170 |         }
 | 
        
           |  |  | 171 |     }
 | 
        
           |  |  | 172 |   | 
        
           |  |  | 173 |     public function excelprint_item(&$worksheet, $row_offset,
 | 
        
           |  |  | 174 |                              $xls_formats, $item,
 | 
        
           |  |  | 175 |                              $groupid, $courseid = false) {
 | 
        
           |  |  | 176 |   | 
        
           |  |  | 177 |         $analysed_item = $this->get_analysed($item, $groupid, $courseid);
 | 
        
           |  |  | 178 |   | 
        
           |  |  | 179 |         $worksheet->write_string($row_offset, 0, $item->label, $xls_formats->head2);
 | 
        
           |  |  | 180 |         $worksheet->write_string($row_offset, 1, $item->name, $xls_formats->head2);
 | 
        
           |  |  | 181 |         $data = $analysed_item->data;
 | 
        
           |  |  | 182 |         if (is_array($data)) {
 | 
        
           |  |  | 183 |   | 
        
           |  |  | 184 |             // Export average.
 | 
        
           |  |  | 185 |             $worksheet->write_string($row_offset,
 | 
        
           |  |  | 186 |                                      2,
 | 
        
           |  |  | 187 |                                      get_string('average', 'feedback'),
 | 
        
           |  |  | 188 |                                      $xls_formats->value_bold);
 | 
        
           |  |  | 189 |   | 
        
           |  |  | 190 |             if (isset($analysed_item->avg)) {
 | 
        
           |  |  | 191 |                 $worksheet->write_number($row_offset + 1,
 | 
        
           |  |  | 192 |                                          2,
 | 
        
           |  |  | 193 |                                          $analysed_item->avg,
 | 
        
           |  |  | 194 |                                          $xls_formats->value_bold);
 | 
        
           |  |  | 195 |             } else {
 | 
        
           |  |  | 196 |                 $worksheet->write_string($row_offset + 1,
 | 
        
           |  |  | 197 |                                          2,
 | 
        
           |  |  | 198 |                                          '',
 | 
        
           |  |  | 199 |                                          $xls_formats->value_bold);
 | 
        
           |  |  | 200 |             }
 | 
        
           |  |  | 201 |             $row_offset++;
 | 
        
           |  |  | 202 |         }
 | 
        
           |  |  | 203 |         $row_offset++;
 | 
        
           |  |  | 204 |         return $row_offset;
 | 
        
           |  |  | 205 |     }
 | 
        
           |  |  | 206 |   | 
        
           |  |  | 207 |     /**
 | 
        
           |  |  | 208 |      * Prints the float nicely in the localized format
 | 
        
           |  |  | 209 |      *
 | 
        
           |  |  | 210 |      * Similar to format_float() but automatically calculates the number of decimal places
 | 
        
           |  |  | 211 |      *
 | 
        
           |  |  | 212 |      * @param float $value The float to print
 | 
        
           |  |  | 213 |      * @return string
 | 
        
           |  |  | 214 |      */
 | 
        
           |  |  | 215 |     protected function format_float($value) {
 | 
        
           |  |  | 216 |         if (!is_numeric($value)) {
 | 
        
           |  |  | 217 |             return null;
 | 
        
           |  |  | 218 |         }
 | 
        
           |  |  | 219 |         $decimal = is_int($value) ? 0 : strlen(substr(strrchr($value, '.'), 1));
 | 
        
           |  |  | 220 |         return format_float($value, $decimal);
 | 
        
           |  |  | 221 |     }
 | 
        
           |  |  | 222 |   | 
        
           |  |  | 223 |     /**
 | 
        
           |  |  | 224 |      * Returns human-readable boundaries (min - max)
 | 
        
           |  |  | 225 |      * @param stdClass $item
 | 
        
           |  |  | 226 |      * @return string
 | 
        
           |  |  | 227 |      */
 | 
        
           |  |  | 228 |     protected function get_boundaries_for_display($item) {
 | 
        
           |  |  | 229 |         list($rangefrom, $rangeto) = explode('|', $item->presentation);
 | 
        
           |  |  | 230 |         if (!isset($rangefrom) || !is_numeric($rangefrom)) {
 | 
        
           |  |  | 231 |             $rangefrom = null;
 | 
        
           |  |  | 232 |         }
 | 
        
           |  |  | 233 |         if (!isset($rangeto) || !is_numeric($rangeto)) {
 | 
        
           |  |  | 234 |             $rangeto = null;
 | 
        
           |  |  | 235 |         }
 | 
        
           |  |  | 236 |   | 
        
           |  |  | 237 |         if (is_null($rangefrom) && is_numeric($rangeto)) {
 | 
        
           |  |  | 238 |             return ' (' . get_string('maximal', 'feedback') .
 | 
        
           |  |  | 239 |                         ': ' . $this->format_float($rangeto) . ')';
 | 
        
           |  |  | 240 |         }
 | 
        
           |  |  | 241 |         if (is_numeric($rangefrom) && is_null($rangeto)) {
 | 
        
           |  |  | 242 |             return ' (' . get_string('minimal', 'feedback') .
 | 
        
           |  |  | 243 |                         ': ' . $this->format_float($rangefrom) . ')';
 | 
        
           |  |  | 244 |         }
 | 
        
           |  |  | 245 |         if (is_null($rangefrom) && is_null($rangeto)) {
 | 
        
           |  |  | 246 |             return '';
 | 
        
           |  |  | 247 |         }
 | 
        
           |  |  | 248 |         return ' (' . $this->format_float($rangefrom) .
 | 
        
           |  |  | 249 |                 ' - ' . $this->format_float($rangeto) . ')';
 | 
        
           |  |  | 250 |     }
 | 
        
           |  |  | 251 |   | 
        
           |  |  | 252 |     /**
 | 
        
           |  |  | 253 |      * Returns the postfix to be appended to the display name that is based on other settings
 | 
        
           |  |  | 254 |      *
 | 
        
           |  |  | 255 |      * @param stdClass $item
 | 
        
           |  |  | 256 |      * @return string
 | 
        
           |  |  | 257 |      */
 | 
        
           |  |  | 258 |     public function get_display_name_postfix($item) {
 | 
        
           |  |  | 259 |         return html_writer::span($this->get_boundaries_for_display($item), 'boundaries');
 | 
        
           |  |  | 260 |     }
 | 
        
           |  |  | 261 |   | 
        
           |  |  | 262 |     /**
 | 
        
           |  |  | 263 |      * Adds an input element to the complete form
 | 
        
           |  |  | 264 |      *
 | 
        
           |  |  | 265 |      * @param stdClass $item
 | 
        
           |  |  | 266 |      * @param mod_feedback_complete_form $form
 | 
        
           |  |  | 267 |      */
 | 
        
           |  |  | 268 |     public function complete_form_element($item, $form) {
 | 
        
           |  |  | 269 |         $name = $this->get_display_name($item);
 | 
        
           |  |  | 270 |         $inputname = $item->typ . '_' . $item->id;
 | 
        
           |  |  | 271 |         $form->add_form_element($item,
 | 
        
           |  |  | 272 |                 ['text', $inputname, $name],
 | 
        
           |  |  | 273 |                 true,
 | 
        
           |  |  | 274 |                 false
 | 
        
           |  |  | 275 |                 );
 | 
        
           |  |  | 276 |         $form->set_element_type($inputname, PARAM_NOTAGS);
 | 
        
           |  |  | 277 |         $tmpvalue = $this->format_float($form->get_item_value($item));
 | 
        
           |  |  | 278 |         $form->set_element_default($inputname, $tmpvalue);
 | 
        
           |  |  | 279 |   | 
        
           |  |  | 280 |         // Add form validation rule to check for boundaries.
 | 
        
           |  |  | 281 |         $form->add_validation_rule(function($values, $files) use ($item) {
 | 
        
           |  |  | 282 |             $inputname = $item->typ . '_' . $item->id;
 | 
        
           |  |  | 283 |             list($rangefrom, $rangeto) = explode('|', $item->presentation);
 | 
        
           |  |  | 284 |             if (!isset($values[$inputname]) || trim($values[$inputname]) === '') {
 | 
        
           |  |  | 285 |                 return $item->required ? array($inputname => get_string('required')) : true;
 | 
        
           |  |  | 286 |             }
 | 
        
           |  |  | 287 |             $value = unformat_float($values[$inputname], true);
 | 
        
           |  |  | 288 |             if ($value === false) {
 | 
        
           |  |  | 289 |                 return array($inputname => get_string('invalidnum', 'error'));
 | 
        
           |  |  | 290 |             }
 | 
        
           |  |  | 291 |             if ((is_numeric($rangefrom) && $value < floatval($rangefrom)) ||
 | 
        
           |  |  | 292 |                     (is_numeric($rangeto) && $value > floatval($rangeto))) {
 | 
        
           |  |  | 293 |                 return array($inputname => get_string('numberoutofrange', 'feedback'));
 | 
        
           |  |  | 294 |             }
 | 
        
           |  |  | 295 |             return true;
 | 
        
           |  |  | 296 |         });
 | 
        
           |  |  | 297 |     }
 | 
        
           |  |  | 298 |   | 
        
           |  |  | 299 |     public function create_value($data) {
 | 
        
           |  |  | 300 |         $data = unformat_float($data, true);
 | 
        
           |  |  | 301 |   | 
        
           |  |  | 302 |         if (is_numeric($data)) {
 | 
        
           |  |  | 303 |             $data = floatval($data);
 | 
        
           |  |  | 304 |         } else {
 | 
        
           |  |  | 305 |             $data = '';
 | 
        
           |  |  | 306 |         }
 | 
        
           |  |  | 307 |         return $data;
 | 
        
           |  |  | 308 |     }
 | 
        
           |  |  | 309 |   | 
        
           |  |  | 310 |     /**
 | 
        
           |  |  | 311 |      * Return the analysis data ready for external functions.
 | 
        
           |  |  | 312 |      *
 | 
        
           |  |  | 313 |      * @param stdClass $item     the item (question) information
 | 
        
           |  |  | 314 |      * @param int      $groupid  the group id to filter data (optional)
 | 
        
           |  |  | 315 |      * @param int      $courseid the course id (optional)
 | 
        
           |  |  | 316 |      * @return array an array of data with non scalar types json encoded
 | 
        
           |  |  | 317 |      * @since  Moodle 3.3
 | 
        
           |  |  | 318 |      */
 | 
        
           |  |  | 319 |     public function get_analysed_for_external($item, $groupid = false, $courseid = false) {
 | 
        
           |  |  | 320 |   | 
        
           |  |  | 321 |         $externaldata = array();
 | 
        
           |  |  | 322 |         $data = $this->get_analysed($item, $groupid, $courseid);
 | 
        
           |  |  | 323 |   | 
        
           |  |  | 324 |         if (is_array($data->data)) {
 | 
        
           |  |  | 325 |             return $data->data; // No need to json, scalar type.
 | 
        
           |  |  | 326 |         }
 | 
        
           |  |  | 327 |         return $externaldata;
 | 
        
           |  |  | 328 |     }
 | 
        
           |  |  | 329 | }
 |