[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/mod/quiz/db/ -> upgrade.php (source)

   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   * Upgrade script for the quiz module.
  19   *
  20   * @package    mod_quiz
  21   * @copyright  2006 Eloy Lafuente (stronk7)
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  
  29  /**
  30   * Quiz module upgrade function.
  31   * @param string $oldversion the version we are upgrading from.
  32   */
  33  function xmldb_quiz_upgrade($oldversion) {
  34      global $CFG, $DB;
  35  
  36      $dbman = $DB->get_manager();
  37  
  38      // Moodle v2.2.0 release upgrade line.
  39      // Put any upgrade step following this.
  40  
  41      if ($oldversion < 2011120700) {
  42  
  43          // Define field lastcron to be dropped from quiz_reports.
  44          $table = new xmldb_table('quiz_reports');
  45          $field = new xmldb_field('lastcron');
  46  
  47          // Conditionally launch drop field lastcron.
  48          if ($dbman->field_exists($table, $field)) {
  49              $dbman->drop_field($table, $field);
  50          }
  51  
  52          // Quiz savepoint reached.
  53          upgrade_mod_savepoint(true, 2011120700, 'quiz');
  54      }
  55  
  56      if ($oldversion < 2011120701) {
  57  
  58          // Define field cron to be dropped from quiz_reports.
  59          $table = new xmldb_table('quiz_reports');
  60          $field = new xmldb_field('cron');
  61  
  62          // Conditionally launch drop field cron.
  63          if ($dbman->field_exists($table, $field)) {
  64              $dbman->drop_field($table, $field);
  65          }
  66  
  67          // Quiz savepoint reached.
  68          upgrade_mod_savepoint(true, 2011120701, 'quiz');
  69      }
  70  
  71      if ($oldversion < 2011120703) {
  72          // Track page of quiz attempts.
  73          $table = new xmldb_table('quiz_attempts');
  74  
  75          $field = new xmldb_field('currentpage', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, 0);
  76  
  77          if (!$dbman->field_exists($table, $field)) {
  78              $dbman->add_field($table, $field);
  79          }
  80          upgrade_mod_savepoint(true, 2011120703, 'quiz');
  81      }
  82  
  83      if ($oldversion < 2012030901) {
  84          // Configuration option for navigation method.
  85          $table = new xmldb_table('quiz');
  86  
  87          $field = new xmldb_field('navmethod', XMLDB_TYPE_CHAR, '16', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, 'free');
  88  
  89          if (!$dbman->field_exists($table, $field)) {
  90              $dbman->add_field($table, $field);
  91          }
  92          upgrade_mod_savepoint(true, 2012030901, 'quiz');
  93      }
  94  
  95      if ($oldversion < 2012040198) {
  96          // This step was added later. In MDL-32727, it was found that adding the
  97          // unique index on quiz-userid-attempt sometimes failed because of
  98          // duplicate entries {quizid}-{userid}-{attempt}. We do two things to
  99          // prevent these problems. First, here, we delete all preview attempts.
 100  
 101          // This code is an approximate copy-and-paste from
 102          // question_engine_data_mapper::delete_questions_usage_by_activities
 103          // Note that, for simplicity, the MySQL performance hack has been removed.
 104          // Since this code is for upgrade only, performance in not so critical,
 105          // where as simplicity of testing the code is.
 106  
 107          // Note that there is a limit to how far I am prepared to go in eliminating
 108          // all calls to library functions in this upgrade code. The only library
 109          // function still being used in question_engine::get_all_response_file_areas();
 110          // I think it is pretty safe not to inline it here.
 111  
 112          // Get a list of response variables that have files.
 113          require_once($CFG->dirroot . '/question/type/questiontypebase.php');
 114          $variables = array();
 115          foreach (core_component::get_plugin_list('qtype') as $qtypename => $path) {
 116              $file = $path . '/questiontype.php';
 117              if (!is_readable($file)) {
 118                  continue;
 119              }
 120              include_once($file);
 121              $class = 'qtype_' . $qtypename;
 122              if (!class_exists($class)) {
 123                  continue;
 124              }
 125              $qtype = new $class();
 126              if (!method_exists($qtype, 'response_file_areas')) {
 127                  continue;
 128              }
 129              $variables += $qtype->response_file_areas();
 130          }
 131  
 132          // Conver that to a list of actual file area names.
 133          $fileareas = array();
 134          foreach (array_unique($variables) as $variable) {
 135              $fileareas[] = 'response_' . $variable;
 136          }
 137          // No point checking if this is empty as an optimisation, because essay
 138          // has response file areas, so the array will never be empty.
 139  
 140          // Get all the contexts where there are previews.
 141          $contextids = $DB->get_records_sql_menu("
 142                  SELECT DISTINCT qu.contextid, 1
 143                    FROM {question_usages} qu
 144                    JOIN {quiz_attempts} quiza ON quiza.uniqueid = qu.id
 145                   WHERE quiza.preview = 1");
 146  
 147          // Loop over contexts and files areas, deleting all files.
 148          $fs = get_file_storage();
 149          foreach ($contextids as $contextid => $notused) {
 150              foreach ($fileareas as $filearea) {
 151                  upgrade_set_timeout(300);
 152                  $fs->delete_area_files_select($contextid, 'question', $filearea,
 153                          "IN (SELECT qas.id
 154                                 FROM {question_attempt_steps} qas
 155                                 JOIN {question_attempts} qa ON qa.id = qas.questionattemptid
 156                                 JOIN {quiz_attempts} quiza ON quiza.uniqueid = qa.questionusageid
 157                                WHERE quiza.preview = 1)");
 158              }
 159          }
 160  
 161          // Now delete the question data associated with the previews.
 162          $DB->delete_records_select('question_attempt_step_data', "attemptstepid IN (
 163                  SELECT qas.id
 164                    FROM {question_attempt_steps} qas
 165                    JOIN {question_attempts} qa ON qa.id = qas.questionattemptid
 166                    JOIN {quiz_attempts} quiza ON quiza.uniqueid = qa.questionusageid
 167                   WHERE quiza.preview = 1)");
 168  
 169          $DB->delete_records_select('question_attempt_steps', "questionattemptid IN (
 170                  SELECT qa.id
 171                    FROM {question_attempts} qa
 172                    JOIN {quiz_attempts} quiza ON quiza.uniqueid = qa.questionusageid
 173                   WHERE quiza.preview = 1)");
 174  
 175          $DB->delete_records_select('question_attempts', "{question_attempts}.questionusageid IN (
 176                  SELECT uniqueid FROM {quiz_attempts} WHERE preview = 1)");
 177  
 178          $DB->delete_records_select('question_usages', "{question_usages}.id IN (
 179                  SELECT uniqueid FROM {quiz_attempts} WHERE preview = 1)");
 180  
 181          // Finally delete the previews.
 182          $DB->delete_records('quiz_attempts', array('preview' => 1));
 183  
 184          // Quiz savepoint reached.
 185          upgrade_mod_savepoint(true, 2012040198, 'quiz');
 186      }
 187  
 188      if ($oldversion < 2012040199) {
 189          // This step was added later. In MDL-32727, it was found that adding the
 190          // unique index on quiz-userid-attempt sometimes failed because of
 191          // duplicate entries {quizid}-{userid}-{attempt}.
 192          // Here, if there are still duplicate entires, we renumber the values in
 193          // the attempt column.
 194  
 195          // Load all the problem quiz attempts.
 196          $problems = $DB->get_recordset_sql('
 197                  SELECT qa.id, qa.quiz, qa.userid, qa.attempt
 198                    FROM {quiz_attempts} qa
 199                    JOIN (
 200                            SELECT DISTINCT quiz, userid
 201                              FROM {quiz_attempts}
 202                          GROUP BY quiz, userid, attempt
 203                            HAVING COUNT(1) > 1
 204                         ) problems_view ON problems_view.quiz = qa.quiz AND
 205                                            problems_view.userid = qa.userid
 206                ORDER BY qa.quiz, qa.userid, qa.attempt, qa.id');
 207  
 208          // Renumber them.
 209          $currentquiz = null;
 210          $currentuserid = null;
 211          $attempt = 1;
 212          foreach ($problems as $problem) {
 213              if ($problem->quiz !== $currentquiz || $problem->userid !== $currentuserid) {
 214                  $currentquiz = $problem->quiz;
 215                  $currentuserid = $problem->userid;
 216                  $attempt = 1;
 217              }
 218              if ($attempt != $problem->attempt) {
 219                  $DB->set_field('quiz_attempts', 'attempt', $attempt, array('id' => $problem->id));
 220              }
 221              $attempt += 1;
 222          }
 223  
 224          $problems->close();
 225  
 226          // Quiz savepoint reached.
 227          upgrade_mod_savepoint(true, 2012040199, 'quiz');
 228      }
 229  
 230      if ($oldversion < 2012040200) {
 231          // Define index userid to be dropped form quiz_attempts
 232          $table = new xmldb_table('quiz_attempts');
 233          $index = new xmldb_index('userid', XMLDB_INDEX_NOTUNIQUE, array('userid'));
 234  
 235          // Conditionally launch drop index quiz-userid-attempt.
 236          if ($dbman->index_exists($table, $index)) {
 237              $dbman->drop_index($table, $index);
 238          }
 239  
 240          // Quiz savepoint reached.
 241          upgrade_mod_savepoint(true, 2012040200, 'quiz');
 242      }
 243  
 244      if ($oldversion < 2012040201) {
 245  
 246          // Define key userid (foreign) to be added to quiz_attempts.
 247          $table = new xmldb_table('quiz_attempts');
 248          $key = new xmldb_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
 249  
 250          // Launch add key userid.
 251          $dbman->add_key($table, $key);
 252  
 253          // Quiz savepoint reached.
 254          upgrade_mod_savepoint(true, 2012040201, 'quiz');
 255      }
 256  
 257      if ($oldversion < 2012040202) {
 258  
 259          // Define index quiz-userid-attempt (unique) to be added to quiz_attempts.
 260          $table = new xmldb_table('quiz_attempts');
 261          $index = new xmldb_index('quiz-userid-attempt', XMLDB_INDEX_UNIQUE, array('quiz', 'userid', 'attempt'));
 262  
 263          // Conditionally launch add index quiz-userid-attempt.
 264          if (!$dbman->index_exists($table, $index)) {
 265              $dbman->add_index($table, $index);
 266          }
 267  
 268          // Quiz savepoint reached.
 269          upgrade_mod_savepoint(true, 2012040202, 'quiz');
 270      }
 271  
 272      if ($oldversion < 2012040203) {
 273  
 274          // Define field state to be added to quiz_attempts.
 275          $table = new xmldb_table('quiz_attempts');
 276          $field = new xmldb_field('state', XMLDB_TYPE_CHAR, '16', null, XMLDB_NOTNULL, null, 'inprogress', 'preview');
 277  
 278          // Conditionally launch add field state.
 279          if (!$dbman->field_exists($table, $field)) {
 280              $dbman->add_field($table, $field);
 281          }
 282  
 283          // Quiz savepoint reached.
 284          upgrade_mod_savepoint(true, 2012040203, 'quiz');
 285      }
 286  
 287      if ($oldversion < 2012040204) {
 288  
 289          // Update quiz_attempts.state for finished attempts.
 290          $DB->set_field_select('quiz_attempts', 'state', 'finished', 'timefinish > 0');
 291  
 292          // Other, more complex transitions (basically abandoned attempts), will
 293          // be handled by cron later.
 294  
 295          // Quiz savepoint reached.
 296          upgrade_mod_savepoint(true, 2012040204, 'quiz');
 297      }
 298  
 299      if ($oldversion < 2012040205) {
 300  
 301          // Define field overduehandling to be added to quiz.
 302          $table = new xmldb_table('quiz');
 303          $field = new xmldb_field('overduehandling', XMLDB_TYPE_CHAR, '16', null, XMLDB_NOTNULL, null, 'autoabandon', 'timelimit');
 304  
 305          // Conditionally launch add field overduehandling.
 306          if (!$dbman->field_exists($table, $field)) {
 307              $dbman->add_field($table, $field);
 308          }
 309  
 310          // Quiz savepoint reached.
 311          upgrade_mod_savepoint(true, 2012040205, 'quiz');
 312      }
 313  
 314      if ($oldversion < 2012040206) {
 315  
 316          // Define field graceperiod to be added to quiz.
 317          $table = new xmldb_table('quiz');
 318          $field = new xmldb_field('graceperiod', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'overduehandling');
 319  
 320          // Conditionally launch add field graceperiod.
 321          if (!$dbman->field_exists($table, $field)) {
 322              $dbman->add_field($table, $field);
 323          }
 324  
 325          // Quiz savepoint reached.
 326          upgrade_mod_savepoint(true, 2012040206, 'quiz');
 327      }
 328  
 329      // Moodle v2.3.0 release upgrade line
 330      // Put any upgrade step following this
 331  
 332      if ($oldversion < 2012061702) {
 333  
 334          // MDL-32791 somebody reported having nonsense rows in their
 335          // quiz_question_instances which caused various problems. These rows
 336          // are meaningless, hence this upgrade step to clean them up.
 337          $DB->delete_records('quiz_question_instances', array('question' => 0));
 338  
 339          // Quiz savepoint reached.
 340          upgrade_mod_savepoint(true, 2012061702, 'quiz');
 341      }
 342  
 343      if ($oldversion < 2012061703) {
 344  
 345          // MDL-34702 the questiondecimalpoints column was created with default -2
 346          // when it should have been -1, and no-one has noticed in the last 2+ years!
 347  
 348          // Changing the default of field questiondecimalpoints on table quiz to -1.
 349          $table = new xmldb_table('quiz');
 350          $field = new xmldb_field('questiondecimalpoints', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '-1', 'decimalpoints');
 351  
 352          // Launch change of default for field questiondecimalpoints.
 353          $dbman->change_field_default($table, $field);
 354  
 355          // Correct any wrong values.
 356          $DB->set_field('quiz', 'questiondecimalpoints', -1, array('questiondecimalpoints' => -2));
 357  
 358          // Quiz savepoint reached.
 359          upgrade_mod_savepoint(true, 2012061703, 'quiz');
 360      }
 361  
 362      if ($oldversion < 2012100801) {
 363  
 364          // Define field timecheckstate to be added to quiz_attempts
 365          $table = new xmldb_table('quiz_attempts');
 366          $field = new xmldb_field('timecheckstate', XMLDB_TYPE_INTEGER, '10', null, null, null, '0', 'timemodified');
 367  
 368          // Conditionally launch add field timecheckstate
 369          if (!$dbman->field_exists($table, $field)) {
 370              $dbman->add_field($table, $field);
 371          }
 372  
 373          // Define index state-timecheckstate (not unique) to be added to quiz_attempts
 374          $table = new xmldb_table('quiz_attempts');
 375          $index = new xmldb_index('state-timecheckstate', XMLDB_INDEX_NOTUNIQUE, array('state', 'timecheckstate'));
 376  
 377          // Conditionally launch add index state-timecheckstate
 378          if (!$dbman->index_exists($table, $index)) {
 379              $dbman->add_index($table, $index);
 380          }
 381  
 382          // Overdue cron no longer needs these
 383          unset_config('overduelastrun', 'quiz');
 384          unset_config('overduedoneto', 'quiz');
 385  
 386          // Update timecheckstate on all open attempts
 387          require_once($CFG->dirroot . '/mod/quiz/locallib.php');
 388          quiz_update_open_attempts(array());
 389  
 390          // quiz savepoint reached
 391          upgrade_mod_savepoint(true, 2012100801, 'quiz');
 392      }
 393  
 394      // Moodle v2.4.0 release upgrade line
 395      // Put any upgrade step following this
 396  
 397      if ($oldversion < 2013031900) {
 398          // Quiz manual grading UI should be controlled by mod/quiz:grade, not :viewreports.
 399          $DB->set_field('quiz_reports', 'capability', 'mod/quiz:grade', array('name' => 'grading'));
 400  
 401          // Mod quiz savepoint reached.
 402          upgrade_mod_savepoint(true, 2013031900, 'quiz');
 403      }
 404  
 405      // Moodle v2.5.0 release upgrade line.
 406      // Put any upgrade step following this.
 407  
 408  
 409      // Moodle v2.6.0 release upgrade line.
 410      // Put any upgrade step following this.
 411  
 412      if ($oldversion < 2014011300) {
 413  
 414          // Define key quiz (foreign) to be dropped form quiz_question_instances.
 415          $table = new xmldb_table('quiz_question_instances');
 416          $key = new xmldb_key('quiz', XMLDB_KEY_FOREIGN, array('quiz'), 'quiz', array('id'));
 417  
 418          // Launch drop key quiz.
 419          $dbman->drop_key($table, $key);
 420  
 421          // Quiz savepoint reached.
 422          upgrade_mod_savepoint(true, 2014011300, 'quiz');
 423      }
 424  
 425      if ($oldversion < 2014011301) {
 426  
 427          // Rename field quiz on table quiz_question_instances to quizid.
 428          $table = new xmldb_table('quiz_question_instances');
 429          $field = new xmldb_field('quiz', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'id');
 430  
 431          // Launch rename field quiz.
 432          $dbman->rename_field($table, $field, 'quizid');
 433  
 434          // Quiz savepoint reached.
 435          upgrade_mod_savepoint(true, 2014011301, 'quiz');
 436      }
 437  
 438      if ($oldversion < 2014011302) {
 439  
 440          // Define key quizid (foreign) to be added to quiz_question_instances.
 441          $table = new xmldb_table('quiz_question_instances');
 442          $key = new xmldb_key('quizid', XMLDB_KEY_FOREIGN, array('quizid'), 'quiz', array('id'));
 443  
 444          // Launch add key quizid.
 445          $dbman->add_key($table, $key);
 446  
 447          // Quiz savepoint reached.
 448          upgrade_mod_savepoint(true, 2014011302, 'quiz');
 449      }
 450  
 451      if ($oldversion < 2014011303) {
 452  
 453          // Define key question (foreign) to be dropped form quiz_question_instances.
 454          $table = new xmldb_table('quiz_question_instances');
 455          $key = new xmldb_key('question', XMLDB_KEY_FOREIGN, array('question'), 'question', array('id'));
 456  
 457          // Launch drop key question.
 458          $dbman->drop_key($table, $key);
 459  
 460          // Quiz savepoint reached.
 461          upgrade_mod_savepoint(true, 2014011303, 'quiz');
 462      }
 463  
 464      if ($oldversion < 2014011304) {
 465  
 466          // Rename field question on table quiz_question_instances to questionid.
 467          $table = new xmldb_table('quiz_question_instances');
 468          $field = new xmldb_field('question', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'quiz');
 469  
 470          // Launch rename field question.
 471          $dbman->rename_field($table, $field, 'questionid');
 472  
 473          // Quiz savepoint reached.
 474          upgrade_mod_savepoint(true, 2014011304, 'quiz');
 475      }
 476  
 477      if ($oldversion < 2014011305) {
 478  
 479          // Define key questionid (foreign) to be added to quiz_question_instances.
 480          $table = new xmldb_table('quiz_question_instances');
 481          $key = new xmldb_key('questionid', XMLDB_KEY_FOREIGN, array('questionid'), 'question', array('id'));
 482  
 483          // Launch add key questionid.
 484          $dbman->add_key($table, $key);
 485  
 486          // Quiz savepoint reached.
 487          upgrade_mod_savepoint(true, 2014011305, 'quiz');
 488      }
 489  
 490      if ($oldversion < 2014011306) {
 491  
 492          // Rename field grade on table quiz_question_instances to maxmark.
 493          $table = new xmldb_table('quiz_question_instances');
 494          $field = new xmldb_field('grade', XMLDB_TYPE_NUMBER, '12, 7', null, XMLDB_NOTNULL, null, '0', 'question');
 495  
 496          // Launch rename field grade.
 497          $dbman->rename_field($table, $field, 'maxmark');
 498  
 499          // Quiz savepoint reached.
 500          upgrade_mod_savepoint(true, 2014011306, 'quiz');
 501      }
 502  
 503      if ($oldversion < 2014021300) {
 504  
 505          // Define field needsupgradetonewqe to be dropped from quiz_attempts.
 506          $table = new xmldb_table('quiz_attempts');
 507          $field = new xmldb_field('needsupgradetonewqe');
 508  
 509          // Conditionally launch drop field needsupgradetonewqe.
 510          if ($dbman->field_exists($table, $field)) {
 511              $dbman->drop_field($table, $field);
 512          }
 513  
 514          // Quiz savepoint reached.
 515          upgrade_mod_savepoint(true, 2014021300, 'quiz');
 516      }
 517  
 518      if ($oldversion < 2014022000) {
 519  
 520          // Define table quiz_question_instances to be renamed to quiz_slots.
 521          $table = new xmldb_table('quiz_question_instances');
 522  
 523          // Launch rename table for quiz_question_instances.
 524          $dbman->rename_table($table, 'quiz_slots');
 525  
 526          // Quiz savepoint reached.
 527          upgrade_mod_savepoint(true, 2014022000, 'quiz');
 528      }
 529  
 530      if ($oldversion < 2014022001) {
 531  
 532          // Define field slot to be added to quiz_slots.
 533          $table = new xmldb_table('quiz_slots');
 534          $field = new xmldb_field('slot', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'id');
 535  
 536          // Conditionally launch add field slot.
 537          if (!$dbman->field_exists($table, $field)) {
 538              $dbman->add_field($table, $field);
 539          }
 540  
 541          // Quiz savepoint reached.
 542          upgrade_mod_savepoint(true, 2014022001, 'quiz');
 543      }
 544  
 545      if ($oldversion < 2014022002) {
 546  
 547          // Define field page to be added to quiz_slots.
 548          $table = new xmldb_table('quiz_slots');
 549          $field = new xmldb_field('page', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'quizid');
 550  
 551          // Conditionally launch add field page.
 552          if (!$dbman->field_exists($table, $field)) {
 553              $dbman->add_field($table, $field);
 554          }
 555  
 556          // Quiz savepoint reached.
 557          upgrade_mod_savepoint(true, 2014022002, 'quiz');
 558      }
 559  
 560      if ($oldversion < 2014022003) {
 561  
 562          // Use the information in the old quiz.questions column to fill in the
 563          // new slot and page columns.
 564          $numquizzes = $DB->count_records('quiz');
 565          if ($numquizzes > 0) {
 566              $pbar = new progress_bar('quizquestionstoslots', 500, true);
 567              $transaction = $DB->start_delegated_transaction();
 568  
 569              $numberdone = 0;
 570              $quizzes = $DB->get_recordset('quiz', null, 'id', 'id,questions,sumgrades');
 571              foreach ($quizzes as $quiz) {
 572                  if ($quiz->questions === '') {
 573                      $questionsinorder = array();
 574                  } else {
 575                      $questionsinorder = explode(',', $quiz->questions);
 576                  }
 577  
 578                  $questionidtoslotrowid = $DB->get_records_menu('quiz_slots',
 579                          array('quizid' => $quiz->id), '', 'id, questionid');
 580  
 581                  $problemfound = false;
 582                  $currentpage = 1;
 583                  $slot = 1;
 584                  foreach ($questionsinorder as $questionid) {
 585                      if ($questionid === '0') {
 586                          // Page break.
 587                          $currentpage++;
 588                          continue;
 589                      }
 590  
 591                      if ($questionid === '') {
 592                          // This can happen as the result of old restore bugs.
 593                          // There can be a missing number in the list of ids.
 594                          // All we can do about this is ignore it, which is what
 595                          // the quiz system used to do. See MDL-45321.
 596                          continue;
 597                      }
 598  
 599                      $key = array_search($questionid, $questionidtoslotrowid);
 600                      if ($key !== false) {
 601                          // Normal case. quiz_slots entry is present.
 602                          // Just need to add slot and page.
 603                          $quizslot = new stdClass();
 604                          $quizslot->id   = $key;
 605                          $quizslot->slot = $slot;
 606                          $quizslot->page = $currentpage;
 607                          $DB->update_record('quiz_slots', $quizslot);
 608  
 609                          unset($questionidtoslotrowid[$key]); // So we can do a sanity check later.
 610                          $slot++;
 611                          continue;
 612  
 613                      } else {
 614                          // This should not happen. The question was listed in
 615                          // quiz.questions, but there was not an entry for it in
 616                          // quiz_slots (formerly quiz_question_instances).
 617                          // Previously, if such question ids were found, then
 618                          // starting an attempt at the quiz would throw an exception.
 619                          // Here, we try to add the missing data.
 620                          $problemfound = true;
 621                          $defaultmark = $DB->get_field('question', 'defaultmark',
 622                                  array('id' => $questionid), IGNORE_MISSING);
 623                          if ($defaultmark === false) {
 624                              debugging('During upgrade, detected that question ' .
 625                                      $questionid . ' was listed as being part of quiz ' .
 626                                      $quiz->id . ' but this question no longer exists. Ignoring it.', DEBUG_NORMAL);
 627  
 628                              // Non-existent question. Ignore it completely.
 629                              continue;
 630                          }
 631  
 632                          debugging('During upgrade, detected that question ' .
 633                                  $questionid . ' was listed as being part of quiz ' .
 634                                  $quiz->id . ' but there was not entry for it in ' .
 635                                  'quiz_question_instances/quiz_slots. Creating an entry with default mark.', DEBUG_NORMAL);
 636                          $quizslot = new stdClass();
 637                          $quizslot->quizid     = $quiz->id;
 638                          $quizslot->slot       = $slot;
 639                          $quizslot->page       = $currentpage;
 640                          $quizslot->questionid = $questionid;
 641                          $quizslot->maxmark    = $defaultmark;
 642                          $DB->insert_record('quiz_slots', $quizslot);
 643  
 644                          $slot++;
 645                          continue;
 646                      }
 647  
 648                  }
 649  
 650                  // Now, as a sanity check, ensure we have done all the
 651                  // quiz_slots rows linked to this quiz.
 652                  if (!empty($questionidtoslotrowid)) {
 653                      debugging('During upgrade, detected that questions ' .
 654                              implode(', ', array_values($questionidtoslotrowid)) .
 655                              ' had instances in quiz ' . $quiz->id . ' but were not actually used. ' .
 656                              'The instances have been removed.', DEBUG_NORMAL);
 657  
 658                      $DB->delete_records_list('quiz_slots', 'id', array_keys($questionidtoslotrowid));
 659                      $problemfound = true;
 660                  }
 661  
 662                  // If there were problems found, we probably need to re-compute
 663                  // quiz.sumgrades.
 664                  if ($problemfound) {
 665                      // C/f the quiz_update_sumgrades function in locallib.php,
 666                      // but note that what we do here is a bit simpler.
 667                      $newsumgrades = $DB->get_field_sql(
 668                              "SELECT SUM(maxmark)
 669                                 FROM {quiz_slots}
 670                                WHERE quizid = ?",
 671                              array($quiz->id));
 672                      if (!$newsumgrades) {
 673                          $newsumgrades = 0;
 674                      }
 675                      if (abs($newsumgrades - $quiz->sumgrades) > 0.000005) {
 676                          debugging('Because of the previously mentioned problems, ' .
 677                                  'sumgrades for quiz ' . $quiz->id .
 678                                  ' was changed from ' . $quiz->sumgrades . ' to ' .
 679                                  $newsumgrades . ' You should probably check that this quiz is still working: ' .
 680                                  $CFG->wwwroot . '/mod/quiz/view.php?q=' . $quiz->id . '.', DEBUG_NORMAL);
 681                          $DB->set_field('quiz', 'sumgrades', $newsumgrades, array('id' => $quiz->id));
 682                      }
 683                  }
 684  
 685                  // Done with this quiz. Update progress bar.
 686                  $numberdone++;
 687                  $pbar->update($numberdone, $numquizzes,
 688                          "Upgrading quiz structure - {$numberdone}/{$numquizzes}.");
 689              }
 690  
 691              $transaction->allow_commit();
 692          }
 693  
 694          // Quiz savepoint reached.
 695          upgrade_mod_savepoint(true, 2014022003, 'quiz');
 696      }
 697  
 698      if ($oldversion < 2014022004) {
 699  
 700          // If, for any reason, there were any quiz_slots missed, then try
 701          // to do something about that now before we add the NOT NULL constraints.
 702          // In fact, becuase of the sanity check at the end of the above check,
 703          // any such quiz_slots rows must refer to a non-existent quiz id, so
 704          // delete them.
 705          $DB->delete_records_select('quiz_slots',
 706                  'NOT EXISTS (SELECT 1 FROM {quiz} q WHERE q.id = quizid)');
 707  
 708          // Quiz savepoint reached.
 709          upgrade_mod_savepoint(true, 2014022004, 'quiz');
 710  
 711          // Now, if any quiz_slots rows are left with slot or page NULL, something
 712          // is badly wrong.
 713          if ($DB->record_exists_select('quiz_slots', 'slot IS NULL OR page IS NULL')) {
 714              throw new coding_exception('Something went wrong in the quiz upgrade step for MDL-43749. ' .
 715                      'Some quiz_slots still contain NULLs which will break the NOT NULL constraints we need to add. ' .
 716                      'Please report this problem at http://tracker.moodle.org/ so that it can be investigated. Thank you.');
 717          }
 718      }
 719  
 720      if ($oldversion < 2014022005) {
 721  
 722          // Changing nullability of field slot on table quiz_slots to not null.
 723          $table = new xmldb_table('quiz_slots');
 724          $field = new xmldb_field('slot', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'id');
 725  
 726          // Launch change of nullability for field slot.
 727          $dbman->change_field_notnull($table, $field);
 728  
 729          // Quiz savepoint reached.
 730          upgrade_mod_savepoint(true, 2014022005, 'quiz');
 731      }
 732  
 733      if ($oldversion < 2014022006) {
 734  
 735          // Changing nullability of field page on table quiz_slots to not null.
 736          $table = new xmldb_table('quiz_slots');
 737          $field = new xmldb_field('page', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'quizid');
 738  
 739          // Launch change of nullability for field page.
 740          $dbman->change_field_notnull($table, $field);
 741  
 742          // Quiz savepoint reached.
 743          upgrade_mod_savepoint(true, 2014022006, 'quiz');
 744      }
 745  
 746      if ($oldversion < 2014022007) {
 747  
 748          // Define index quizid-slot (unique) to be added to quiz_slots.
 749          $table = new xmldb_table('quiz_slots');
 750          $index = new xmldb_index('quizid-slot', XMLDB_INDEX_UNIQUE, array('quizid', 'slot'));
 751  
 752          // Conditionally launch add index quizid-slot.
 753          if (!$dbman->index_exists($table, $index)) {
 754              $dbman->add_index($table, $index);
 755          }
 756  
 757          // Quiz savepoint reached.
 758          upgrade_mod_savepoint(true, 2014022007, 'quiz');
 759      }
 760  
 761      if ($oldversion < 2014022008) {
 762  
 763          // Define field questions to be dropped from quiz.
 764          $table = new xmldb_table('quiz');
 765          $field = new xmldb_field('questions');
 766  
 767          // Conditionally launch drop field questions.
 768          if ($dbman->field_exists($table, $field)) {
 769              $dbman->drop_field($table, $field);
 770          }
 771  
 772          // Quiz savepoint reached.
 773          upgrade_mod_savepoint(true, 2014022008, 'quiz');
 774      }
 775  
 776      // Moodle v2.7.0 release upgrade line.
 777      // Put any upgrade step following this.
 778  
 779      if ($oldversion < 2014052800) {
 780  
 781          // Define field completionattemptsexhausted to be added to quiz.
 782          $table = new xmldb_table('quiz');
 783          $field = new xmldb_field('completionattemptsexhausted', XMLDB_TYPE_INTEGER, '1', null, null, null, '0', 'showblocks');
 784  
 785          // Conditionally launch add field completionattemptsexhausted.
 786          if (!$dbman->field_exists($table, $field)) {
 787              $dbman->add_field($table, $field);
 788          }
 789          // Quiz savepoint reached.
 790          upgrade_mod_savepoint(true, 2014052800, 'quiz');
 791      }
 792  
 793      if ($oldversion < 2014052801) {
 794          // Define field completionpass to be added to quiz.
 795          $table = new xmldb_table('quiz');
 796          $field = new xmldb_field('completionpass', XMLDB_TYPE_INTEGER, '1', null, null, null, 0, 'completionattemptsexhausted');
 797  
 798          // Conditionally launch add field completionpass.
 799          if (!$dbman->field_exists($table, $field)) {
 800              $dbman->add_field($table, $field);
 801          }
 802  
 803          // Quiz savepoint reached.
 804          upgrade_mod_savepoint(true, 2014052801, 'quiz');
 805      }
 806  
 807      // Moodle v2.8.0 release upgrade line.
 808      // Put any upgrade step following this.
 809  
 810      return true;
 811  }
 812  


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1