[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/question/type/multichoice/ -> questiontype.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   * The questiontype class for the multiple choice question type.
  19   *
  20   * @package    qtype
  21   * @subpackage multichoice
  22   * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  global $CFG;
  30  require_once($CFG->libdir . '/questionlib.php');
  31  
  32  
  33  /**
  34   * The multiple choice question type.
  35   *
  36   * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  37   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38   */
  39  class qtype_multichoice extends question_type {
  40      public function get_question_options($question) {
  41          global $DB, $OUTPUT;
  42          $question->options = $DB->get_record('qtype_multichoice_options',
  43                  array('questionid' => $question->id), '*', MUST_EXIST);
  44          parent::get_question_options($question);
  45      }
  46  
  47      public function save_question_options($question) {
  48          global $DB;
  49          $context = $question->context;
  50          $result = new stdClass();
  51  
  52          $oldanswers = $DB->get_records('question_answers',
  53                  array('question' => $question->id), 'id ASC');
  54  
  55          // Following hack to check at least two answers exist.
  56          $answercount = 0;
  57          foreach ($question->answer as $key => $answer) {
  58              if ($answer != '') {
  59                  $answercount++;
  60              }
  61          }
  62          if ($answercount < 2) { // Check there are at lest 2 answers for multiple choice.
  63              $result->notice = get_string('notenoughanswers', 'qtype_multichoice', '2');
  64              return $result;
  65          }
  66  
  67          // Insert all the new answers.
  68          $totalfraction = 0;
  69          $maxfraction = -1;
  70          foreach ($question->answer as $key => $answerdata) {
  71              if (trim($answerdata['text']) == '') {
  72                  continue;
  73              }
  74  
  75              // Update an existing answer if possible.
  76              $answer = array_shift($oldanswers);
  77              if (!$answer) {
  78                  $answer = new stdClass();
  79                  $answer->question = $question->id;
  80                  $answer->answer = '';
  81                  $answer->feedback = '';
  82                  $answer->id = $DB->insert_record('question_answers', $answer);
  83              }
  84  
  85              // Doing an import.
  86              $answer->answer = $this->import_or_save_files($answerdata,
  87                      $context, 'question', 'answer', $answer->id);
  88              $answer->answerformat = $answerdata['format'];
  89              $answer->fraction = $question->fraction[$key];
  90              $answer->feedback = $this->import_or_save_files($question->feedback[$key],
  91                      $context, 'question', 'answerfeedback', $answer->id);
  92              $answer->feedbackformat = $question->feedback[$key]['format'];
  93  
  94              $DB->update_record('question_answers', $answer);
  95  
  96              if ($question->fraction[$key] > 0) {
  97                  $totalfraction += $question->fraction[$key];
  98              }
  99              if ($question->fraction[$key] > $maxfraction) {
 100                  $maxfraction = $question->fraction[$key];
 101              }
 102          }
 103  
 104          // Delete any left over old answer records.
 105          $fs = get_file_storage();
 106          foreach ($oldanswers as $oldanswer) {
 107              $fs->delete_area_files($context->id, 'question', 'answerfeedback', $oldanswer->id);
 108              $DB->delete_records('question_answers', array('id' => $oldanswer->id));
 109          }
 110  
 111          $options = $DB->get_record('qtype_multichoice_options', array('questionid' => $question->id));
 112          if (!$options) {
 113              $options = new stdClass();
 114              $options->questionid = $question->id;
 115              $options->correctfeedback = '';
 116              $options->partiallycorrectfeedback = '';
 117              $options->incorrectfeedback = '';
 118              $options->id = $DB->insert_record('qtype_multichoice_options', $options);
 119          }
 120  
 121          $options->single = $question->single;
 122          if (isset($question->layout)) {
 123              $options->layout = $question->layout;
 124          }
 125          $options->answernumbering = $question->answernumbering;
 126          $options->shuffleanswers = $question->shuffleanswers;
 127          $options = $this->save_combined_feedback_helper($options, $question, $context, true);
 128          $DB->update_record('qtype_multichoice_options', $options);
 129  
 130          $this->save_hints($question, true);
 131  
 132          // Perform sanity checks on fractional grades.
 133          if ($options->single) {
 134              if ($maxfraction != 1) {
 135                  $result->noticeyesno = get_string('fractionsnomax', 'qtype_multichoice',
 136                          $maxfraction * 100);
 137                  return $result;
 138              }
 139          } else {
 140              $totalfraction = round($totalfraction, 2);
 141              if ($totalfraction != 1) {
 142                  $result->noticeyesno = get_string('fractionsaddwrong', 'qtype_multichoice',
 143                          $totalfraction * 100);
 144                  return $result;
 145              }
 146          }
 147      }
 148  
 149      protected function make_question_instance($questiondata) {
 150          question_bank::load_question_definition_classes($this->name());
 151          if ($questiondata->options->single) {
 152              $class = 'qtype_multichoice_single_question';
 153          } else {
 154              $class = 'qtype_multichoice_multi_question';
 155          }
 156          return new $class();
 157      }
 158  
 159      protected function make_hint($hint) {
 160          return question_hint_with_parts::load_from_record($hint);
 161      }
 162  
 163      protected function initialise_question_instance(question_definition $question, $questiondata) {
 164          parent::initialise_question_instance($question, $questiondata);
 165          $question->shuffleanswers = $questiondata->options->shuffleanswers;
 166          $question->answernumbering = $questiondata->options->answernumbering;
 167          if (!empty($questiondata->options->layout)) {
 168              $question->layout = $questiondata->options->layout;
 169          } else {
 170              $question->layout = qtype_multichoice_single_question::LAYOUT_VERTICAL;
 171          }
 172          $this->initialise_combined_feedback($question, $questiondata, true);
 173  
 174          $this->initialise_question_answers($question, $questiondata, false);
 175      }
 176  
 177      public function make_answer($answer) {
 178          // Overridden just so we can make it public for use by question.php.
 179          return parent::make_answer($answer);
 180      }
 181  
 182      public function delete_question($questionid, $contextid) {
 183          global $DB;
 184          $DB->delete_records('qtype_multichoice_options', array('questionid' => $questionid));
 185  
 186          parent::delete_question($questionid, $contextid);
 187      }
 188  
 189      public function get_random_guess_score($questiondata) {
 190          if (!$questiondata->options->single) {
 191              // Pretty much impossible to compute for _multi questions. Don't try.
 192              return null;
 193          }
 194  
 195          // Single choice questions - average choice fraction.
 196          $totalfraction = 0;
 197          foreach ($questiondata->options->answers as $answer) {
 198              $totalfraction += $answer->fraction;
 199          }
 200          return $totalfraction / count($questiondata->options->answers);
 201      }
 202  
 203      public function get_possible_responses($questiondata) {
 204          if ($questiondata->options->single) {
 205              $responses = array();
 206  
 207              foreach ($questiondata->options->answers as $aid => $answer) {
 208                  $responses[$aid] = new question_possible_response(
 209                          question_utils::to_plain_text($answer->answer, $answer->answerformat),
 210                          $answer->fraction);
 211              }
 212  
 213              $responses[null] = question_possible_response::no_response();
 214              return array($questiondata->id => $responses);
 215          } else {
 216              $parts = array();
 217  
 218              foreach ($questiondata->options->answers as $aid => $answer) {
 219                  $parts[$aid] = array($aid => new question_possible_response(
 220                          question_utils::to_plain_text($answer->answer, $answer->answerformat),
 221                          $answer->fraction));
 222              }
 223  
 224              return $parts;
 225          }
 226      }
 227  
 228      /**
 229       * @return array of the numbering styles supported. For each one, there
 230       *      should be a lang string answernumberingxxx in teh qtype_multichoice
 231       *      language file, and a case in the switch statement in number_in_style,
 232       *      and it should be listed in the definition of this column in install.xml.
 233       */
 234      public static function get_numbering_styles() {
 235          $styles = array();
 236          foreach (array('abc', 'ABCD', '123', 'iii', 'IIII', 'none') as $numberingoption) {
 237              $styles[$numberingoption] =
 238                      get_string('answernumbering' . $numberingoption, 'qtype_multichoice');
 239          }
 240          return $styles;
 241      }
 242  
 243      public function move_files($questionid, $oldcontextid, $newcontextid) {
 244          parent::move_files($questionid, $oldcontextid, $newcontextid);
 245          $this->move_files_in_answers($questionid, $oldcontextid, $newcontextid, true);
 246          $this->move_files_in_combined_feedback($questionid, $oldcontextid, $newcontextid);
 247          $this->move_files_in_hints($questionid, $oldcontextid, $newcontextid);
 248      }
 249  
 250      protected function delete_files($questionid, $contextid) {
 251          parent::delete_files($questionid, $contextid);
 252          $this->delete_files_in_answers($questionid, $contextid, true);
 253          $this->delete_files_in_combined_feedback($questionid, $contextid);
 254          $this->delete_files_in_hints($questionid, $contextid);
 255      }
 256  }


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