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 * 19 * Data structure to count responses for each of the sub parts of a question. 20 * 21 * @package core_question 22 * @copyright 2014 The Open University 23 * @author James Pratt me@jamiep.org 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 */ 26 27namespace core_question\statistics\responses; 28 29/** 30 * Representing the analysis of each of the sub parts of each variant of the question. 31 * 32 * - There is a separate data structure for each question or sub question's analysis 33 * {@link \core_question\statistics\responses\analysis_for_question} 34 * or {@link \core_question\statistics\responses\analysis_for_question_all_tries}. 35 * - There are separate analysis for each variant in this top level instance. 36 * - Then there are class instances representing the analysis of each of the sub parts of each variant of the question. 37 * {@link \core_question\statistics\responses\analysis_for_subpart}. 38 * - Then within the sub part analysis there are response class analysis 39 * {@link \core_question\statistics\responses\analysis_for_class}. 40 * - Then within each class analysis there are analysis for each actual response 41 * {@link \core_question\statistics\responses\analysis_for_actual_response}. 42 * 43 * @package core_question 44 * @copyright 2014 The Open University 45 * @author James Pratt me@jamiep.org 46 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 47 */ 48class analysis_for_subpart { 49 50 /** 51 * @var analysis_for_class[] 52 */ 53 protected $responseclasses; 54 55 /** 56 * Takes an array of possible_responses as returned from {@link \question_type::get_possible_responses()}. 57 * 58 * @param \question_possible_response[] $responseclasses as returned from {@link \question_type::get_possible_responses()}. 59 */ 60 public function __construct(array $responseclasses = null) { 61 if (is_array($responseclasses)) { 62 foreach ($responseclasses as $responseclassid => $responseclass) { 63 $this->responseclasses[$responseclassid] = new analysis_for_class($responseclass, $responseclassid); 64 } 65 } else { 66 $this->responseclasses = []; 67 } 68 } 69 70 /** 71 * Unique ids for response classes. 72 * 73 * @return string[] 74 */ 75 public function get_response_class_ids() { 76 return array_keys($this->responseclasses); 77 } 78 79 /** 80 * Get the instance of the class handling the analysis of $classid for this sub part. 81 * 82 * @param string $classid id for response class. 83 * @return analysis_for_class 84 */ 85 public function get_response_class($classid) { 86 if (!isset($this->responseclasses[$classid])) { 87 debugging('Unexpected class id ' . $classid . ' encountered.'); 88 $this->responseclasses[$classid] = new analysis_for_class('[Unknown]', $classid); 89 } 90 return $this->responseclasses[$classid]; 91 92 } 93 94 /** 95 * Whether there is more than one response class for responses in this question sub part? 96 * 97 * @return bool Are there? 98 */ 99 public function has_multiple_response_classes() { 100 return count($this->get_response_class_ids()) > 1; 101 } 102 103 /** 104 * Count a part of a response. 105 * 106 * @param \question_classified_response $subpart 107 * @param int $try the try number or zero if not keeping track of try number 108 */ 109 public function count_response($subpart, $try = 0) { 110 $responseanalysisforclass = $this->get_response_class($subpart->responseclassid); 111 $responseanalysisforclass->count_response($subpart->response, $subpart->fraction, $try); 112 } 113 114 /** 115 * Cache analysis for sub part. 116 * 117 * @param \qubaid_condition $qubaids which question usages have been analysed. 118 * @param string $whichtries which tries have been analysed? 119 * @param int $questionid which question. 120 * @param int $variantno which variant. 121 * @param string $subpartid which sub part. 122 */ 123 public function cache($qubaids, $whichtries, $questionid, $variantno, $subpartid) { 124 foreach ($this->get_response_class_ids() as $responseclassid) { 125 $analysisforclass = $this->get_response_class($responseclassid); 126 $analysisforclass->cache($qubaids, $whichtries, $questionid, $variantno, $subpartid, $responseclassid); 127 } 128 } 129 130 /** 131 * Has actual responses different to the model response for this class? 132 * 133 * @return bool whether this analysis has a response class with more than one 134 * different actual response, or if the actual response is different from 135 * the model response. 136 */ 137 public function has_actual_responses() { 138 foreach ($this->get_response_class_ids() as $responseclassid) { 139 if ($this->get_response_class($responseclassid)->has_actual_responses()) { 140 return true; 141 } 142 } 143 return false; 144 } 145 146 /** 147 * What is the highest try number for this sub part? 148 * 149 * @return int max tries 150 */ 151 public function get_maximum_tries() { 152 $max = 1; 153 foreach ($this->get_response_class_ids() as $responseclassid) { 154 $max = max($max, $this->get_response_class($responseclassid)->get_maximum_tries()); 155 } 156 return $max; 157 } 158} 159