Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]
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 * This file defines the quiz responses table for showing first or all tries at a question. 19 * 20 * @package quiz_responses 21 * @copyright 2014 The Open University 22 * @author Jamie Pratt <me@jamiep.org> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 use mod_quiz\quiz_attempt; 27 28 defined('MOODLE_INTERNAL') || die(); 29 30 /** 31 * This is a table subclass for displaying the quiz responses report, showing first or all tries. 32 * 33 * @package quiz_responses 34 * @copyright 2014 The Open University 35 * @author Jamie Pratt <me@jamiep.org> 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 */ 38 class quiz_first_or_all_responses_table extends quiz_last_responses_table { 39 40 /** 41 * The full question usage object for each try shown in report. 42 * 43 * @var question_usage_by_activity[] 44 */ 45 protected $questionusagesbyactivity; 46 47 protected function field_from_extra_data($tablerow, $slot, $field) { 48 $questionattempt = $this->get_question_attempt($tablerow->usageid, $slot); 49 switch($field) { 50 case 'questionsummary' : 51 return $questionattempt->get_question_summary(); 52 case 'responsesummary' : 53 return $this->get_summary_after_try($tablerow, $slot); 54 case 'rightanswer' : 55 return $questionattempt->get_right_answer_summary(); 56 default : 57 throw new coding_exception('Unknown question attempt field.'); 58 } 59 } 60 61 62 protected function load_extra_data() { 63 if (count($this->rawdata) === 0) { 64 return; 65 } 66 $qubaids = $this->get_qubaids_condition(); 67 $dm = new question_engine_data_mapper(); 68 $this->questionusagesbyactivity = $dm->load_questions_usages_by_activity($qubaids); 69 70 // Insert an extra field in attempt data and extra rows where necessary. 71 $newrawdata = []; 72 foreach ($this->rawdata as $attempt) { 73 if (!isset($this->questionusagesbyactivity[$attempt->usageid])) { 74 // This is a user without attempts. 75 $attempt->try = 0; 76 $attempt->lasttryforallparts = true; 77 $newrawdata[] = $attempt; 78 continue; 79 } 80 81 // We have an attempt, which may require several rows. 82 $maxtriesinanyslot = 1; 83 foreach ($this->questionusagesbyactivity[$attempt->usageid]->get_slots() as $slot) { 84 $tries = $this->get_no_of_tries($attempt, $slot); 85 $maxtriesinanyslot = max($maxtriesinanyslot, $tries); 86 } 87 for ($try = 1; $try <= $maxtriesinanyslot; $try++) { 88 $newtablerow = clone($attempt); 89 $newtablerow->lasttryforallparts = ($try == $maxtriesinanyslot); 90 if ($try !== $maxtriesinanyslot) { 91 $newtablerow->state = quiz_attempt::IN_PROGRESS; 92 } 93 $newtablerow->try = $try; 94 $newrawdata[] = $newtablerow; 95 if ($this->options->whichtries == question_attempt::FIRST_TRY) { 96 break; 97 } 98 } 99 } 100 $this->rawdata = $newrawdata; 101 } 102 103 /** 104 * Return the question attempt object. 105 * 106 * @param int $questionusagesid 107 * @param int $slot 108 * @return question_attempt 109 */ 110 protected function get_question_attempt($questionusagesid, $slot) { 111 return $this->questionusagesbyactivity[$questionusagesid]->get_question_attempt($slot); 112 } 113 114 /** 115 * Find the state for $slot given after this try. 116 * 117 * @param stdClass $tablerow row data 118 * @param int $slot Slot number. 119 * @return question_state The question state after the attempt. 120 */ 121 protected function slot_state($tablerow, $slot) { 122 $qa = $this->get_question_attempt($tablerow->usageid, $slot); 123 $submissionsteps = $qa->get_steps_with_submitted_response_iterator(); 124 $step = $submissionsteps[$tablerow->try]; 125 if ($step === null) { 126 return null; 127 } 128 if ($this->is_last_try($tablerow, $slot, $tablerow->try)) { 129 // If this is the last try then the step with the try data does not contain the correct state. We need to 130 // use the last step's state, after the attempt has been finished. 131 return $qa->get_state(); 132 } 133 return $step->get_state(); 134 } 135 136 137 /** 138 * Get the summary of the response after the try. 139 * 140 * @param stdClass $tablerow row data 141 * @param int $slot Slot number. 142 * @return string summary for the question after this try. 143 */ 144 public function get_summary_after_try($tablerow, $slot) { 145 $qa = $this->get_question_attempt($tablerow->usageid, $slot); 146 if (!($qa->get_question(false) instanceof question_manually_gradable)) { 147 // No responses, and we cannot call summarise_response below. 148 return null; 149 } 150 $submissionsteps = $qa->get_steps_with_submitted_response_iterator(); 151 $step = $submissionsteps[$tablerow->try]; 152 if ($step === null) { 153 return null; 154 } 155 $qtdata = $step->get_qt_data(); 156 return $qa->get_question()->summarise_response($qtdata); 157 } 158 159 /** 160 * Has this question usage been flagged? 161 * 162 * @param int $questionusageid Question usage id. 163 * @param int $slot Slot number 164 * @return bool Has it been flagged? 165 */ 166 protected function is_flagged($questionusageid, $slot) { 167 return $this->get_question_attempt($questionusageid, $slot)->is_flagged(); 168 } 169 170 /** 171 * The grade for this slot after this try. 172 * 173 * @param stdClass $tablerow attempt data from db. 174 * @param int $slot Slot number. 175 * @return float The fraction. 176 */ 177 protected function slot_fraction($tablerow, $slot) { 178 $qa = $this->get_question_attempt($tablerow->usageid, $slot); 179 $submissionsteps = $qa->get_steps_with_submitted_response_iterator(); 180 $step = $submissionsteps[$tablerow->try]; 181 if ($step === null) { 182 return null; 183 } 184 if ($this->is_last_try($tablerow, $slot, $tablerow->try)) { 185 // If this is the last try then the step with the try data does not contain the correct fraction. We need to 186 // use the last step's fraction, after the attempt has been finished. 187 return $qa->get_fraction(); 188 } 189 return $step->get_fraction(); 190 } 191 192 /** 193 * Is this the last try in the question attempt? 194 * 195 * @param stdClass $tablerow attempt data from db. 196 * @param int $slot Slot number 197 * @param int $tryno try no 198 * @return bool Is it the last try? 199 */ 200 protected function is_last_try($tablerow, $slot, $tryno) { 201 return $tryno == $this->get_no_of_tries($tablerow, $slot); 202 } 203 204 /** 205 * How many tries were attempted at this question in this slot, during this usage? 206 * 207 * @param stdClass $tablerow attempt data from db. 208 * @param int $slot Slot number 209 * @return int the number of tries in the question attempt for slot $slot. 210 */ 211 public function get_no_of_tries($tablerow, $slot) { 212 return count($this->get_question_attempt($tablerow->usageid, $slot)->get_steps_with_submitted_response_iterator()); 213 } 214 215 216 /** 217 * What is the step no this try was seen in? 218 * 219 * @param int $questionusageid The question usage id. 220 * @param int $slot Slot number 221 * @param int $tryno Try no 222 * @return int the step no or zero if not found 223 */ 224 protected function step_no_for_try($questionusageid, $slot, $tryno) { 225 $qa = $this->get_question_attempt($questionusageid, $slot); 226 return $qa->get_steps_with_submitted_response_iterator()->step_no_for_try($tryno); 227 } 228 229 public function col_checkbox($tablerow) { 230 if ($tablerow->try != 1) { 231 return ''; 232 } else { 233 return parent::col_checkbox($tablerow); 234 } 235 } 236 237 /** 238 * Cell value function for email column. This extracts the contents for any cell in the email column from the row data. 239 * 240 * @param stdClass $tablerow Row data. 241 * @return string What to put in the cell for this column, for this row data. 242 */ 243 public function col_email($tablerow) { 244 if ($tablerow->try > 1) { 245 return ''; 246 } else { 247 return $tablerow->email; 248 } 249 } 250 251 /** 252 * Cell value function for sumgrades column. This extracts the contents for any cell in the sumgrades column from the row data. 253 * 254 * @param stdClass $tablerow Row data. 255 * @return string What to put in the cell for this column, for this row data. 256 */ 257 public function col_sumgrades($tablerow) { 258 if ($tablerow->try == 0) { 259 // We are showing a user without a quiz attempt. 260 return '-'; 261 } else if (!$tablerow->lasttryforallparts) { 262 // There are more rows to come for this quiz attempt, so we will show this later. 263 return ''; 264 } else { 265 // Last row for this attempt. Now is the time to show attempt-related data. 266 return parent::col_sumgrades($tablerow); 267 } 268 } 269 270 public function col_state($tablerow) { 271 if ($tablerow->try == 0) { 272 // We are showing a user without a quiz attempt. 273 return '-'; 274 } else if (!$tablerow->lasttryforallparts) { 275 // There are more rows to come for this quiz attempt, so we will show this later. 276 return ''; 277 } else { 278 // Last row for this attempt. Now is the time to show attempt-related data. 279 return parent::col_state($tablerow); 280 } 281 } 282 283 public function get_row_class($tablerow) { 284 if ($this->options->whichtries == question_attempt::ALL_TRIES && $tablerow->lasttryforallparts) { 285 return 'lastrowforattempt'; 286 } else { 287 return ''; 288 } 289 } 290 291 public function make_review_link($data, $tablerow, $slot) { 292 if ($this->slot_state($tablerow, $slot) === null) { 293 return $data; 294 } else { 295 return parent::make_review_link($data, $tablerow, $slot); 296 } 297 } 298 } 299 300
title
Description
Body
title
Description
Body
title
Description
Body
title
Body