PageRenderTime 23ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/question/type/match/backup/moodle2/restore_qtype_match_plugin.class.php

https://github.com/kpike/moodle
PHP | 241 lines | 124 code | 32 blank | 85 comment | 13 complexity | c94a58e3925c1c938f9445279fd43c99 MD5 | raw file
  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. * @package moodlecore
  18. * @subpackage backup-moodle2
  19. * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  20. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  21. */
  22. defined('MOODLE_INTERNAL') || die();
  23. /**
  24. * restore plugin class that provides the necessary information
  25. * needed to restore one match qtype plugin
  26. *
  27. * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  28. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  29. */
  30. class restore_qtype_match_plugin extends restore_qtype_plugin {
  31. /**
  32. * Returns the paths to be handled by the plugin at question level
  33. */
  34. protected function define_question_plugin_structure() {
  35. $paths = array();
  36. // Add own qtype stuff
  37. $elename = 'matchoptions';
  38. // We used get_recommended_name() so this works.
  39. $elepath = $this->get_pathfor('/matchoptions');
  40. $paths[] = new restore_path_element($elename, $elepath);
  41. $elename = 'match';
  42. // We used get_recommended_name() so this works.
  43. $elepath = $this->get_pathfor('/matches/match');
  44. $paths[] = new restore_path_element($elename, $elepath);
  45. return $paths; // And we return the interesting paths
  46. }
  47. /**
  48. * Process the qtype/matchoptions element
  49. */
  50. public function process_matchoptions($data) {
  51. global $DB;
  52. $data = (object)$data;
  53. $oldid = $data->id;
  54. // Detect if the question is created or mapped
  55. $oldquestionid = $this->get_old_parentid('question');
  56. $newquestionid = $this->get_new_parentid('question');
  57. $questioncreated = $this->get_mappingid('question_created', $oldquestionid) ? true : false;
  58. // If the question has been created by restore, we need to create its question_match too
  59. if ($questioncreated) {
  60. // Fill in some field that were added in 2.1, and so which may be missing
  61. // from backups made in older versions of Moodle.
  62. if (!isset($data->correctfeedback)) {
  63. $data->correctfeedback = '';
  64. $data->correctfeedbackformat = FORMAT_HTML;
  65. }
  66. if (!isset($data->partiallycorrectfeedback)) {
  67. $data->partiallycorrectfeedback = '';
  68. $data->partiallycorrectfeedbackformat = FORMAT_HTML;
  69. }
  70. if (!isset($data->incorrectfeedback)) {
  71. $data->incorrectfeedback = '';
  72. $data->incorrectfeedbackformat = FORMAT_HTML;
  73. }
  74. if (!isset($data->shownumcorrect)) {
  75. $data->shownumcorrect = 0;
  76. }
  77. // Adjust some columns
  78. $data->question = $newquestionid;
  79. // Keep question_match->subquestions unmodified
  80. // after_execute_question() will perform the remapping once all subquestions
  81. // have been created
  82. // Insert record
  83. $newitemid = $DB->insert_record('question_match', $data);
  84. // Create mapping
  85. $this->set_mapping('question_match', $oldid, $newitemid);
  86. }
  87. }
  88. /**
  89. * Process the qtype/matches/match element
  90. */
  91. public function process_match($data) {
  92. global $DB;
  93. $data = (object)$data;
  94. $oldid = $data->id;
  95. // Detect if the question is created or mapped
  96. $oldquestionid = $this->get_old_parentid('question');
  97. $newquestionid = $this->get_new_parentid('question');
  98. $questioncreated = $this->get_mappingid('question_created', $oldquestionid) ? true : false;
  99. if ($questioncreated) {
  100. // If the question has been created by restore, we need to create its
  101. // question_match_sub too
  102. // Adjust some columns
  103. $data->question = $newquestionid;
  104. // Insert record
  105. $newitemid = $DB->insert_record('question_match_sub', $data);
  106. // Create mapping (there are files and states based on this)
  107. $this->set_mapping('question_match_sub', $oldid, $newitemid);
  108. } else {
  109. // match questions require mapping of question_match_sub, because
  110. // they are used by question_states->answer
  111. // Look for matching subquestion (by question, questiontext and answertext)
  112. $sub = $DB->get_record_select('question_match_sub', 'question = ? AND ' .
  113. $DB->sql_compare_text('questiontext') . ' = ' .
  114. $DB->sql_compare_text('?').' AND answertext = ?',
  115. array($newquestionid, $data->questiontext, $data->answertext),
  116. 'id', IGNORE_MULTIPLE);
  117. // Found, let's create the mapping
  118. if ($sub) {
  119. $this->set_mapping('question_match_sub', $oldid, $sub->id);
  120. } else {
  121. throw new restore_step_exception('error_question_match_sub_missing_in_db', $data);
  122. }
  123. }
  124. }
  125. /**
  126. * This method is executed once the whole restore_structure_step,
  127. * more exactly ({@link restore_create_categories_and_questions})
  128. * has ended processing the whole xml structure. Its name is:
  129. * "after_execute_" + connectionpoint ("question")
  130. *
  131. * For match qtype we use it to restore the subquestions column,
  132. * containing one list of question_match_sub ids
  133. */
  134. public function after_execute_question() {
  135. global $DB;
  136. // Now that all the question_match_subs have been restored, let's process
  137. // the created question_match subquestions (list of question_match_sub ids)
  138. $rs = $DB->get_recordset_sql(
  139. "SELECT qm.id, qm.subquestions
  140. FROM {question_match} qm
  141. JOIN {backup_ids_temp} bi ON bi.newitemid = qm.question
  142. WHERE bi.backupid = ?
  143. AND bi.itemname = 'question_created'", array($this->get_restoreid()));
  144. foreach ($rs as $rec) {
  145. $subquestionsarr = explode(',', $rec->subquestions);
  146. foreach ($subquestionsarr as $key => $subquestion) {
  147. $subquestionsarr[$key] = $this->get_mappingid(
  148. 'question_match_sub', $subquestion);
  149. }
  150. $subquestions = implode(',', $subquestionsarr);
  151. $DB->set_field('question_match', 'subquestions', $subquestions,
  152. array('id' => $rec->id));
  153. }
  154. $rs->close();
  155. }
  156. public function recode_response($questionid, $sequencenumber, array $response) {
  157. if (array_key_exists('_stemorder', $response)) {
  158. $response['_stemorder'] = $this->recode_match_sub_order($response['_stemorder']);
  159. }
  160. if (array_key_exists('_choiceorder', $response)) {
  161. $response['_choiceorder'] = $this->recode_match_sub_order($response['_choiceorder']);
  162. }
  163. return $response;
  164. }
  165. /**
  166. * Given one question_states record, return the answer
  167. * recoded pointing to all the restored stuff for match questions
  168. *
  169. * answer is one comma separated list of hypen separated pairs
  170. * containing question_match_sub->id and question_match_sub->code
  171. */
  172. public function recode_legacy_state_answer($state) {
  173. $answer = $state->answer;
  174. $resultarr = array();
  175. foreach (explode(',', $answer) as $pair) {
  176. $pairarr = explode('-', $pair);
  177. $id = $pairarr[0];
  178. $code = $pairarr[1];
  179. $newid = $this->get_mappingid('question_match_sub', $id);
  180. $resultarr[] = implode('-', array($newid, $code));
  181. }
  182. return implode(',', $resultarr);
  183. }
  184. /**
  185. * Recode the choice order as stored in the response.
  186. * @param string $order the original order.
  187. * @return string the recoded order.
  188. */
  189. protected function recode_match_sub_order($order) {
  190. $neworder = array();
  191. foreach (explode(',', $order) as $id) {
  192. if ($newid = $this->get_mappingid('question_match_sub', $id)) {
  193. $neworder[] = $newid;
  194. }
  195. }
  196. return implode(',', $neworder);
  197. }
  198. /**
  199. * Return the contents of this qtype to be processed by the links decoder
  200. */
  201. public static function define_decode_contents() {
  202. $contents = array();
  203. $contents[] = new restore_decode_content('question_match_sub',
  204. array('questiontext'), 'question_match_sub');
  205. $fields = array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback');
  206. $contents[] = new restore_decode_content('question_match', $fields, 'question_match');
  207. return $contents;
  208. }
  209. }