[ 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 * Short answer question definition class. 19 * 20 * @package qtype 21 * @subpackage shortanswer 22 * @copyright 2009 The Open University 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 require_once($CFG->dirroot . '/question/type/questionbase.php'); 30 31 /** 32 * Represents a short answer question. 33 * 34 * @copyright 2009 The Open University 35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 36 */ 37 class qtype_shortanswer_question extends question_graded_by_strategy 38 implements question_response_answer_comparer { 39 /** @var boolean whether answers should be graded case-sensitively. */ 40 public $usecase; 41 /** @var array of question_answer. */ 42 public $answers = array(); 43 44 public function __construct() { 45 parent::__construct(new question_first_matching_answer_grading_strategy($this)); 46 } 47 48 public function get_expected_data() { 49 return array('answer' => PARAM_RAW_TRIMMED); 50 } 51 52 public function summarise_response(array $response) { 53 if (isset($response['answer'])) { 54 return $response['answer']; 55 } else { 56 return null; 57 } 58 } 59 60 public function is_complete_response(array $response) { 61 return array_key_exists('answer', $response) && 62 ($response['answer'] || $response['answer'] === '0'); 63 } 64 65 public function get_validation_error(array $response) { 66 if ($this->is_gradable_response($response)) { 67 return ''; 68 } 69 return get_string('pleaseenterananswer', 'qtype_shortanswer'); 70 } 71 72 public function is_same_response(array $prevresponse, array $newresponse) { 73 return question_utils::arrays_same_at_key_missing_is_blank( 74 $prevresponse, $newresponse, 'answer'); 75 } 76 77 public function get_answers() { 78 return $this->answers; 79 } 80 81 public function compare_response_with_answer(array $response, question_answer $answer) { 82 if (!array_key_exists('answer', $response) || is_null($response['answer'])) { 83 return false; 84 } 85 86 return self::compare_string_with_wildcard( 87 $response['answer'], $answer->answer, !$this->usecase); 88 } 89 90 public static function compare_string_with_wildcard($string, $pattern, $ignorecase) { 91 92 // Normalise any non-canonical UTF-8 characters before we start. 93 $pattern = self::safe_normalize($pattern); 94 $string = self::safe_normalize($string); 95 96 // Break the string on non-escaped runs of asterisks. 97 // ** is equivalent to *, but people were doing that, and with many *s it breaks preg. 98 $bits = preg_split('/(?<!\\\\)\*+/', $pattern); 99 100 // Escape regexp special characters in the bits. 101 $escapedbits = array(); 102 foreach ($bits as $bit) { 103 $escapedbits[] = preg_quote(str_replace('\*', '*', $bit), '|'); 104 } 105 // Put it back together to make the regexp. 106 $regexp = '|^' . implode('.*', $escapedbits) . '$|u'; 107 108 // Make the match insensitive if requested to. 109 if ($ignorecase) { 110 $regexp .= 'i'; 111 } 112 113 return preg_match($regexp, trim($string)); 114 } 115 116 /** 117 * Normalise a UTf-8 string to FORM_C, avoiding the pitfalls in PHP's 118 * normalizer_normalize function. 119 * @param string $string the input string. 120 * @return string the normalised string. 121 */ 122 protected static function safe_normalize($string) { 123 if ($string === '') { 124 return ''; 125 } 126 127 if (!function_exists('normalizer_normalize')) { 128 return $string; 129 } 130 131 $normalised = normalizer_normalize($string, Normalizer::FORM_C); 132 if (is_null($normalised)) { 133 // An error occurred in normalizer_normalize, but we have no idea what. 134 debugging('Failed to normalise string: ' . $string, DEBUG_DEVELOPER); 135 return $string; // Return the original string, since it is the best we have. 136 } 137 138 return $normalised; 139 } 140 141 public function get_correct_response() { 142 $response = parent::get_correct_response(); 143 if ($response) { 144 $response['answer'] = $this->clean_response($response['answer']); 145 } 146 return $response; 147 } 148 149 public function clean_response($answer) { 150 // Break the string on non-escaped asterisks. 151 $bits = preg_split('/(?<!\\\\)\*/', $answer); 152 153 // Unescape *s in the bits. 154 $cleanbits = array(); 155 foreach ($bits as $bit) { 156 $cleanbits[] = str_replace('\*', '*', $bit); 157 } 158 159 // Put it back together with spaces to look nice. 160 return trim(implode(' ', $cleanbits)); 161 } 162 163 public function check_file_access($qa, $options, $component, $filearea, 164 $args, $forcedownload) { 165 if ($component == 'question' && $filearea == 'answerfeedback') { 166 $currentanswer = $qa->get_last_qt_var('answer'); 167 $answer = $this->get_matching_answer(array('answer' => $currentanswer)); 168 $answerid = reset($args); // Itemid is answer id. 169 return $options->feedback && $answer && $answerid == $answer->id; 170 171 } else if ($component == 'question' && $filearea == 'hint') { 172 return $this->check_hint_file_access($qa, $options, $args); 173 174 } else { 175 return parent::check_file_access($qa, $options, $component, $filearea, 176 $args, $forcedownload); 177 } 178 } 179 }
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 |