Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/admin/tool/qeupgradehelper/locallib.php
Go to the documentation of this file.
00001 <?php
00002 // This file is part of Moodle - http://moodle.org/
00003 //
00004 // Moodle is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU General Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // Moodle is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00016 
00027 defined('MOODLE_INTERNAL') || die();
00028 
00029 
00034 function tool_qeupgradehelper_is_upgraded() {
00035     global $CFG, $DB;
00036     $dbman = $DB->get_manager();
00037     return is_readable($CFG->dirroot . '/question/engine/upgrade/upgradelib.php') &&
00038             $dbman->table_exists('question_usages');
00039 }
00040 
00044 function tool_qeupgradehelper_require_upgraded() {
00045     if (!tool_qeupgradehelper_is_upgraded()) {
00046         throw new moodle_exception('upgradedsiterequired', 'tool_qeupgradehelper',
00047                 tool_qeupgradehelper_url('index'));
00048     }
00049 }
00050 
00054 function tool_qeupgradehelper_require_not_upgraded() {
00055     if (tool_qeupgradehelper_is_upgraded()) {
00056         throw new moodle_exception('notupgradedsiterequired', 'tool_qeupgradehelper',
00057                 tool_qeupgradehelper_url('index'));
00058     }
00059 }
00060 
00066 function tool_qeupgradehelper_url($script, $params = array()) {
00067     return new moodle_url('/admin/tool/qeupgradehelper/' . $script . '.php', $params);
00068 }
00069 
00070 
00077 class tool_qeupgradehelper_action {
00079     public $name;
00081     public $url;
00083     public $description;
00084 
00088     protected function __construct($name, moodle_url $url, $description) {
00089         $this->name = $name;
00090         $this->url = $url;
00091         $this->description = $description;
00092     }
00093 
00100     public static function make($shortname, $params = array()) {
00101         return new self(
00102                 get_string($shortname, 'tool_qeupgradehelper'),
00103                 tool_qeupgradehelper_url($shortname, $params),
00104                 get_string($shortname . '_desc', 'tool_qeupgradehelper'));
00105     }
00106 }
00107 
00108 
00116 abstract class tool_qeupgradehelper_quiz_list {
00117     public $title;
00118     public $intro;
00119     public $quizacolheader;
00120     public $sql;
00121     public $quizlist = null;
00122     public $totalquizas = 0;
00123     public $totalqas = 0;
00124 
00125     protected function __construct($title, $intro, $quizacolheader) {
00126         global $DB;
00127         $this->title = get_string($title, 'tool_qeupgradehelper');
00128         $this->intro = get_string($intro, 'tool_qeupgradehelper');
00129         $this->quizacolheader = get_string($quizacolheader, 'tool_qeupgradehelper');
00130         $this->build_sql();
00131         $this->quizlist = $DB->get_records_sql($this->sql);
00132     }
00133 
00134     protected function build_sql() {
00135         $this->sql = '
00136             SELECT
00137                 quiz.id,
00138                 quiz.name,
00139                 c.shortname,
00140                 c.id AS courseid,
00141                 COUNT(1) AS attemptcount,
00142                 SUM(qsesscounts.num) AS questionattempts
00143 
00144             FROM {quiz_attempts} quiza
00145             JOIN {quiz} quiz ON quiz.id = quiza.quiz
00146             JOIN {course} c ON c.id = quiz.course
00147             LEFT JOIN (
00148                 SELECT attemptid, COUNT(1) AS num
00149                 FROM {question_sessions}
00150                 GROUP BY attemptid
00151             ) qsesscounts ON qsesscounts.attemptid = quiza.uniqueid
00152 
00153             WHERE quiza.preview = 0
00154                 ' . $this->extra_where_clause() . '
00155 
00156             GROUP BY quiz.id, quiz.name, c.shortname, c.id
00157 
00158             ORDER BY c.shortname, quiz.name, quiz.id';
00159     }
00160 
00161     abstract protected function extra_where_clause();
00162 
00163     public function get_col_headings() {
00164         return array(
00165             get_string('quizid', 'tool_qeupgradehelper'),
00166             get_string('course'),
00167             get_string('pluginname', 'quiz'),
00168             $this->quizacolheader,
00169             get_string('questionsessions', 'tool_qeupgradehelper'),
00170         );
00171     }
00172 
00173     public function get_row($quizinfo) {
00174         $this->totalquizas += $quizinfo->attemptcount;
00175         $this->totalqas += $quizinfo->questionattempts;
00176         return array(
00177             $quizinfo->id,
00178             html_writer::link(new moodle_url('/course/view.php',
00179                     array('id' => $quizinfo->courseid)), format_string($quizinfo->shortname)),
00180             html_writer::link(new moodle_url('/mod/quiz/view.php',
00181                     array('q' => $quizinfo->id)), format_string($quizinfo->name)),
00182             $quizinfo->attemptcount,
00183             $quizinfo->questionattempts ? $quizinfo->questionattempts : 0,
00184         );
00185     }
00186 
00187     public function get_row_class($quizinfo) {
00188         return null;
00189     }
00190 
00191     public function get_total_row() {
00192         return array(
00193             '',
00194             html_writer::tag('b', get_string('total')),
00195             '',
00196             html_writer::tag('b', $this->totalquizas),
00197             html_writer::tag('b', $this->totalqas),
00198         );
00199     }
00200 
00201     public function is_empty() {
00202         return empty($this->quizlist);
00203     }
00204 }
00205 
00206 
00213 class tool_qeupgradehelper_upgradable_quiz_list extends tool_qeupgradehelper_quiz_list {
00214     public function __construct() {
00215         parent::__construct('quizzeswithunconverted', 'listtodointro', 'attemptstoconvert');
00216     }
00217 
00218     protected function extra_where_clause() {
00219         return 'AND quiza.needsupgradetonewqe = 1';
00220     }
00221 
00222     public function get_col_headings() {
00223         $headings = parent::get_col_headings();
00224         $headings[] = get_string('action', 'tool_qeupgradehelper');
00225         return $headings;
00226     }
00227 
00228     public function get_row($quizinfo) {
00229         $row = parent::get_row($quizinfo);
00230         $row[] = html_writer::link(tool_qeupgradehelper_url('convertquiz', array('quizid' => $quizinfo->id)),
00231                         get_string('convertquiz', 'tool_qeupgradehelper'));
00232         return $row;
00233     }
00234 }
00235 
00236 
00243 class tool_qeupgradehelper_resettable_quiz_list extends tool_qeupgradehelper_quiz_list {
00244     public function __construct() {
00245         parent::__construct('quizzesthatcanbereset', 'listupgradedintro', 'convertedattempts');
00246     }
00247 
00248     protected function extra_where_clause() {
00249         return 'AND quiza.needsupgradetonewqe = 0
00250               AND EXISTS(SELECT 1 FROM {question_states}
00251                     WHERE attempt = quiza.uniqueid)';
00252     }
00253 
00254     public function get_col_headings() {
00255         $headings = parent::get_col_headings();
00256         $headings[] = get_string('action', 'tool_qeupgradehelper');
00257         return $headings;
00258     }
00259 
00260     public function get_row($quizinfo) {
00261         $row = parent::get_row($quizinfo);
00262         $row[] = html_writer::link(tool_qeupgradehelper_url('resetquiz', array('quizid' => $quizinfo->id)),
00263                         get_string('resetquiz', 'tool_qeupgradehelper'));
00264         return $row;
00265     }
00266 }
00267 
00268 
00275 class tool_qeupgradehelper_pre_upgrade_quiz_list extends tool_qeupgradehelper_quiz_list {
00276     public function __construct() {
00277         parent::__construct('quizzestobeupgraded', 'listpreupgradeintro', 'numberofattempts');
00278     }
00279 
00280     protected function extra_where_clause() {
00281         return '';
00282     }
00283 }
00284 
00285 
00293 class tool_qeupgradehelper_pre_upgrade_quiz_list_restricted extends tool_qeupgradehelper_pre_upgrade_quiz_list {
00294     protected $quizids;
00295     protected $restrictedtotalquizas = 0;
00296     protected $restrictedtotalqas = 0;
00297 
00298     public function __construct($quizids) {
00299         parent::__construct();
00300         $this->quizids = $quizids;
00301     }
00302 
00303     public function get_row_class($quizinfo) {
00304         if (!in_array($quizinfo->id, $this->quizids)) {
00305             return 'dimmed';
00306         } else {
00307             return parent::get_row_class($quizinfo);
00308         }
00309     }
00310 
00311     public function get_col_headings() {
00312         $headings = parent::get_col_headings();
00313         $headings[] = get_string('includedintheupgrade', 'tool_qeupgradehelper');
00314         return $headings;
00315     }
00316 
00317     public function get_row($quizinfo) {
00318         $row = parent::get_row($quizinfo);
00319         if (in_array($quizinfo->id, $this->quizids)) {
00320             $this->restrictedtotalquizas += $quizinfo->attemptcount;
00321             $this->restrictedtotalqas += $quizinfo->questionattempts;
00322             $row[] = get_string('yes');
00323         } else {
00324             $row[] = get_string('no');
00325         }
00326         return $row;
00327     }
00328 
00329     protected function out_of($restrictedtotal, $fulltotal) {
00330         $a = new stdClass();
00331         $a->some = $a->some = html_writer::tag('b', $restrictedtotal);
00332         $a->total = $fulltotal;
00333         return get_string('outof', 'tool_qeupgradehelper', $a);
00334     }
00335 
00336     public function get_total_row() {
00337         return array(
00338             '',
00339             html_writer::tag('b', get_string('total')),
00340             '',
00341             $this->out_of($this->restrictedtotalquizas, $this->totalquizas),
00342             $this->out_of($this->restrictedtotalqas, $this->totalqas),
00343         );
00344     }
00345 }
00346 
00347 
00352 function tool_qeupgradehelper_get_num_very_old_attempts() {
00353     global $DB;
00354     return $DB->count_records_sql('
00355             SELECT COUNT(1)
00356               FROM {quiz_attempts} quiza
00357              WHERE uniqueid IN (
00358                 SELECT DISTINCT qst.attempt
00359                   FROM {question_states} qst
00360                   LEFT JOIN {question_sessions} qsess ON
00361                         qst.question = qsess.questionid AND qst.attempt = qsess.attemptid
00362                  WHERE qsess.id IS NULL)');
00363 }
00364 
00371 function tool_qeupgradehelper_get_quiz($quizid) {
00372     global $DB;
00373     return $DB->get_record_sql("
00374             SELECT
00375                 quiz.id,
00376                 quiz.name,
00377                 c.shortname,
00378                 c.id AS courseid,
00379                 COUNT(1) AS numtoconvert
00380 
00381             FROM {quiz_attempts} quiza
00382             JOIN {quiz} quiz ON quiz.id = quiza.quiz
00383             JOIN {course} c ON c.id = quiz.course
00384 
00385             WHERE quiza.preview = 0
00386               AND quiza.needsupgradetonewqe = 1
00387               AND quiz.id = ?
00388 
00389             GROUP BY quiz.id, quiz.name, c.shortname, c.id
00390 
00391             ORDER BY c.shortname, quiz.name, quiz.id", array($quizid));
00392 }
00393 
00401 function tool_qeupgradehelper_get_resettable_quiz($quizid) {
00402     global $DB;
00403     return $DB->get_record_sql("
00404             SELECT
00405                 quiz.id,
00406                 quiz.name,
00407                 c.shortname,
00408                 c.id AS courseid,
00409                 COUNT(1) AS totalattempts,
00410                 SUM(CASE WHEN quiza.needsupgradetonewqe = 0 AND
00411                     oldtimemodified.time IS NOT NULL THEN 1 ELSE 0 END) AS convertedattempts,
00412                 SUM(CASE WHEN quiza.needsupgradetonewqe = 0 AND
00413                     newtimemodified.time IS NULL OR oldtimemodified.time >= newtimemodified.time
00414                             THEN 1 ELSE 0 END) AS resettableattempts
00415 
00416             FROM {quiz_attempts} quiza
00417             JOIN {quiz} quiz ON quiz.id = quiza.quiz
00418             JOIN {course} c ON c.id = quiz.course
00419             LEFT JOIN (
00420                 SELECT attempt, MAX(timestamp) AS time
00421                 FROM {question_states}
00422                 GROUP BY attempt
00423             ) AS oldtimemodified ON oldtimemodified.attempt = quiza.uniqueid
00424             LEFT JOIN (
00425                 SELECT qa.questionusageid, MAX(qas.timecreated) AS time
00426                 FROM {question_attempts} qa
00427                 JOIN {question_attempt_steps} qas ON qas.questionattemptid = qa.id
00428                 GROUP BY qa.questionusageid
00429             ) AS newtimemodified ON newtimemodified.questionusageid = quiza.uniqueid
00430 
00431             WHERE quiza.preview = 0
00432               AND quiz.id = ?
00433 
00434             GROUP BY quiz.id, quiz.name, c.shortname, c.id", array($quizid));
00435 }
00436 
00443 function tool_qeupgradehelper_get_session_id($attemptid, $questionid) {
00444     global $DB;
00445     $attempt = $DB->get_record('quiz_attempts', array('id' => $attemptid));
00446     if (!$attempt) {
00447         return null;
00448     }
00449     return $DB->get_field('question_sessions', 'id',
00450             array('attemptid' => $attempt->uniqueid, 'questionid' => $questionid));
00451 }
00452 
00461 function tool_qeupgradehelper_find_test_case($behaviour, $statehistory, $qtype, $extratests) {
00462     global $DB;
00463 
00464     $params = array(
00465         'qtype' => $qtype,
00466         'statehistory' => $statehistory
00467     );
00468 
00469     if ($behaviour == 'deferredfeedback') {
00470         $extrawhere = '';
00471         $params['optionflags'] = 0;
00472 
00473     } else if ($behaviour == 'adaptive') {
00474         $extrawhere = 'AND penaltyscheme = :penaltyscheme';
00475         $params['optionflags'] = 0;
00476         $params['penaltyscheme'] = 0;
00477 
00478     } else {
00479         $extrawhere = 'AND penaltyscheme = :penaltyscheme';
00480         $params['optionflags'] = 0;
00481         $params['penaltyscheme'] = 1;
00482     }
00483 
00484     $possibleids = $DB->get_records_sql_menu('
00485             SELECT
00486                 qsess.id,
00487                 1
00488 
00489             FROM {question_sessions} qsess
00490             JOIN {question_states} qst ON qst.attempt = qsess.attemptid
00491                     AND qst.question = qsess.questionid
00492             JOIN {quiz_attempts} quiza ON quiza.uniqueid = qsess.attemptid
00493             JOIN {quiz} quiz ON quiz.id = quiza.quiz
00494             JOIN {question} q ON q.id = qsess.questionid
00495 
00496             WHERE q.qtype = :qtype
00497             AND quiz.optionflags = :optionflags
00498             ' . $extrawhere . '
00499 
00500             GROUP BY
00501                 qsess.id
00502 
00503             HAVING SUM(
00504                 (CASE WHEN qst.event = 10 THEN 1 ELSE qst.event END) *
00505                 POWER(10, CAST(qst.seq_number AS NUMERIC(110,0)))
00506             ) = :statehistory' . $extratests, $params, 0, 100);
00507 
00508     if (!$possibleids) {
00509         return null;
00510     }
00511 
00512     return array_rand($possibleids);
00513 }
00514 
00519 function tool_qeupgradehelper_generate_unit_test($questionsessionid, $namesuffix) {
00520     global $DB;
00521 
00522     $qsession = $DB->get_record('question_sessions', array('id' => $questionsessionid));
00523     $attempt = $DB->get_record('quiz_attempts', array('uniqueid' => $qsession->attemptid));
00524     $quiz = $DB->get_record('quiz', array('id' => $attempt->quiz));
00525     $qstates = $DB->get_records('question_states',
00526             array('attempt' => $qsession->attemptid, 'question' => $qsession->questionid),
00527             'seq_number, id');
00528 
00529     $question = tool_qeupgradehelper_load_question($qsession->questionid, $quiz->id);
00530 
00531     if (!tool_qeupgradehelper_is_upgraded()) {
00532         if (!$quiz->optionflags) {
00533             $quiz->preferredbehaviour = 'deferredfeedback';
00534         } else if ($quiz->penaltyscheme) {
00535             $quiz->preferredbehaviour = 'adaptive';
00536         } else {
00537             $quiz->preferredbehaviour = 'adaptivenopenalty';
00538         }
00539         unset($quiz->optionflags);
00540         unset($quiz->penaltyscheme);
00541 
00542         $question->defaultmark = $question->defaultgrade;
00543         unset($question->defaultgrade);
00544     }
00545 
00546     $attempt->needsupgradetonewqe = 1;
00547 
00548     echo '<textarea readonly="readonly" rows="80" cols="120" >' . "
00549     public function test_{$question->qtype}_{$quiz->preferredbehaviour}_{$namesuffix}() {
00550 ";
00551     tool_qeupgradehelper_display_convert_attempt_input($quiz, $attempt,
00552             $question, $qsession, $qstates);
00553 
00554     if ($question->qtype == 'random') {
00555         list($randombit, $realanswer) = explode('-', reset($qstates)->answer, 2);
00556         $newquestionid = substr($randombit, 6);
00557         $newquestion = tool_qeupgradehelper_load_question($newquestionid);
00558         $newquestion->maxmark = $question->maxmark;
00559 
00560         echo tool_qeupgradehelper_format_var('$realquestion', $newquestion);
00561         echo '        $this->loader->put_question_in_cache($realquestion);
00562 ';
00563     }
00564 
00565     echo '
00566         $qa = $this->updater->convert_question_attempt($quiz, $attempt, $question, $qsession, $qstates);
00567 
00568         $expectedqa = (object) array(';
00569     echo "
00570             'behaviour' => '{$quiz->preferredbehaviour}',
00571             'questionid' => {$question->id},
00572             'variant' => 1,
00573             'maxmark' => {$question->maxmark},
00574             'minfraction' => 0,
00575             'flagged' => 0,
00576             'questionsummary' => '',
00577             'rightanswer' => '',
00578             'responsesummary' => '',
00579             'timemodified' => 0,
00580             'steps' => array(";
00581     foreach ($qstates as $state) {
00582         echo "
00583                 {$state->seq_number} => (object) array(
00584                     'sequencenumber' => {$state->seq_number},
00585                     'state' => '',
00586                     'fraction' => null,
00587                     'timecreated' => {$state->timestamp},
00588                     'userid' => {$attempt->userid},
00589                     'data' => array(),
00590                 ),";
00591     }
00592     echo '
00593             ),
00594         );
00595 
00596         $this->compare_qas($expectedqa, $qa);
00597     }
00598 </textarea>';
00599 }
00600 
00601 function tool_qeupgradehelper_format_var($name, $var) {
00602     $out = var_export($var, true);
00603     $out = str_replace('<', '&lt;', $out);
00604     $out = str_replace('ADOFetchObj::__set_state(array(', '(object) array(', $out);
00605     $out = str_replace('stdClass::__set_state(array(', '(object) array(', $out);
00606     $out = str_replace('array (', 'array(', $out);
00607     $out = preg_replace('/=> \n\s*/', '=> ', $out);
00608     $out = str_replace(')),', '),', $out);
00609     $out = str_replace('))', ')', $out);
00610     $out = preg_replace('/\n               (?! )/', "\n                                    ", $out);
00611     $out = preg_replace('/\n            (?! )/',    "\n                                ", $out);
00612     $out = preg_replace('/\n           (?! )/',     "\n                            ", $out);
00613     $out = preg_replace('/\n          (?! )/',      "\n                            ", $out);
00614     $out = preg_replace('/\n         (?! )/',       "\n                        ", $out);
00615     $out = preg_replace('/\n        (?! )/',        "\n                        ", $out);
00616     $out = preg_replace('/\n       (?! )/',         "\n                        ", $out);
00617     $out = preg_replace('/\n      (?! )/',          "\n                    ", $out);
00618     $out = preg_replace('/\n     (?! )/',           "\n                ", $out);
00619     $out = preg_replace('/\n    (?! )/',            "\n                ", $out);
00620     $out = preg_replace('/\n   (?! )/',             "\n            ", $out);
00621     $out = preg_replace('/\n  (?! )/',              "\n            ", $out);
00622     $out = preg_replace('/\n(?! )/',                "\n        ", $out);
00623     $out = preg_replace('/\bNULL\b/', 'null', $out);
00624     return "        $name = $out;\n";
00625 }
00626 
00627 function tool_qeupgradehelper_display_convert_attempt_input($quiz, $attempt,
00628         $question, $qsession, $qstates) {
00629     echo tool_qeupgradehelper_format_var('$quiz', $quiz);
00630     echo tool_qeupgradehelper_format_var('$attempt', $attempt);
00631     echo tool_qeupgradehelper_format_var('$question', $question);
00632     echo tool_qeupgradehelper_format_var('$qsession', $qsession);
00633     echo tool_qeupgradehelper_format_var('$qstates', $qstates);
00634 }
00635 
00636 function tool_qeupgradehelper_load_question($questionid, $quizid) {
00637     global $CFG, $DB;
00638 
00639     $question = $DB->get_record_sql('
00640             SELECT q.*, qqi.grade AS maxmark
00641             FROM {question} q
00642             JOIN {quiz_question_instances} qqi ON qqi.question = q.id
00643             WHERE q.id = :questionid AND qqi.quiz = :quizid',
00644             array('questionid' => $questionid, 'quizid' => $quizid));
00645 
00646     if (tool_qeupgradehelper_is_upgraded()) {
00647         require_once($CFG->dirroot . '/question/engine/bank.php');
00648         $qtype = question_bank::get_qtype($question->qtype, false);
00649     } else {
00650         global $QTYPES;
00651         if (!array_key_exists($question->qtype, $QTYPES)) {
00652             $question->qtype = 'missingtype';
00653             $question->questiontext = '<p>' . get_string('warningmissingtype', 'quiz') . '</p>' . $question->questiontext;
00654         }
00655         $qtype = $QTYPES[$question->qtype];
00656     }
00657 
00658     $qtype->get_question_options($question);
00659 
00660     return $question;
00661 }
00662 
00663 function tool_qeupgradehelper_get_quiz_for_upgrade() {
00664     global $DB;
00665 
00666     return $DB->get_record_sql("SELECT quiz.id
00667             FROM {quiz_attempts} quiza
00668             JOIN {quiz} quiz ON quiz.id = quiza.quiz
00669             JOIN {course} c ON c.id = quiz.course
00670             WHERE quiza.preview = 0 AND quiza.needsupgradetonewqe = 1
00671             GROUP BY quiz.id, quiz.name, c.shortname, c.id
00672             ORDER BY quiza.timemodified DESC", array(), IGNORE_MULTIPLE);
00673 }
 All Data Structures Namespaces Files Functions Variables Enumerations