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