Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

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