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 * Upgrade library code for the match question type. 19 * 20 * @package qtype_match 21 * @copyright 2010 The Open University 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 29 /** 30 * Class for converting attempt data for match questions when upgrading 31 * attempts to the new question engine. 32 * 33 * This class is used by the code in question/engine/upgrade/upgradelib.php. 34 * 35 * @copyright 2010 The Open University 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 */ 38 class qtype_match_qe2_attempt_updater extends question_qtype_attempt_updater { 39 protected $stems; 40 protected $choices; 41 protected $right; 42 protected $stemorder; 43 protected $choiceorder; 44 protected $flippedchoiceorder; 45 46 public function question_summary() { 47 $this->stems = array(); 48 $this->choices = array(); 49 $this->right = array(); 50 51 foreach ($this->question->options->subquestions as $matchsub) { 52 $ans = $matchsub->answertext; 53 $key = array_search($matchsub->answertext, $this->choices); 54 if ($key === false) { 55 $key = $matchsub->id; 56 $this->choices[$key] = $matchsub->answertext; 57 } 58 59 if ($matchsub->questiontext !== '') { 60 $this->stems[$matchsub->id] = $this->to_text($matchsub->questiontext); 61 $this->right[$matchsub->id] = $key; 62 } 63 } 64 65 return $this->to_text($this->question->questiontext) . ' {' . 66 implode('; ', $this->stems) . '} -> {' . implode('; ', $this->choices) . '}'; 67 } 68 69 public function right_answer() { 70 $answer = array(); 71 foreach ($this->stems as $key => $stem) { 72 $answer[$stem] = $this->choices[$this->right[$key]]; 73 } 74 return $this->make_summary($answer); 75 } 76 77 protected function explode_answer($answer) { 78 if (!$answer) { 79 return array(); 80 } 81 $bits = explode(',', $answer); 82 $selections = array(); 83 foreach ($bits as $bit) { 84 list($stem, $choice) = explode('-', $bit); 85 $selections[$stem] = $choice; 86 } 87 return $selections; 88 } 89 90 protected function make_summary($pairs) { 91 $bits = array(); 92 foreach ($pairs as $stem => $answer) { 93 $bits[] = $stem . ' -> ' . $answer; 94 } 95 return implode('; ', $bits); 96 } 97 98 protected function lookup_choice($choice) { 99 foreach ($this->question->options->subquestions as $matchsub) { 100 if ($matchsub->id == $choice) { 101 if (array_key_exists($matchsub->id, $this->choices)) { 102 return $matchsub->id; 103 } else { 104 return array_search($matchsub->answertext, $this->choices); 105 } 106 } 107 } 108 return null; 109 } 110 111 public function response_summary($state) { 112 $choices = $this->explode_answer($state->answer); 113 if (empty($choices)) { 114 return null; 115 } 116 117 $pairs = array(); 118 foreach ($choices as $stemid => $choicekey) { 119 if (array_key_exists($stemid, $this->stems) && $choices[$stemid]) { 120 $choiceid = $this->lookup_choice($choicekey); 121 if ($choiceid) { 122 $pairs[$this->stems[$stemid]] = $this->choices[$choiceid]; 123 } else { 124 $this->logger->log_assumption("Dealing with a place where the 125 student selected a choice that was later deleted for 126 match question {$this->question->id}"); 127 $pairs[$this->stems[$stemid]] = '[CHOICE THAT WAS LATER DELETED]'; 128 } 129 } 130 } 131 132 if ($pairs) { 133 return $this->make_summary($pairs); 134 } else { 135 return ''; 136 } 137 } 138 139 public function was_answered($state) { 140 $choices = $this->explode_answer($state->answer); 141 foreach ($choices as $choice) { 142 if ($choice) { 143 return true; 144 } 145 } 146 return false; 147 } 148 149 public function set_first_step_data_elements($state, &$data) { 150 $choices = $this->explode_answer($state->answer); 151 foreach ($choices as $key => $notused) { 152 if (array_key_exists($key, $this->stems)) { 153 $this->stemorder[] = $key; 154 } 155 } 156 157 $this->choiceorder = array_keys($this->choices); 158 shuffle($this->choiceorder); 159 $this->flippedchoiceorder = array_combine( 160 array_values($this->choiceorder), array_keys($this->choiceorder)); 161 162 $data['_stemorder'] = implode(',', $this->stemorder); 163 $data['_choiceorder'] = implode(',', $this->choiceorder); 164 } 165 166 public function supply_missing_first_step_data(&$data) { 167 throw new coding_exception('qtype_match_updater::supply_missing_first_step_data ' . 168 'not tested'); 169 $data['_stemorder'] = array_keys($this->stems); 170 $data['_choiceorder'] = shuffle(array_keys($this->choices)); 171 } 172 173 public function set_data_elements_for_step($state, &$data) { 174 $choices = $this->explode_answer($state->answer); 175 176 foreach ($this->stemorder as $i => $key) { 177 if (empty($choices[$key])) { 178 $data['sub' . $i] = 0; 179 continue; 180 } 181 $choice = $this->lookup_choice($choices[$key]); 182 183 if (array_key_exists($choice, $this->flippedchoiceorder)) { 184 $data['sub' . $i] = $this->flippedchoiceorder[$choice] + 1; 185 } else { 186 $data['sub' . $i] = 0; 187 } 188 } 189 } 190 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body