Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 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   * Drag-and-drop onto image question definition class.
  19   *
  20   * @package    qtype_ddimageortext
  21   * @copyright  2009 The Open University
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  require_once($CFG->dirroot . '/question/type/questionbase.php');
  29  require_once($CFG->dirroot . '/question/type/gapselect/questionbase.php');
  30  
  31  
  32  /**
  33   * Represents a drag-and-drop onto image question.
  34   *
  35   * @copyright  2009 The Open University
  36   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class qtype_ddtoimage_question_base extends qtype_gapselect_question_base {
  39      public function clear_wrong_from_response(array $response) {
  40          foreach ($this->places as $place => $notused) {
  41              if (array_key_exists($this->field($place), $response) &&
  42                      $response[$this->field($place)] != $this->get_right_choice_for($place)) {
  43                  $response[$this->field($place)] = '';
  44              }
  45          }
  46          return $response;
  47      }
  48  
  49      public function get_right_choice_for($placeno) {
  50          $place = $this->places[$placeno];
  51          foreach ($this->choiceorder[$place->group] as $choicekey => $choiceid) {
  52              if ($this->rightchoices[$placeno] == $choiceid) {
  53                  return $choicekey;
  54              }
  55          }
  56      }
  57      public function summarise_response(array $response) {
  58          $allblank = true;
  59          foreach ($this->places as $placeno => $place) {
  60              $summariseplace = $place->summarise();
  61              if (array_key_exists($this->field($placeno), $response) &&
  62                                                                  $response[$this->field($placeno)]) {
  63                  $selected = $this->get_selected_choice($place->group,
  64                                                                  $response[$this->field($placeno)]);
  65                  if (isset($selected)) {
  66                      $summarisechoice = $selected->summarise();
  67                  } else {
  68                      $summarisechoice = get_string('deletedchoice', 'qtype_ddimageortext');
  69                  }
  70                  $allblank = false;
  71              } else {
  72                  $summarisechoice = '';
  73              }
  74              $choices[] = "$summariseplace -> {{$summarisechoice}}";
  75          }
  76          if ($allblank) {
  77              return null;
  78          }
  79          return implode(' ', $choices);
  80      }
  81  
  82      public function check_file_access($qa, $options, $component, $filearea, $args, $forcedownload) {
  83          if ($filearea == 'bgimage' || $filearea == 'dragimage') {
  84              $validfilearea = true;
  85          } else {
  86              $validfilearea = false;
  87          }
  88          if ($component == 'qtype_ddimageortext' && $validfilearea) {
  89              $question = $qa->get_question();
  90              $itemid = reset($args);
  91              if ($filearea == 'bgimage') {
  92                  return $itemid == $question->id;
  93              } else if ($filearea == 'dragimage') {
  94                  foreach ($question->choices as $group) {
  95                      foreach ($group as $drag) {
  96                          if ($drag->id == $itemid) {
  97                              return true;
  98                          }
  99                      }
 100                  }
 101                  return false;
 102              }
 103          } else {
 104              return parent::check_file_access($qa, $options, $component,
 105                                                                  $filearea, $args, $forcedownload);
 106          }
 107      }
 108      public function get_validation_error(array $response) {
 109          if ($this->is_complete_response($response)) {
 110              return '';
 111          }
 112          return get_string('pleasedraganimagetoeachdropregion', 'qtype_ddimageortext');
 113      }
 114  
 115      public function classify_response(array $response) {
 116          $parts = array();
 117          foreach ($this->places as $placeno => $place) {
 118              $group = $place->group;
 119              if (!array_key_exists($this->field($placeno), $response) ||
 120                      !$response[$this->field($placeno)]) {
 121                  $parts[$placeno] = question_classified_response::no_response();
 122                  continue;
 123              }
 124  
 125              $fieldname = $this->field($placeno);
 126              $choicekey = $this->choiceorder[$group][$response[$fieldname]];
 127              $choice = $this->choices[$group][$choicekey];
 128  
 129              $correct = $this->get_right_choice_for($placeno) == $response[$fieldname];
 130              if ($correct) {
 131                  $grade = 1;
 132              } else {
 133                  $grade = 0;
 134              }
 135              $parts[$placeno] = new question_classified_response($choice->no, $choice->summarise(), $grade);
 136          }
 137          return $parts;
 138      }
 139  
 140      public function get_random_guess_score() {
 141          if (empty($this->places)) {
 142              // Having no places would be nonsensical. However, it used to be possible
 143              // to create questions like that, so avoid errors in this case.
 144              return null;
 145          }
 146  
 147          $accum = 0;
 148          foreach ($this->places as $place) {
 149              foreach ($this->choices[$place->group] as $choice) {
 150                  if ($choice->infinite) {
 151                      return null;
 152                  }
 153              }
 154              $accum += 1 / count($this->choices[$place->group]);
 155          }
 156  
 157          return $accum / count($this->places);
 158      }
 159  
 160  
 161      public function get_question_summary() {
 162          $summary = '';
 163          if (!html_is_blank($this->questiontext)) {
 164              $question = $this->html_to_text($this->questiontext, $this->questiontextformat);
 165              $summary .= $question . '; ';
 166          }
 167          $places = array();
 168          foreach ($this->places as $place) {
 169              $cs = array();
 170              foreach ($this->choices[$place->group] as $choice) {
 171                  $cs[] = $choice->summarise();
 172              }
 173              $places[] = '[[' . $place->summarise() . ']] -> {' . implode(' / ', $cs) . '}';
 174          }
 175          $summary .= implode('; ', $places);
 176          return $summary;
 177      }
 178  }