[ Index ]

PHP Cross Reference of moodle-2.8

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 delete_question($questionid, $contextid) {
 178          global $DB;
 179          $DB->delete_records('qtype_multichoice_options', array('questionid' => $questionid));
 180  
 181          parent::delete_question($questionid, $contextid);
 182      }
 183  
 184      public function get_random_guess_score($questiondata) {
 185          if (!$questiondata->options->single) {
 186              // Pretty much impossible to compute for _multi questions. Don't try.
 187              return null;
 188          }
 189  
 190          // Single choice questions - average choice fraction.
 191          $totalfraction = 0;
 192          foreach ($questiondata->options->answers as $answer) {
 193              $totalfraction += $answer->fraction;
 194          }
 195          return $totalfraction / count($questiondata->options->answers);
 196      }
 197  
 198      public function get_possible_responses($questiondata) {
 199          if ($questiondata->options->single) {
 200              $responses = array();
 201  
 202              foreach ($questiondata->options->answers as $aid => $answer) {
 203                  $responses[$aid] = new question_possible_response(
 204                          question_utils::to_plain_text($answer->answer, $answer->answerformat),
 205                          $answer->fraction);
 206              }
 207  
 208              $responses[null] = question_possible_response::no_response();
 209              return array($questiondata->id => $responses);
 210          } else {
 211              $parts = array();
 212  
 213              foreach ($questiondata->options->answers as $aid => $answer) {
 214                  $parts[$aid] = array($aid => new question_possible_response(
 215                          question_utils::to_plain_text($answer->answer, $answer->answerformat),
 216                          $answer->fraction));
 217              }
 218  
 219              return $parts;
 220          }
 221      }
 222  
 223      /**
 224       * @return array of the numbering styles supported. For each one, there
 225       *      should be a lang string answernumberingxxx in teh qtype_multichoice
 226       *      language file, and a case in the switch statement in number_in_style,
 227       *      and it should be listed in the definition of this column in install.xml.
 228       */
 229      public static function get_numbering_styles() {
 230          $styles = array();
 231          foreach (array('abc', 'ABCD', '123', 'iii', 'IIII', 'none') as $numberingoption) {
 232              $styles[$numberingoption] =
 233                      get_string('answernumbering' . $numberingoption, 'qtype_multichoice');
 234          }
 235          return $styles;
 236      }
 237  
 238      public function move_files($questionid, $oldcontextid, $newcontextid) {
 239          parent::move_files($questionid, $oldcontextid, $newcontextid);
 240          $this->move_files_in_answers($questionid, $oldcontextid, $newcontextid, true);
 241          $this->move_files_in_combined_feedback($questionid, $oldcontextid, $newcontextid);
 242          $this->move_files_in_hints($questionid, $oldcontextid, $newcontextid);
 243      }
 244  
 245      protected function delete_files($questionid, $contextid) {
 246          parent::delete_files($questionid, $contextid);
 247          $this->delete_files_in_answers($questionid, $contextid, true);
 248          $this->delete_files_in_combined_feedback($questionid, $contextid);
 249          $this->delete_files_in_hints($questionid, $contextid);
 250      }
 251  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1