[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 behaviour where the student can submit questions one at a 19 * time for immediate feedback. 20 * 21 * @package qbehaviour 22 * @subpackage interactive 23 * @copyright 2009 The Open University 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 */ 26 27 28 defined('MOODLE_INTERNAL') || die(); 29 30 31 /** 32 * Question behaviour for the interactive model. 33 * 34 * Each question has a submit button next to it which the student can use to 35 * submit it. Once the qustion is submitted, it is not possible for the 36 * student to change their answer any more, but the student gets full feedback 37 * straight away. 38 * 39 * @copyright 2009 The Open University 40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 41 */ 42 class qbehaviour_interactive extends question_behaviour_with_multiple_tries { 43 /** 44 * Special value used for {@link question_display_options::$readonly when 45 * we are showing the try again button to the student during an attempt. 46 * The particular number was chosen randomly. PHP will treat it the same 47 * as true, but in the renderer we reconginse it display the try again 48 * button enabled even though the rest of the question is disabled. 49 * @var integer 50 */ 51 const READONLY_EXCEPT_TRY_AGAIN = 23485299; 52 53 public function is_compatible_question(question_definition $question) { 54 return $question instanceof question_automatically_gradable; 55 } 56 57 public function can_finish_during_attempt() { 58 return true; 59 } 60 61 public function get_right_answer_summary() { 62 return $this->question->get_right_answer_summary(); 63 } 64 65 /** 66 * @return bool are we are currently in the try_again state. 67 */ 68 protected function is_try_again_state() { 69 $laststep = $this->qa->get_last_step(); 70 return $this->qa->get_state()->is_active() && $laststep->has_behaviour_var('submit') && 71 $laststep->has_behaviour_var('_triesleft'); 72 } 73 74 public function adjust_display_options(question_display_options $options) { 75 // We only need different behaviour in try again states. 76 if (!$this->is_try_again_state()) { 77 parent::adjust_display_options($options); 78 if ($this->qa->get_state() == question_state::$invalid && 79 $options->marks == question_display_options::MARK_AND_MAX) { 80 $options->marks = question_display_options::MAX_ONLY; 81 } 82 return; 83 } 84 85 // Let the hint adjust the options. 86 $hint = $this->get_applicable_hint(); 87 if (!is_null($hint)) { 88 $hint->adjust_display_options($options); 89 } 90 91 // Now call the base class method, but protect some fields from being overwritten. 92 $save = clone($options); 93 parent::adjust_display_options($options); 94 $options->feedback = $save->feedback; 95 $options->numpartscorrect = $save->numpartscorrect; 96 97 // In a try-again state, everything except the try again button 98 // Should be read-only. This is a mild hack to achieve this. 99 if (!$options->readonly) { 100 $options->readonly = self::READONLY_EXCEPT_TRY_AGAIN; 101 } 102 } 103 104 public function get_applicable_hint() { 105 if (!$this->is_try_again_state()) { 106 return null; 107 } 108 return $this->question->get_hint(count($this->question->hints) - 109 $this->qa->get_last_behaviour_var('_triesleft'), $this->qa); 110 } 111 112 public function get_expected_data() { 113 if ($this->is_try_again_state()) { 114 return array( 115 'tryagain' => PARAM_BOOL, 116 ); 117 } else if ($this->qa->get_state()->is_active()) { 118 return array( 119 'submit' => PARAM_BOOL, 120 ); 121 } 122 return parent::get_expected_data(); 123 } 124 125 public function get_expected_qt_data() { 126 $hint = $this->get_applicable_hint(); 127 if (!empty($hint->clearwrong)) { 128 return $this->question->get_expected_data(); 129 } 130 return parent::get_expected_qt_data(); 131 } 132 133 public function get_state_string($showcorrectness) { 134 $state = $this->qa->get_state(); 135 if (!$state->is_active() || $state == question_state::$invalid) { 136 return parent::get_state_string($showcorrectness); 137 } 138 139 return get_string('triesremaining', 'qbehaviour_interactive', 140 $this->qa->get_last_behaviour_var('_triesleft')); 141 } 142 143 public function init_first_step(question_attempt_step $step, $variant) { 144 parent::init_first_step($step, $variant); 145 $step->set_behaviour_var('_triesleft', count($this->question->hints) + 1); 146 } 147 148 public function process_action(question_attempt_pending_step $pendingstep) { 149 if ($pendingstep->has_behaviour_var('finish')) { 150 return $this->process_finish($pendingstep); 151 } 152 if ($this->is_try_again_state()) { 153 if ($pendingstep->has_behaviour_var('tryagain')) { 154 return $this->process_try_again($pendingstep); 155 } else { 156 return question_attempt::DISCARD; 157 } 158 } else { 159 if ($pendingstep->has_behaviour_var('comment')) { 160 return $this->process_comment($pendingstep); 161 } else if ($pendingstep->has_behaviour_var('submit')) { 162 return $this->process_submit($pendingstep); 163 } else { 164 return $this->process_save($pendingstep); 165 } 166 } 167 } 168 169 public function summarise_action(question_attempt_step $step) { 170 if ($step->has_behaviour_var('comment')) { 171 return $this->summarise_manual_comment($step); 172 } else if ($step->has_behaviour_var('finish')) { 173 return $this->summarise_finish($step); 174 } else if ($step->has_behaviour_var('tryagain')) { 175 return get_string('tryagain', 'qbehaviour_interactive'); 176 } else if ($step->has_behaviour_var('submit')) { 177 return $this->summarise_submit($step); 178 } else { 179 return $this->summarise_save($step); 180 } 181 } 182 183 public function process_try_again(question_attempt_pending_step $pendingstep) { 184 $pendingstep->set_state(question_state::$todo); 185 return question_attempt::KEEP; 186 } 187 188 public function process_submit(question_attempt_pending_step $pendingstep) { 189 if ($this->qa->get_state()->is_finished()) { 190 return question_attempt::DISCARD; 191 } 192 193 if (!$this->is_complete_response($pendingstep)) { 194 $pendingstep->set_state(question_state::$invalid); 195 196 } else { 197 $triesleft = $this->qa->get_last_behaviour_var('_triesleft'); 198 $response = $pendingstep->get_qt_data(); 199 list($fraction, $state) = $this->question->grade_response($response); 200 if ($state == question_state::$gradedright || $triesleft == 1) { 201 $pendingstep->set_state($state); 202 $pendingstep->set_fraction($this->adjust_fraction($fraction, $pendingstep)); 203 204 } else { 205 $pendingstep->set_behaviour_var('_triesleft', $triesleft - 1); 206 $pendingstep->set_state(question_state::$todo); 207 } 208 $pendingstep->set_new_response_summary($this->question->summarise_response($response)); 209 } 210 return question_attempt::KEEP; 211 } 212 213 protected function adjust_fraction($fraction, question_attempt_pending_step $pendingstep) { 214 $totaltries = $this->qa->get_step(0)->get_behaviour_var('_triesleft'); 215 $triesleft = $this->qa->get_last_behaviour_var('_triesleft'); 216 217 $fraction -= ($totaltries - $triesleft) * $this->question->penalty; 218 $fraction = max($fraction, 0); 219 return $fraction; 220 } 221 222 public function process_finish(question_attempt_pending_step $pendingstep) { 223 if ($this->qa->get_state()->is_finished()) { 224 return question_attempt::DISCARD; 225 } 226 227 $response = $this->qa->get_last_qt_data(); 228 if (!$this->question->is_gradable_response($response)) { 229 $pendingstep->set_state(question_state::$gaveup); 230 231 } else { 232 list($fraction, $state) = $this->question->grade_response($response); 233 $pendingstep->set_fraction($this->adjust_fraction($fraction, $pendingstep)); 234 $pendingstep->set_state($state); 235 } 236 $pendingstep->set_new_response_summary($this->question->summarise_response($response)); 237 return question_attempt::KEEP; 238 } 239 240 public function process_save(question_attempt_pending_step $pendingstep) { 241 $status = parent::process_save($pendingstep); 242 if ($status == question_attempt::KEEP && 243 $pendingstep->get_state() == question_state::$complete) { 244 $pendingstep->set_state(question_state::$todo); 245 } 246 return $status; 247 } 248 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |