[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/question/type/shortanswer/ -> question.php (source)

   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  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1