Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

   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)) {
 146              echo "<table class=\"analysis itemtype_{$item->typ}\">";
 147              echo '<tr><th colspan="2" align="left">';
 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 colspan="2" 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 colspan="2"><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  }