Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]

   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 scorm module.
  19   *
  20   * @package    mod_scorm
  21   * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  /**
  28   * @global moodle_database $DB
  29   * @param int $oldversion
  30   * @return bool
  31   */
  32  function xmldb_scorm_upgrade($oldversion) {
  33      global $DB, $OUTPUT;
  34  
  35      $dbman = $DB->get_manager();
  36  
  37      // Automatically generated Moodle v3.9.0 release upgrade line.
  38      // Put any upgrade step following this.
  39  
  40      if ($oldversion < 2021052501) {
  41          $table = new xmldb_table('scorm');
  42          $field = new xmldb_field('displayactivityname');
  43          if ($dbman->field_exists($table, $field)) {
  44              $dbman->drop_field($table, $field);
  45          }
  46          upgrade_mod_savepoint(true, 2021052501, 'scorm');
  47      }
  48  
  49      // Automatically generated Moodle v4.0.0 release upgrade line.
  50      // Put any upgrade step following this.
  51  
  52      // Automatically generated Moodle v4.1.0 release upgrade line.
  53      // Put any upgrade step following this.
  54  
  55      // Automatically generated Moodle v4.2.0 release upgrade line.
  56      // Put any upgrade step following this.
  57  
  58      // New table structure for scorm_scoes_track.
  59      if ($oldversion < 2023042401) {
  60          // Define table scorm_attempt to be created.
  61          $table = new xmldb_table('scorm_attempt');
  62  
  63          // Adding fields to table scorm_attempt.
  64          $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
  65          $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
  66          $table->add_field('scormid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
  67          $table->add_field('attempt', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '1');
  68  
  69          // Adding keys to table scorm_attempt.
  70          $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
  71          $table->add_key('user', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']);
  72          $table->add_key('scorm', XMLDB_KEY_FOREIGN, ['scormid'], 'scorm', ['id']);
  73  
  74          // Conditionally launch create table for scorm_attempt.
  75          if (!$dbman->table_exists($table)) {
  76              $dbman->create_table($table);
  77          }
  78  
  79          // Define table scorm_element to be created.
  80          $table = new xmldb_table('scorm_element');
  81  
  82          // Adding fields to table scorm_element.
  83          $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
  84          $table->add_field('element', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
  85  
  86          // Adding keys to table scorm_element.
  87          $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
  88  
  89          // Adding indexes to table scorm_element.
  90          $table->add_index('element', XMLDB_INDEX_UNIQUE, ['element']);
  91  
  92          // Conditionally launch create table for scorm_element.
  93          if (!$dbman->table_exists($table)) {
  94              $dbman->create_table($table);
  95          }
  96  
  97          // Define table scorm_scoes_value to be created.
  98          $table = new xmldb_table('scorm_scoes_value');
  99  
 100          // Adding fields to table scorm_scoes_value.
 101          $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
 102          $table->add_field('scoid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
 103          $table->add_field('attemptid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
 104          $table->add_field('elementid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
 105          $table->add_field('value', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
 106          $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
 107  
 108          // Adding keys to table scorm_scoes_value.
 109          $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
 110          $table->add_key('scoe', XMLDB_KEY_FOREIGN, ['scoid'], 'scorm_scoes', ['id']);
 111          $table->add_key('attempt', XMLDB_KEY_FOREIGN, ['attemptid'], 'scorm_attempt', ['id']);
 112          $table->add_key('element', XMLDB_KEY_FOREIGN, ['elementid'], 'scorm_element', ['id']);
 113  
 114          // Conditionally launch create table for scorm_scoes_value.
 115          if (!$dbman->table_exists($table)) {
 116              $dbman->create_table($table);
 117          }
 118  
 119          upgrade_mod_savepoint(true, 2023042401, 'scorm');
 120      }
 121  
 122      if ($oldversion < 2023042402) {
 123          $trans = $DB->start_delegated_transaction();
 124  
 125          // First grab all elements and store those.
 126          $sql = "INSERT INTO {scorm_element} (element)
 127                      SELECT DISTINCT element FROM {scorm_scoes_track}";
 128          $DB->execute($sql);
 129  
 130          // Now store all data in the scorm_attempt table.
 131          $sql = "INSERT INTO {scorm_attempt} (userid, scormid, attempt)
 132                      SELECT DISTINCT userid, scormid, attempt FROM {scorm_scoes_track}";
 133          $DB->execute($sql);
 134  
 135          $trans->allow_commit();
 136          // Scorm savepoint reached.
 137          upgrade_mod_savepoint(true, 2023042402, 'scorm');
 138  
 139      }
 140      if ($oldversion < 2023042403) {
 141          // Now store all translated data in the scorm_scoes_value table.
 142          $total = $DB->count_records('scorm_scoes_track');
 143          if ($total > 500000) {
 144              // This site has a large number of user track records, lets warn that this next part may take some time.
 145              $notification = new \core\output\notification(get_string('largetrackupgrade', 'scorm', format_float($total, 0)),
 146                             \core\output\notification::NOTIFY_WARNING);
 147              $notification->set_show_closebutton(false);
 148              echo $OUTPUT->render($notification);
 149          }
 150  
 151          // We don't need a progress bar - just run the fastest option possible.
 152          $sql = "INSERT INTO {scorm_scoes_value} (attemptid, scoid, elementid, value, timemodified)
 153                  SELECT a.id as attemptid, t.scoid as scoid, e.id as elementid, t.value as value, t.timemodified
 154                    FROM {scorm_scoes_track} t
 155                    JOIN {scorm_element} e ON e.element = t.element
 156                    JOIN {scorm_attempt} a ON (t.userid = a.userid AND t.scormid = a.scormid AND a.attempt = t.attempt)";
 157          $DB->execute($sql);
 158  
 159          // Drop old table scorm_scoes_track.
 160          $table = new xmldb_table('scorm_scoes_track');
 161  
 162          // Conditionally launch drop table for scorm_scoes_track.
 163          if ($dbman->table_exists($table)) {
 164              $dbman->drop_table($table);
 165          }
 166  
 167          // Scorm savepoint reached.
 168          upgrade_mod_savepoint(true, 2023042403, 'scorm');
 169      }
 170  
 171      // Automatically generated Moodle v4.3.0 release upgrade line.
 172      // Put any upgrade step following this.
 173  
 174      if ($oldversion < 2023100901) {
 175          // MDL-79967 - fix up any possible activity completion states since the upgrade to 2023042403.
 176          // Get timestamp of when this site updated to version 2023042403.
 177          $upgraded = $DB->get_field_sql("SELECT min(timemodified)
 178                                            FROM {upgrade_log}
 179                                           WHERE plugin = 'mod_scorm' AND version = '2023042403'");
 180          if (empty($upgraded)) {
 181              // The code causing this regression landed upstream 28 Jul 2023, if a site has done a fresh install since then,
 182              // the upgrade step won't exist - set it to 20th July so we don't end up dealing with too many attempts.
 183              $upgraded = 1689811200; // 20 July 2023 12AM.
 184          }
 185          // Don't bother triggering this next step if the upgrade completed within the last hour.
 186          if (time() - HOURSECS > $upgraded) {
 187              // Get all attempts that have occurred since the upgrade.
 188              $sql = "SELECT DISTINCT s.id, sa.userid
 189                        FROM {scorm} s
 190                        JOIN {scorm_attempt} sa ON sa.scormid = s.id
 191                        JOIN {scorm_scoes_value} sv on sv.attemptid = sa.id
 192                        WHERE sv.timemodified > ?";
 193              $scorms = $DB->get_recordset_sql($sql, [$upgraded]);
 194              foreach ($scorms as $scorm) {
 195                  // Run an ad-hoc task to update the grades.
 196                  $task = new \mod_scorm\task\update_grades();
 197                  $task->set_custom_data([
 198                      'scormid' => $scorm->id,
 199                      'userid' => $scorm->userid,
 200                  ]);
 201                  \core\task\manager::queue_adhoc_task($task, true);
 202              }
 203              $scorms->close();
 204          }
 205  
 206          // Scorm savepoint reached.
 207          upgrade_mod_savepoint(true, 2023100901, 'scorm');
 208      }
 209      return true;
 210  }