Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401]

   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  /**
  18   * Question statistics calculations class. Used in the quiz statistics report.
  19   *
  20   * @package    core_question
  21   * @copyright  2018 Ryan Wyllie <ryan@moodle.com>
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace core_question\statistics\questions;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  require_once($CFG->dirroot . '/question/engine/lib.php');
  30  
  31  /**
  32   * Class calculated_question_summary
  33   *
  34   * This class is used to indicate the statistics for a random question slot should
  35   * be rendered with a link to a summary of the displayed questions.
  36   *
  37   * It's used in the limited view of the statistics calculation in lieu of adding
  38   * the stats for each subquestion individually.
  39   *
  40   * @copyright 2018 Ryan Wyllie <ryan@moodle.com>
  41   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  42   */
  43  class calculated_question_summary extends calculated {
  44  
  45      /**
  46       * @var int only set immediately before display in the table. The order of display in the table.
  47       */
  48      public $subqdisplayorder;
  49  
  50      /**
  51       * @var calculated[] The instances storing the calculated stats of the questions that are being summarised.
  52       */
  53      protected $subqstats;
  54  
  55      /**
  56       * calculated_question_summary constructor.
  57       *
  58       * @param \stdClass $question
  59       * @param int $slot
  60       * @param calculated[] $subqstats The instances of the calculated stats of the questions that are being summarised.
  61       */
  62      public function __construct($question, $slot, $subqstats) {
  63          parent::__construct($question, $slot);
  64  
  65          $this->subqstats = $subqstats;
  66          $this->subquestions = implode(',', array_column($subqstats, 'questionid'));
  67      }
  68  
  69      /**
  70       * This is a summary stat so never breakdown by variant.
  71       *
  72       * @return bool
  73       */
  74      public function break_down_by_variant() {
  75          return false;
  76      }
  77  
  78      /**
  79       * Returns the minimum and maximum values of the given attribute in the summarised calculated stats.
  80       *
  81       * @param string $attribute The attribute that we are looking for its extremums.
  82       * @return array An array of [min,max]
  83       */
  84      public function get_min_max_of($attribute) {
  85          $getmethod = 'get_min_max_of_' . $attribute;
  86          if (method_exists($this, $getmethod)) {
  87              return $this->$getmethod();
  88          } else {
  89              $min = $max = null;
  90              $set = false;
  91  
  92              // We cannot simply use min or max functions because, in theory, some attributes might be non-scalar.
  93              foreach (array_column($this->subqstats, $attribute) as $value) {
  94                  if (is_scalar($value) || is_null($value)) {
  95                      if (!$set) {    // It is not good enough to check if (!isset($min)),
  96                                      // because $min might have been set to null in an earlier iteration.
  97                          $min = $value;
  98                          $max = $value;
  99                          $set = true;
 100                      }
 101  
 102                      $min  = $this->min($min, $value);
 103                      $max  = $this->max($max, $value);
 104                  }
 105              }
 106  
 107              return [$min, $max];
 108          }
 109      }
 110  
 111      /**
 112       * Returns the minimum and maximum values of the standard deviation in the summarised calculated stats.
 113       * @return array An array of [min,max]
 114       */
 115      protected function get_min_max_of_sd() {
 116          $min = $max = null;
 117          $set = false;
 118  
 119          foreach ($this->subqstats as $subqstat) {
 120              if (isset($subqstat->sd) && $subqstat->maxmark > \question_utils::MARK_TOLERANCE) {
 121                  $value = $subqstat->sd / $subqstat->maxmark;
 122              } else {
 123                  $value = null;
 124              }
 125  
 126              if (!$set) {    // It is not good enough to check if (!isset($min)),
 127                              // because $min might have been set to null in an earlier iteration.
 128                  $min = $value;
 129                  $max = $value;
 130                  $set = true;
 131              }
 132  
 133              $min = $this->min($min, $value);
 134              $max = $this->max($max, $value);
 135          }
 136  
 137          return [$min, $max];
 138      }
 139  
 140      /**
 141       * Find higher value.
 142       * A zero value is almost considered equal to zero in comparisons. The only difference is that when being compared to zero,
 143       * zero is higher than null.
 144       *
 145       * @param float|null $value1
 146       * @param float|null $value2
 147       * @return float|null
 148       */
 149      protected function max(float $value1 = null, float $value2 = null) {
 150          $temp1 = $value1 ?: 0;
 151          $temp2 = $value2 ?: 0;
 152  
 153          $tempmax = max($temp1, $temp2);
 154  
 155          if (!$tempmax && $value1 !== 0 && $value2 !== 0) {
 156              $max = null;
 157          } else {
 158              $max = $tempmax;
 159          }
 160  
 161          return $max;
 162      }
 163  
 164      /**
 165       * Find lower value.
 166       * A zero value is almost considered equal to zero in comparisons. The only difference is that when being compared to zero,
 167       * zero is lower than null.
 168       *
 169       * @param float|null $value1
 170       * @param float|null $value2
 171       * @return mixed|null
 172       */
 173      protected function min(float $value1 = null, float $value2 = null) {
 174          $temp1 = $value1 ?: 0;
 175          $temp2 = $value2 ?: 0;
 176  
 177          $tempmin = min($temp1, $temp2);
 178  
 179          if (!$tempmin && $value1 !== 0 && $value2 !== 0) {
 180              $min = null;
 181          } else {
 182              $min = $tempmin;
 183          }
 184  
 185          return $min;
 186      }
 187  }