PageRenderTime 94ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/admin/tool/qeupgradehelper/locallib.php

https://bitbucket.org/kudutest1/moodlegit
PHP | 673 lines | 469 code | 82 blank | 122 comment | 25 complexity | e55438c4eea823e8e394a6f936b79656 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. * Question engine upgrade helper library code.
  18. *
  19. * @package tool
  20. * @subpackage qeupgradehelper
  21. * @copyright 2010 The Open University
  22. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23. */
  24. defined('MOODLE_INTERNAL') || die();
  25. /**
  26. * Detect whether this site has been upgraded to the new question engine yet.
  27. * @return bool whether the site has been upgraded.
  28. */
  29. function tool_qeupgradehelper_is_upgraded() {
  30. global $CFG, $DB;
  31. $dbman = $DB->get_manager();
  32. return is_readable($CFG->dirroot . '/question/engine/upgrade/upgradelib.php') &&
  33. $dbman->table_exists('question_usages');
  34. }
  35. /**
  36. * If the site has not yet been upgraded, display an error.
  37. */
  38. function tool_qeupgradehelper_require_upgraded() {
  39. if (!tool_qeupgradehelper_is_upgraded()) {
  40. throw new moodle_exception('upgradedsiterequired', 'tool_qeupgradehelper',
  41. tool_qeupgradehelper_url('index'));
  42. }
  43. }
  44. /**
  45. * If the site has been upgraded, display an error.
  46. */
  47. function tool_qeupgradehelper_require_not_upgraded() {
  48. if (tool_qeupgradehelper_is_upgraded()) {
  49. throw new moodle_exception('notupgradedsiterequired', 'tool_qeupgradehelper',
  50. tool_qeupgradehelper_url('index'));
  51. }
  52. }
  53. /**
  54. * Get the URL of a script within this plugin.
  55. * @param string $script the script name, without .php. E.g. 'index'.
  56. * @param array $params URL parameters (optional).
  57. */
  58. function tool_qeupgradehelper_url($script, $params = array()) {
  59. return new moodle_url('/admin/tool/qeupgradehelper/' . $script . '.php', $params);
  60. }
  61. /**
  62. * Class to encapsulate one of the functionalities that this plugin offers.
  63. *
  64. * @copyright 2010 The Open University
  65. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  66. */
  67. class tool_qeupgradehelper_action {
  68. /** @var string the name of this action. */
  69. public $name;
  70. /** @var moodle_url the URL to launch this action. */
  71. public $url;
  72. /** @var string a description of this aciton. */
  73. public $description;
  74. /**
  75. * Constructor to set the fields.
  76. */
  77. protected function __construct($name, moodle_url $url, $description) {
  78. $this->name = $name;
  79. $this->url = $url;
  80. $this->description = $description;
  81. }
  82. /**
  83. * Make an action with standard values.
  84. * @param string $shortname internal name of the action. Used to get strings
  85. * and build a URL.
  86. * @param array $params any URL params required.
  87. */
  88. public static function make($shortname, $params = array()) {
  89. return new self(
  90. get_string($shortname, 'tool_qeupgradehelper'),
  91. tool_qeupgradehelper_url($shortname, $params),
  92. get_string($shortname . '_desc', 'tool_qeupgradehelper'));
  93. }
  94. }
  95. /**
  96. * A class to represent a list of quizzes with various information about
  97. * attempts that can be displayed as a table.
  98. *
  99. * @copyright 2010 The Open University
  100. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  101. */
  102. abstract class tool_qeupgradehelper_quiz_list {
  103. public $title;
  104. public $intro;
  105. public $quizacolheader;
  106. public $sql;
  107. public $quizlist = null;
  108. public $totalquizas = 0;
  109. public $totalqas = 0;
  110. protected function __construct($title, $intro, $quizacolheader) {
  111. global $DB;
  112. $this->title = get_string($title, 'tool_qeupgradehelper');
  113. $this->intro = get_string($intro, 'tool_qeupgradehelper');
  114. $this->quizacolheader = get_string($quizacolheader, 'tool_qeupgradehelper');
  115. $this->build_sql();
  116. $this->quizlist = $DB->get_records_sql($this->sql);
  117. }
  118. protected function build_sql() {
  119. $this->sql = '
  120. SELECT
  121. quiz.id,
  122. quiz.name,
  123. c.shortname,
  124. c.id AS courseid,
  125. COUNT(1) AS attemptcount,
  126. SUM(qsesscounts.num) AS questionattempts
  127. FROM {quiz_attempts} quiza
  128. JOIN {quiz} quiz ON quiz.id = quiza.quiz
  129. JOIN {course} c ON c.id = quiz.course
  130. LEFT JOIN (
  131. SELECT attemptid, COUNT(1) AS num
  132. FROM {question_sessions}
  133. GROUP BY attemptid
  134. ) qsesscounts ON qsesscounts.attemptid = quiza.uniqueid
  135. WHERE quiza.preview = 0
  136. ' . $this->extra_where_clause() . '
  137. GROUP BY quiz.id, quiz.name, c.shortname, c.id
  138. ORDER BY c.shortname, quiz.name, quiz.id';
  139. }
  140. abstract protected function extra_where_clause();
  141. public function get_col_headings() {
  142. return array(
  143. get_string('quizid', 'tool_qeupgradehelper'),
  144. get_string('course'),
  145. get_string('pluginname', 'quiz'),
  146. $this->quizacolheader,
  147. get_string('questionsessions', 'tool_qeupgradehelper'),
  148. );
  149. }
  150. public function get_row($quizinfo) {
  151. $this->totalquizas += $quizinfo->attemptcount;
  152. $this->totalqas += $quizinfo->questionattempts;
  153. return array(
  154. $quizinfo->id,
  155. html_writer::link(new moodle_url('/course/view.php',
  156. array('id' => $quizinfo->courseid)), format_string($quizinfo->shortname)),
  157. html_writer::link(new moodle_url('/mod/quiz/view.php',
  158. array('q' => $quizinfo->id)), format_string($quizinfo->name)),
  159. $quizinfo->attemptcount,
  160. $quizinfo->questionattempts ? $quizinfo->questionattempts : 0,
  161. );
  162. }
  163. public function get_row_class($quizinfo) {
  164. return null;
  165. }
  166. public function get_total_row() {
  167. return array(
  168. '',
  169. html_writer::tag('b', get_string('total')),
  170. '',
  171. html_writer::tag('b', $this->totalquizas),
  172. html_writer::tag('b', $this->totalqas),
  173. );
  174. }
  175. public function is_empty() {
  176. return empty($this->quizlist);
  177. }
  178. }
  179. /**
  180. * A list of quizzes that still need to be upgraded after the main upgrade.
  181. *
  182. * @copyright 2010 The Open University
  183. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  184. */
  185. class tool_qeupgradehelper_upgradable_quiz_list extends tool_qeupgradehelper_quiz_list {
  186. public function __construct() {
  187. parent::__construct('quizzeswithunconverted', 'listtodointro', 'attemptstoconvert');
  188. }
  189. protected function extra_where_clause() {
  190. return 'AND quiza.needsupgradetonewqe = 1';
  191. }
  192. public function get_col_headings() {
  193. $headings = parent::get_col_headings();
  194. $headings[] = get_string('action', 'tool_qeupgradehelper');
  195. return $headings;
  196. }
  197. public function get_row($quizinfo) {
  198. $row = parent::get_row($quizinfo);
  199. $row[] = html_writer::link(tool_qeupgradehelper_url('convertquiz', array('quizid' => $quizinfo->id)),
  200. get_string('convertquiz', 'tool_qeupgradehelper'));
  201. return $row;
  202. }
  203. }
  204. /**
  205. * A list of quizzes that still need to be upgraded after the main upgrade.
  206. *
  207. * @copyright 2010 The Open University
  208. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  209. */
  210. class tool_qeupgradehelper_resettable_quiz_list extends tool_qeupgradehelper_quiz_list {
  211. public function __construct() {
  212. parent::__construct('quizzesthatcanbereset', 'listupgradedintro', 'convertedattempts');
  213. }
  214. protected function extra_where_clause() {
  215. return 'AND quiza.needsupgradetonewqe = 0
  216. AND EXISTS(SELECT 1 FROM {question_states}
  217. WHERE attempt = quiza.uniqueid)';
  218. }
  219. public function get_col_headings() {
  220. $headings = parent::get_col_headings();
  221. $headings[] = get_string('action', 'tool_qeupgradehelper');
  222. return $headings;
  223. }
  224. public function get_row($quizinfo) {
  225. $row = parent::get_row($quizinfo);
  226. $row[] = html_writer::link(tool_qeupgradehelper_url('resetquiz', array('quizid' => $quizinfo->id)),
  227. get_string('resetquiz', 'tool_qeupgradehelper'));
  228. return $row;
  229. }
  230. }
  231. /**
  232. * A list of quizzes that will be upgraded during the main upgrade.
  233. *
  234. * @copyright 2010 The Open University
  235. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  236. */
  237. class tool_qeupgradehelper_pre_upgrade_quiz_list extends tool_qeupgradehelper_quiz_list {
  238. public function __construct() {
  239. parent::__construct('quizzestobeupgraded', 'listpreupgradeintro', 'numberofattempts');
  240. }
  241. protected function extra_where_clause() {
  242. return '';
  243. }
  244. }
  245. /**
  246. * A list of quizzes that will be upgraded during the main upgrade, when the
  247. * partialupgrade.php script is being used.
  248. *
  249. * @copyright 2011 The Open University
  250. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  251. */
  252. class tool_qeupgradehelper_pre_upgrade_quiz_list_restricted extends tool_qeupgradehelper_pre_upgrade_quiz_list {
  253. protected $quizids;
  254. protected $restrictedtotalquizas = 0;
  255. protected $restrictedtotalqas = 0;
  256. public function __construct($quizids) {
  257. parent::__construct();
  258. $this->quizids = $quizids;
  259. }
  260. public function get_row_class($quizinfo) {
  261. if (!in_array($quizinfo->id, $this->quizids)) {
  262. return 'dimmed';
  263. } else {
  264. return parent::get_row_class($quizinfo);
  265. }
  266. }
  267. public function get_col_headings() {
  268. $headings = parent::get_col_headings();
  269. $headings[] = get_string('includedintheupgrade', 'tool_qeupgradehelper');
  270. return $headings;
  271. }
  272. public function get_row($quizinfo) {
  273. $row = parent::get_row($quizinfo);
  274. if (in_array($quizinfo->id, $this->quizids)) {
  275. $this->restrictedtotalquizas += $quizinfo->attemptcount;
  276. $this->restrictedtotalqas += $quizinfo->questionattempts;
  277. $row[] = get_string('yes');
  278. } else {
  279. $row[] = get_string('no');
  280. }
  281. return $row;
  282. }
  283. protected function out_of($restrictedtotal, $fulltotal) {
  284. $a = new stdClass();
  285. $a->some = $a->some = html_writer::tag('b', $restrictedtotal);
  286. $a->total = $fulltotal;
  287. return get_string('outof', 'tool_qeupgradehelper', $a);
  288. }
  289. public function get_total_row() {
  290. return array(
  291. '',
  292. html_writer::tag('b', get_string('total')),
  293. '',
  294. $this->out_of($this->restrictedtotalquizas, $this->totalquizas),
  295. $this->out_of($this->restrictedtotalqas, $this->totalqas),
  296. );
  297. }
  298. }
  299. /**
  300. * List the number of quiz attempts that were never upgraded from 1.4 -> 1.5.
  301. * @return int the number of such attempts.
  302. */
  303. function tool_qeupgradehelper_get_num_very_old_attempts() {
  304. global $DB;
  305. return $DB->count_records_sql('
  306. SELECT COUNT(1)
  307. FROM {quiz_attempts} quiza
  308. WHERE uniqueid IN (
  309. SELECT DISTINCT qst.attempt
  310. FROM {question_states} qst
  311. LEFT JOIN {question_sessions} qsess ON
  312. qst.question = qsess.questionid AND qst.attempt = qsess.attemptid
  313. WHERE qsess.id IS NULL)');
  314. }
  315. /**
  316. * Get the information about a quiz to be upgraded.
  317. * @param integer $quizid the quiz id.
  318. * @return object the information about that quiz, as for
  319. * {@link tool_qeupgradehelper_get_upgradable_quizzes()}.
  320. */
  321. function tool_qeupgradehelper_get_quiz($quizid) {
  322. global $DB;
  323. return $DB->get_record_sql("
  324. SELECT
  325. quiz.id,
  326. quiz.name,
  327. c.shortname,
  328. c.id AS courseid,
  329. COUNT(1) AS numtoconvert
  330. FROM {quiz_attempts} quiza
  331. JOIN {quiz} quiz ON quiz.id = quiza.quiz
  332. JOIN {course} c ON c.id = quiz.course
  333. WHERE quiza.preview = 0
  334. AND quiza.needsupgradetonewqe = 1
  335. AND quiz.id = ?
  336. GROUP BY quiz.id, quiz.name, c.shortname, c.id
  337. ORDER BY c.shortname, quiz.name, quiz.id", array($quizid));
  338. }
  339. /**
  340. * Get the information about a quiz to be upgraded.
  341. * @param integer $quizid the quiz id.
  342. * @return object the information about that quiz, as for
  343. * {@link tool_qeupgradehelper_get_resettable_quizzes()}, but with extra fields
  344. * totalattempts and resettableattempts.
  345. */
  346. function tool_qeupgradehelper_get_resettable_quiz($quizid) {
  347. global $DB;
  348. return $DB->get_record_sql("
  349. SELECT
  350. quiz.id,
  351. quiz.name,
  352. c.shortname,
  353. c.id AS courseid,
  354. COUNT(1) AS totalattempts,
  355. SUM(CASE WHEN quiza.needsupgradetonewqe = 0 AND
  356. oldtimemodified.time IS NOT NULL THEN 1 ELSE 0 END) AS convertedattempts,
  357. SUM(CASE WHEN quiza.needsupgradetonewqe = 0 AND
  358. newtimemodified.time IS NULL OR oldtimemodified.time >= newtimemodified.time
  359. THEN 1 ELSE 0 END) AS resettableattempts
  360. FROM {quiz_attempts} quiza
  361. JOIN {quiz} quiz ON quiz.id = quiza.quiz
  362. JOIN {course} c ON c.id = quiz.course
  363. LEFT JOIN (
  364. SELECT attempt, MAX(timestamp) AS time
  365. FROM {question_states}
  366. GROUP BY attempt
  367. ) AS oldtimemodified ON oldtimemodified.attempt = quiza.uniqueid
  368. LEFT JOIN (
  369. SELECT qa.questionusageid, MAX(qas.timecreated) AS time
  370. FROM {question_attempts} qa
  371. JOIN {question_attempt_steps} qas ON qas.questionattemptid = qa.id
  372. GROUP BY qa.questionusageid
  373. ) AS newtimemodified ON newtimemodified.questionusageid = quiza.uniqueid
  374. WHERE quiza.preview = 0
  375. AND quiz.id = ?
  376. GROUP BY quiz.id, quiz.name, c.shortname, c.id", array($quizid));
  377. }
  378. /**
  379. * Get a question session id form a quiz attempt id and a question id.
  380. * @param int $attemptid a quiz attempt id.
  381. * @param int $questionid a question id.
  382. * @return int the question session id.
  383. */
  384. function tool_qeupgradehelper_get_session_id($attemptid, $questionid) {
  385. global $DB;
  386. $attempt = $DB->get_record('quiz_attempts', array('id' => $attemptid));
  387. if (!$attempt) {
  388. return null;
  389. }
  390. return $DB->get_field('question_sessions', 'id',
  391. array('attemptid' => $attempt->uniqueid, 'questionid' => $questionid));
  392. }
  393. /**
  394. * Identify the question session id of a question attempt matching certain
  395. * requirements.
  396. * @param integer $behaviour 0 = deferred feedback, 1 = interactive.
  397. * @param string $statehistory of states, last first. E.g. 620.
  398. * @param string $qtype question type.
  399. * @return integer question_session.id.
  400. */
  401. function tool_qeupgradehelper_find_test_case($behaviour, $statehistory, $qtype, $extratests) {
  402. global $DB;
  403. $params = array(
  404. 'qtype' => $qtype,
  405. 'statehistory' => $statehistory
  406. );
  407. if ($behaviour == 'deferredfeedback') {
  408. $extrawhere = '';
  409. $params['optionflags'] = 0;
  410. } else if ($behaviour == 'adaptive') {
  411. $extrawhere = 'AND penaltyscheme = :penaltyscheme';
  412. $params['optionflags'] = 0;
  413. $params['penaltyscheme'] = 0;
  414. } else {
  415. $extrawhere = 'AND penaltyscheme = :penaltyscheme';
  416. $params['optionflags'] = 0;
  417. $params['penaltyscheme'] = 1;
  418. }
  419. $possibleids = $DB->get_records_sql_menu('
  420. SELECT
  421. qsess.id,
  422. 1
  423. FROM {question_sessions} qsess
  424. JOIN {question_states} qst ON qst.attempt = qsess.attemptid
  425. AND qst.question = qsess.questionid
  426. JOIN {quiz_attempts} quiza ON quiza.uniqueid = qsess.attemptid
  427. JOIN {quiz} quiz ON quiz.id = quiza.quiz
  428. JOIN {question} q ON q.id = qsess.questionid
  429. WHERE q.qtype = :qtype
  430. AND quiz.optionflags = :optionflags
  431. ' . $extrawhere . '
  432. GROUP BY
  433. qsess.id
  434. HAVING SUM(
  435. (CASE WHEN qst.event = 10 THEN 1 ELSE qst.event END) *
  436. POWER(10, CAST(qst.seq_number AS NUMERIC(110,0)))
  437. ) = :statehistory' . $extratests, $params, 0, 100);
  438. if (!$possibleids) {
  439. return null;
  440. }
  441. return array_rand($possibleids);
  442. }
  443. /**
  444. * Grab all the data that upgrade will need for upgrading one
  445. * attempt at one question from the old DB.
  446. */
  447. function tool_qeupgradehelper_generate_unit_test($questionsessionid, $namesuffix) {
  448. global $DB;
  449. $qsession = $DB->get_record('question_sessions', array('id' => $questionsessionid));
  450. $attempt = $DB->get_record('quiz_attempts', array('uniqueid' => $qsession->attemptid));
  451. $quiz = $DB->get_record('quiz', array('id' => $attempt->quiz));
  452. $qstates = $DB->get_records('question_states',
  453. array('attempt' => $qsession->attemptid, 'question' => $qsession->questionid),
  454. 'seq_number, id');
  455. $question = tool_qeupgradehelper_load_question($qsession->questionid, $quiz->id);
  456. if (!tool_qeupgradehelper_is_upgraded()) {
  457. if (!$quiz->optionflags) {
  458. $quiz->preferredbehaviour = 'deferredfeedback';
  459. } else if ($quiz->penaltyscheme) {
  460. $quiz->preferredbehaviour = 'adaptive';
  461. } else {
  462. $quiz->preferredbehaviour = 'adaptivenopenalty';
  463. }
  464. unset($quiz->optionflags);
  465. unset($quiz->penaltyscheme);
  466. $question->defaultmark = $question->defaultgrade;
  467. unset($question->defaultgrade);
  468. }
  469. $attempt->needsupgradetonewqe = 1;
  470. echo '<textarea readonly="readonly" rows="80" cols="120" >' . "
  471. public function test_{$question->qtype}_{$quiz->preferredbehaviour}_{$namesuffix}() {
  472. ";
  473. tool_qeupgradehelper_display_convert_attempt_input($quiz, $attempt,
  474. $question, $qsession, $qstates);
  475. if ($question->qtype == 'random') {
  476. list($randombit, $realanswer) = explode('-', reset($qstates)->answer, 2);
  477. $newquestionid = substr($randombit, 6);
  478. $newquestion = tool_qeupgradehelper_load_question($newquestionid);
  479. $newquestion->maxmark = $question->maxmark;
  480. echo tool_qeupgradehelper_format_var('$realquestion', $newquestion);
  481. echo ' $this->loader->put_question_in_cache($realquestion);
  482. ';
  483. }
  484. echo '
  485. $qa = $this->updater->convert_question_attempt($quiz, $attempt, $question, $qsession, $qstates);
  486. $expectedqa = (object) array(';
  487. echo "
  488. 'behaviour' => '{$quiz->preferredbehaviour}',
  489. 'questionid' => {$question->id},
  490. 'variant' => 1,
  491. 'maxmark' => {$question->maxmark},
  492. 'minfraction' => 0,
  493. 'flagged' => 0,
  494. 'questionsummary' => '',
  495. 'rightanswer' => '',
  496. 'responsesummary' => '',
  497. 'timemodified' => 0,
  498. 'steps' => array(";
  499. foreach ($qstates as $state) {
  500. echo "
  501. {$state->seq_number} => (object) array(
  502. 'sequencenumber' => {$state->seq_number},
  503. 'state' => '',
  504. 'fraction' => null,
  505. 'timecreated' => {$state->timestamp},
  506. 'userid' => {$attempt->userid},
  507. 'data' => array(),
  508. ),";
  509. }
  510. echo '
  511. ),
  512. );
  513. $this->compare_qas($expectedqa, $qa);
  514. }
  515. </textarea>';
  516. }
  517. function tool_qeupgradehelper_format_var($name, $var) {
  518. $out = var_export($var, true);
  519. $out = str_replace('<', '&lt;', $out);
  520. $out = str_replace('ADOFetchObj::__set_state(array(', '(object) array(', $out);
  521. $out = str_replace('stdClass::__set_state(array(', '(object) array(', $out);
  522. $out = str_replace('array (', 'array(', $out);
  523. $out = preg_replace('/=> \n\s*/', '=> ', $out);
  524. $out = str_replace(')),', '),', $out);
  525. $out = str_replace('))', ')', $out);
  526. $out = preg_replace('/\n (?! )/', "\n ", $out);
  527. $out = preg_replace('/\n (?! )/', "\n ", $out);
  528. $out = preg_replace('/\n (?! )/', "\n ", $out);
  529. $out = preg_replace('/\n (?! )/', "\n ", $out);
  530. $out = preg_replace('/\n (?! )/', "\n ", $out);
  531. $out = preg_replace('/\n (?! )/', "\n ", $out);
  532. $out = preg_replace('/\n (?! )/', "\n ", $out);
  533. $out = preg_replace('/\n (?! )/', "\n ", $out);
  534. $out = preg_replace('/\n (?! )/', "\n ", $out);
  535. $out = preg_replace('/\n (?! )/', "\n ", $out);
  536. $out = preg_replace('/\n (?! )/', "\n ", $out);
  537. $out = preg_replace('/\n (?! )/', "\n ", $out);
  538. $out = preg_replace('/\n(?! )/', "\n ", $out);
  539. $out = preg_replace('/\bNULL\b/', 'null', $out);
  540. return " $name = $out;\n";
  541. }
  542. function tool_qeupgradehelper_display_convert_attempt_input($quiz, $attempt,
  543. $question, $qsession, $qstates) {
  544. echo tool_qeupgradehelper_format_var('$quiz', $quiz);
  545. echo tool_qeupgradehelper_format_var('$attempt', $attempt);
  546. echo tool_qeupgradehelper_format_var('$question', $question);
  547. echo tool_qeupgradehelper_format_var('$qsession', $qsession);
  548. echo tool_qeupgradehelper_format_var('$qstates', $qstates);
  549. }
  550. function tool_qeupgradehelper_load_question($questionid, $quizid) {
  551. global $CFG, $DB;
  552. $question = $DB->get_record_sql('
  553. SELECT q.*, qqi.grade AS maxmark
  554. FROM {question} q
  555. JOIN {quiz_question_instances} qqi ON qqi.question = q.id
  556. WHERE q.id = :questionid AND qqi.quiz = :quizid',
  557. array('questionid' => $questionid, 'quizid' => $quizid));
  558. if (tool_qeupgradehelper_is_upgraded()) {
  559. require_once($CFG->dirroot . '/question/engine/bank.php');
  560. $qtype = question_bank::get_qtype($question->qtype, false);
  561. } else {
  562. global $QTYPES;
  563. if (!array_key_exists($question->qtype, $QTYPES)) {
  564. $question->qtype = 'missingtype';
  565. $question->questiontext = '<p>' . get_string('warningmissingtype', 'quiz') . '</p>' . $question->questiontext;
  566. }
  567. $qtype = $QTYPES[$question->qtype];
  568. }
  569. $qtype->get_question_options($question);
  570. return $question;
  571. }
  572. function tool_qeupgradehelper_get_quiz_for_upgrade() {
  573. global $DB;
  574. return $DB->get_record_sql("SELECT quiz.id
  575. FROM {quiz_attempts} quiza
  576. JOIN {quiz} quiz ON quiz.id = quiza.quiz
  577. JOIN {course} c ON c.id = quiz.course
  578. WHERE quiza.preview = 0 AND quiza.needsupgradetonewqe = 1
  579. GROUP BY quiz.id, quiz.name, c.shortname, c.id
  580. ORDER BY MAX(quiza.timemodified) DESC", array(), IGNORE_MULTIPLE);
  581. }