Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.
   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   * @package    moodlecore
  19   * @subpackage backup-moodle2
  20   * @copyright  2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  21   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22   */
  23  
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  
  28  /**
  29   * restore plugin class that provides the necessary information
  30   * needed to restore one random qtype plugin
  31   *
  32   * @copyright  2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  33   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34   */
  35  class restore_qtype_random_plugin extends restore_qtype_plugin {
  36  
  37      /**
  38       * Define the plugin structure.
  39       *
  40       * @return array  Array of {@link restore_path_elements}.
  41       */
  42      protected function define_question_plugin_structure() {
  43          $paths = array();
  44  
  45          // We have to specify a path here if we want after_execute_question to be called.
  46          $elename = 'donothing';
  47          $elepath = $this->get_pathfor('/');
  48  
  49          $paths[] = new restore_path_element($elename, $elepath);
  50  
  51          return $paths; // And we return the interesting paths.
  52      }
  53  
  54      /**
  55       * Required function to process path. Should never be called.
  56       *
  57       * @param object $data Data elements.
  58       */
  59      public function process_donothing($data) {
  60          // Intentionally blank.
  61      }
  62  
  63      /**
  64       * Given one question_states record, return the answer
  65       * recoded pointing to all the restored stuff for random questions
  66       *
  67       * answer format is randomxx-yy, with xx being question->id and
  68       * yy the actual response to the question. We'll delegate the recode
  69       * to the corresponding qtype
  70       *
  71       * also, some old states can contain, simply, one question->id,
  72       * support them, just in case
  73       */
  74      public function recode_legacy_state_answer($state) {
  75          global $DB;
  76  
  77          $answer = $state->answer;
  78          $result = '';
  79          // Randomxx-yy answer format.
  80          if (preg_match('~^random([0-9]+)-(.*)$~', $answer, $matches)) {
  81              $questionid = $matches[1];
  82              $subanswer  = $matches[2];
  83              $newquestionid = $this->get_mappingid('question', $questionid);
  84              $questionqtype = $DB->get_field('question', 'qtype', array('id' => $newquestionid));
  85              // Delegate subanswer recode to proper qtype, faking one question_states record.
  86              $substate = new stdClass();
  87              $substate->question = $newquestionid;
  88              $substate->answer = $subanswer;
  89              $newanswer = $this->step->restore_recode_legacy_answer($substate, $questionqtype);
  90              $result = 'random' . $newquestionid . '-' . $newanswer;
  91  
  92              // Simple question id format.
  93          } else {
  94              $newquestionid = $this->get_mappingid('question', $answer);
  95              $result = $newquestionid;
  96          }
  97          return $result;
  98      }
  99  
 100      /**
 101       * After restoring, make sure questiontext is set properly.
 102       */
 103      public function after_execute_question() {
 104          global $DB;
 105  
 106          // For random questions, questiontext should only ever be '0' or '1'.
 107          // In the past there were sometimes junk values like ''. If there
 108          // were any in the restore, fix them up.
 109          //
 110          // Note, we cannot just do this in one DB query, because MySQL is useless.
 111          // The expected case is that the SELECT returns 0 rows, so loading all the
 112          // ids should not be a problem.
 113          $problemquestions = $DB->get_records_sql_menu("
 114                  SELECT q.id, 1
 115                    FROM {question} q
 116                    JOIN {backup_ids_temp} bi ON q.id = bi.newitemid
 117                   WHERE q.qtype = 'random'
 118                     AND " . $DB->sql_compare_text('q.questiontext') . " = ?
 119                     AND bi.backupid = ?
 120                     AND bi.itemname = 'question_created'
 121                  ", array('', $this->get_restoreid()));
 122  
 123          if (!$problemquestions) {
 124              return; // Nothing to do.
 125          }
 126  
 127          list($idtest, $params) = $DB->get_in_or_equal(array_keys($problemquestions));
 128          $DB->set_field_select('question', 'questiontext', '0', "id $idtest", $params);
 129      }
 130  }