Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 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   * @package    core_question
  19   * @copyright  2013 The Open University
  20   * @author     James Pratt me@jamiep.org
  21   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22   */
  23  
  24  namespace core_question\statistics\responses;
  25  
  26  /**
  27   * The leafs of the analysis data structure.
  28   *
  29   * - There is a separate data structure for each question or sub question's analysis
  30   * {@link \core_question\statistics\responses\analysis_for_question}
  31   * or {@link \core_question\statistics\responses\analysis_for_question_all_tries}.
  32   * - There are separate analysis for each variant in this top level instance.
  33   * - Then there are class instances representing the analysis of each of the sub parts of each variant of the question.
  34   * {@link \core_question\statistics\responses\analysis_for_subpart}.
  35   * - Then within the sub part analysis there are response class analysis
  36   * {@link \core_question\statistics\responses\analysis_for_class}.
  37   * - Then within each class analysis there are analysis for each actual response
  38   * {@link \core_question\statistics\responses\analysis_for_actual_response}.
  39   *
  40   * @package    core_question
  41   * @copyright  2014 The Open University
  42   * @author     James Pratt me@jamiep.org
  43   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  44   */
  45  class analysis_for_actual_response {
  46      /**
  47       * @var int[] count per try for this response.
  48       */
  49      protected $trycount = array();
  50  
  51      /**
  52       * @var int total count of tries with this response.
  53       */
  54      protected $totalcount = 0;
  55  
  56      /**
  57       * @var float grade for this response, normally between 0 and 1.
  58       */
  59      protected $fraction;
  60  
  61      /**
  62       * @var string the response as it will be displayed in report.
  63       */
  64      protected $response;
  65  
  66      /**
  67       * @param string $response
  68       * @param float  $fraction
  69       */
  70      public function __construct($response, $fraction) {
  71          $this->response = $response;
  72          $this->fraction = $fraction;
  73      }
  74  
  75      /**
  76       * Used to count the occurrences of response sub parts.
  77       *
  78       * @param int $try the try number, or 0 if only keeping one count, not a count for each try.
  79       */
  80      public function increment_count($try = 0) {
  81          $this->totalcount++;
  82          if ($try != 0) {
  83              if ($try > analyser::MAX_TRY_COUNTED) {
  84                  $try = analyser::MAX_TRY_COUNTED;
  85              }
  86              if (!isset($this->trycount[$try])) {
  87                  $this->trycount[$try] = 0;
  88              }
  89              $this->trycount[$try]++;
  90          }
  91  
  92      }
  93  
  94      /**
  95       * Used to set the count of occurrences of response sub parts, when loading count from cache.
  96       *
  97       * @param int $try the try number, or 0 if only keeping one count, not a count for each try.
  98       * @param int $count
  99       */
 100      public function set_count($try, $count) {
 101          $this->totalcount = $this->totalcount + $count;
 102          $this->trycount[$try] = $count;
 103      }
 104  
 105      /**
 106       * Cache analysis for class.
 107       *
 108       * @param \qubaid_condition $qubaids    which question usages have been analysed.
 109       * @param string            $whichtries which tries have been analysed?
 110       * @param int               $questionid which question.
 111       * @param int               $variantno  which variant.
 112       * @param string            $subpartid which sub part is this actual response in?
 113       * @param string            $responseclassid which response class is this actual response in?
 114       * @param int|null          $calculationtime time when the analysis was done. (Defaults to time()).
 115       */
 116      public function cache($qubaids, $whichtries, $questionid, $variantno, $subpartid, $responseclassid, $calculationtime = null) {
 117          global $DB;
 118          $row = new \stdClass();
 119          $row->hashcode = $qubaids->get_hash_code();
 120          $row->whichtries = $whichtries;
 121          $row->questionid = $questionid;
 122          $row->variant = $variantno;
 123          $row->subqid = $subpartid;
 124          if ($responseclassid === '') {
 125              $row->aid = null;
 126          } else {
 127              $row->aid = $responseclassid;
 128          }
 129          $row->response = $this->response;
 130          $row->credit = $this->fraction;
 131          $row->timemodified = $calculationtime ?? time();
 132          $analysisid = $DB->insert_record('question_response_analysis', $row);
 133          if ($whichtries === \question_attempt::ALL_TRIES) {
 134              foreach ($this->trycount as $try => $count) {
 135                  $countrow = new \stdClass();
 136                  $countrow->try = $try;
 137                  $countrow->rcount = $count;
 138                  $countrow->analysisid = $analysisid;
 139                  $DB->insert_record('question_response_count', $countrow, false);
 140              }
 141          } else {
 142              $countrow = new \stdClass();
 143              $countrow->try = 0;
 144              $countrow->rcount = $this->totalcount;
 145              $countrow->analysisid = $analysisid;
 146              $DB->insert_record('question_response_count', $countrow, false);
 147          }
 148      }
 149  
 150      /**
 151       * Returns an object with a property for each column of the question response analysis table.
 152       *
 153       * @param string $partid
 154       * @param string $modelresponse
 155       * @return object
 156       */
 157      public function data_for_question_response_table($partid, $modelresponse) {
 158          $rowdata = new \stdClass();
 159          $rowdata->part = $partid;
 160          $rowdata->responseclass = $modelresponse;
 161          $rowdata->response = $this->response;
 162          $rowdata->fraction = $this->fraction;
 163          $rowdata->totalcount = $this->totalcount;
 164          $rowdata->trycount = $this->trycount;
 165          return $rowdata;
 166      }
 167  
 168      /**
 169       * What is the highest try number that this response has been seen?
 170       *
 171       * @return int try number
 172       */
 173      public function get_maximum_tries() {
 174          return max(array_keys($this->trycount));
 175      }
 176  }