Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]

   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   * Question type class for the true-false question type.
  19   *
  20   * @package    qtype
  21   * @subpackage truefalse
  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  require_once($CFG->libdir . '/questionlib.php');
  30  
  31  
  32  /**
  33   * The true-false question type class.
  34   *
  35   * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  36   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class qtype_truefalse extends question_type {
  39      public function save_question_options($question) {
  40          global $DB;
  41          $result = new stdClass();
  42          $context = $question->context;
  43  
  44          // Fetch old answer ids so that we can reuse them.
  45          $oldanswers = $DB->get_records('question_answers',
  46                  array('question' => $question->id), 'id ASC');
  47  
  48          // Save the true answer - update an existing answer if possible.
  49          $answer = array_shift($oldanswers);
  50          if (!$answer) {
  51              $answer = new stdClass();
  52              $answer->question = $question->id;
  53              $answer->answer = '';
  54              $answer->feedback = '';
  55              $answer->id = $DB->insert_record('question_answers', $answer);
  56          }
  57  
  58          $answer->answer   = get_string('true', 'qtype_truefalse');
  59          $answer->fraction = $question->correctanswer;
  60          $answer->feedback = $this->import_or_save_files($question->feedbacktrue,
  61                  $context, 'question', 'answerfeedback', $answer->id);
  62          $answer->feedbackformat = $question->feedbacktrue['format'];
  63          $DB->update_record('question_answers', $answer);
  64          $trueid = $answer->id;
  65  
  66          // Save the false answer - update an existing answer if possible.
  67          $answer = array_shift($oldanswers);
  68          if (!$answer) {
  69              $answer = new stdClass();
  70              $answer->question = $question->id;
  71              $answer->answer = '';
  72              $answer->feedback = '';
  73              $answer->id = $DB->insert_record('question_answers', $answer);
  74          }
  75  
  76          $answer->answer   = get_string('false', 'qtype_truefalse');
  77          $answer->fraction = 1 - (int)$question->correctanswer;
  78          $answer->feedback = $this->import_or_save_files($question->feedbackfalse,
  79                  $context, 'question', 'answerfeedback', $answer->id);
  80          $answer->feedbackformat = $question->feedbackfalse['format'];
  81          $DB->update_record('question_answers', $answer);
  82          $falseid = $answer->id;
  83  
  84          // Delete any left over old answer records.
  85          $fs = get_file_storage();
  86          foreach ($oldanswers as $oldanswer) {
  87              $fs->delete_area_files($context->id, 'question', 'answerfeedback', $oldanswer->id);
  88              $DB->delete_records('question_answers', array('id' => $oldanswer->id));
  89          }
  90  
  91          // Save question options in question_truefalse table.
  92          if ($options = $DB->get_record('question_truefalse', array('question' => $question->id))) {
  93              // No need to do anything, since the answer IDs won't have changed
  94              // But we'll do it anyway, just for robustness.
  95              $options->trueanswer  = $trueid;
  96              $options->falseanswer = $falseid;
  97              $options->showstandardinstruction = !empty($question->showstandardinstruction);
  98              $DB->update_record('question_truefalse', $options);
  99          } else {
 100              $options = new stdClass();
 101              $options->question    = $question->id;
 102              $options->trueanswer  = $trueid;
 103              $options->falseanswer = $falseid;
 104              $options->showstandardinstruction = !empty($question->showstandardinstruction);
 105              $DB->insert_record('question_truefalse', $options);
 106          }
 107  
 108          $this->save_hints($question);
 109  
 110          return true;
 111      }
 112  
 113      public function save_defaults_for_new_questions(stdClass $fromform): void {
 114          parent::save_defaults_for_new_questions($fromform);
 115          $this->set_default_value('showstandardinstruction', $fromform->showstandardinstruction);
 116      }
 117  
 118      /**
 119       * Loads the question type specific options for the question.
 120       */
 121      public function get_question_options($question) {
 122          global $DB, $OUTPUT;
 123          parent::get_question_options($question);
 124          // Get additional information from database
 125          // and attach it to the question object.
 126          if (!$question->options = $DB->get_record('question_truefalse',
 127                  array('question' => $question->id))) {
 128              echo $OUTPUT->notification('Error: Missing question options!');
 129              return false;
 130          }
 131          // Load the answers.
 132          if (!$question->options->answers = $DB->get_records('question_answers',
 133                  array('question' =>  $question->id), 'id ASC')) {
 134              echo $OUTPUT->notification('Error: Missing question answers for truefalse question ' .
 135                      $question->id . '!');
 136              return false;
 137          }
 138  
 139          return true;
 140      }
 141  
 142      protected function initialise_question_instance(question_definition $question, $questiondata) {
 143          parent::initialise_question_instance($question, $questiondata);
 144          $answers = $questiondata->options->answers;
 145          if ($answers[$questiondata->options->trueanswer]->fraction > 0.99) {
 146              $question->rightanswer = true;
 147          } else {
 148              $question->rightanswer = false;
 149          }
 150          $question->truefeedback =  $answers[$questiondata->options->trueanswer]->feedback;
 151          $question->falsefeedback = $answers[$questiondata->options->falseanswer]->feedback;
 152          $question->truefeedbackformat =
 153                  $answers[$questiondata->options->trueanswer]->feedbackformat;
 154          $question->falsefeedbackformat =
 155                  $answers[$questiondata->options->falseanswer]->feedbackformat;
 156          $question->trueanswerid =  $questiondata->options->trueanswer;
 157          $question->falseanswerid = $questiondata->options->falseanswer;
 158          $question->showstandardinstruction = $questiondata->options->showstandardinstruction;
 159      }
 160  
 161      public function delete_question($questionid, $contextid) {
 162          global $DB;
 163          $DB->delete_records('question_truefalse', array('question' => $questionid));
 164  
 165          parent::delete_question($questionid, $contextid);
 166      }
 167  
 168      public function move_files($questionid, $oldcontextid, $newcontextid) {
 169          parent::move_files($questionid, $oldcontextid, $newcontextid);
 170          $this->move_files_in_answers($questionid, $oldcontextid, $newcontextid);
 171      }
 172  
 173      protected function delete_files($questionid, $contextid) {
 174          parent::delete_files($questionid, $contextid);
 175          $this->delete_files_in_answers($questionid, $contextid);
 176      }
 177  
 178      public function get_random_guess_score($questiondata) {
 179          return 0.5;
 180      }
 181  
 182      public function get_possible_responses($questiondata) {
 183          return array(
 184              $questiondata->id => array(
 185                  0 => new question_possible_response(get_string('false', 'qtype_truefalse'),
 186                          $questiondata->options->answers[
 187                          $questiondata->options->falseanswer]->fraction),
 188                  1 => new question_possible_response(get_string('true', 'qtype_truefalse'),
 189                          $questiondata->options->answers[
 190                          $questiondata->options->trueanswer]->fraction),
 191                  null => question_possible_response::no_response()
 192              )
 193          );
 194      }
 195  }