MDL-43541 SCORM: set first launchable sco correctly.
authorDan Marsden <dan@danmarsden.com>
Tue, 28 Jan 2014 01:15:31 +0000 (14:15 +1300)
committerDan Marsden <dan@danmarsden.com>
Mon, 17 Feb 2014 06:56:40 +0000 (19:56 +1300)
mod/scorm/datamodels/aicclib.php
mod/scorm/datamodels/scormlib.php
mod/scorm/db/upgrade.php
mod/scorm/locallib.php
mod/scorm/version.php

index 4675494..da1ef1c 100644 (file)
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
+/**
+ * functions used by AICC packages.
+ *
+ * @package    mod_scorm
+ * @copyright 1999 onwards Roberto Pinna
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
 function scorm_add_time($a, $b) {
     $aes = explode(':', $a);
     $bes = explode(':', $b);
@@ -106,8 +114,14 @@ function scorm_forge_cols_regexp($columns, $remodule='(".*")?,') {
     return $regexp;
 }
 
+/**
+ * Sets up AICC packages
+ * Called whenever package changes
+ * @param object $scorm instance - fields are updated and changes saved into database
 
-function scorm_parse_aicc($scorm) {
+ * @return bool
+ */
+function scorm_parse_aicc(&$scorm) {
     global $DB;
 
     if ($scorm->scormtype == SCORM_TYPE_AICCURL) {
@@ -359,9 +373,18 @@ function scorm_parse_aicc($scorm) {
         }
     }
 
-    $scorm->version = 'AICC';
+    // Find first launchable object.
+    $sqlselect = 'scorm = ? AND '.$DB->sql_isnotempty('scorm_scoes', 'launch', false, true);
+    // We use get_records here as we need to pass a limit in the query that works cross db.
+    $scoes = $DB->get_records_select('scorm_scoes', $sqlselect, array($scorm->id), 'sortorder', 'id', 0, 1);
+    if (!empty($scoes)) {
+        $sco = reset($scoes); // We only care about the first record - the above query only returns one.
+        $scorm->launch = $sco->id;
+    } else {
+        $scorm->launch = $launch;
+    }
 
-    $scorm->launch = $launch;
+    $scorm->version = 'AICC';
 
     return true;
 }
index 91ef6d8..b8b14e9 100644 (file)
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
+/**
+ * functions used by SCORM 1.2/2004 packages.
+ *
+ * @package    mod_scorm
+ * @copyright 1999 onwards Roberto Pinna
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
 function scorm_get_resources($blocks) {
     $resources = array();
     foreach ($blocks as $block) {
@@ -503,7 +511,14 @@ function scorm_get_manifest($blocks, $scoes) {
     return $scoes;
 }
 
-function scorm_parse_scorm($scorm, $manifest) {
+/**
+ * Sets up SCORM 1.2/2004 packages using the manifest file.
+ * Called whenever SCORM changes
+ * @param object $scorm instance - fields are updated and changes saved into database
+ * @param stored_file|string $manifest - path to manifest file or stored_file.
+ * @return bool
+ */
+function scorm_parse_scorm(&$scorm, $manifest) {
     global $CFG, $DB;
 
     // load manifest into string
@@ -514,7 +529,8 @@ function scorm_parse_scorm($scorm, $manifest) {
         $xmltext = download_file_content($manifest);
     }
 
-    $launch = 0;
+    $defaultorgid = 0;
+    $firstinorg = 0;
 
     $pattern = '/&(?!\w{2,6};)/';
     $replacement = '&amp;';
@@ -525,6 +541,7 @@ function scorm_parse_scorm($scorm, $manifest) {
     $scoes = new stdClass();
     $scoes->version = '';
     $scoes = scorm_get_manifest($manifests, $scoes);
+    $newscoes = array();
     $sortorder = 0;
     if (count($scoes->elements) > 0) {
         $olditems = $DB->get_records('scorm_scoes', array('scorm'=>$scorm->id));
@@ -547,6 +564,10 @@ function scorm_parse_scorm($scorm, $manifest) {
                         }
                     }
 
+                    if (!empty($defaultorgid) && empty($firstinorg) && $newitem->parent == $scoes->defaultorg) {
+                        $firstinorg = $sortorder;
+                    }
+
                     if (!empty($olditems) && ($olditemid = scorm_array_search('identifier', $newitem->identifier, $olditems))) {
                         $newitem->id = $olditemid;
                         // Update the Sco sortorder but keep id so that user tracks are kept against the same ids.
@@ -567,6 +588,7 @@ function scorm_parse_scorm($scorm, $manifest) {
                         // Insert the new SCO, and retain the link between the old and new for later adjustment
                         $id = $DB->insert_record('scorm_scoes', $newitem);
                     }
+                    $newscoes[$id] = $newitem; // Save this sco in memory so we can use it later.
 
                     if ($optionaldatas = scorm_optionals_data($item, $standarddatas)) {
                         $data = new stdClass();
@@ -651,8 +673,8 @@ function scorm_parse_scorm($scorm, $manifest) {
                             }
                         }
                     }
-                    if (($launch == 0) && ((empty($scoes->defaultorg)) || ($scoes->defaultorg == $identifier))) {
-                        $launch = $id;
+                    if (empty($defaultorgid) && ((empty($scoes->defaultorg)) || ($scoes->defaultorg == $identifier))) {
+                        $defaultorgid = $id;
                     }
                 }
             }
@@ -673,11 +695,34 @@ function scorm_parse_scorm($scorm, $manifest) {
         if (empty($scoes->version)) {
             $scoes->version = 'SCORM_1.2';
         }
-        $DB->set_field('scorm', 'version', $scoes->version, array('id'=>$scorm->id));
+        $DB->set_field('scorm', 'version', $scoes->version, array('id' => $scorm->id));
         $scorm->version = $scoes->version;
     }
-
-    $scorm->launch = $launch;
+    $scorm->launch = 0;
+    // Check launch sco is valid.
+    if (!empty($defaultorgid) && isset($newscoes[$defaultorgid]) && !empty($newscoes[$defaultorgid]->launch)) {
+        // Launch param is valid - do nothing.
+        $scorm->launch = $defaultorgid;
+    } else if (!empty($defaultorgid) && isset($newscoes[$defaultorgid]) && empty($newscoes[$defaultorgid]->launch)) {
+        // The launch is probably the default org so we need to find the first launchable item inside this org.
+        $sqlselect = 'scorm = ? AND sortorder > ? AND '.$DB->sql_isnotempty('scorm_scoes', 'launch', false, true);
+        // We use get_records here as we need to pass a limit in the query that works cross db.
+        $scoes = $DB->get_records_select('scorm_scoes', $sqlselect, array($scorm->id, $firstinorg), 'sortorder', 'id', 0, 1);
+        if (!empty($scoes)) {
+            $sco = reset($scoes); // We only care about the first record - the above query only returns one.
+            $scorm->launch = $sco->id;
+        }
+    }
+    if (empty($scorm->launch)) {
+        // No valid Launch is specified - find the first launchable sco instead.
+        $sqlselect = 'scorm = ? AND '.$DB->sql_isnotempty('scorm_scoes', 'launch', false, true);
+        // We use get_records here as we need to pass a limit in the query that works cross db.
+        $scoes = $DB->get_records_select('scorm_scoes', $sqlselect, array($scorm->id), 'sortorder', 'id', 0, 1);
+        if (!empty($scoes)) {
+            $sco = reset($scoes); // We only care about the first record - the above query only returns one.
+            $scorm->launch = $sco->id;
+        }
+    }
 
     return true;
 }
index 785f9bb..7275d42 100644 (file)
@@ -17,9 +17,8 @@
 /**
  * Upgrade script for the scorm module.
  *
- * @package    mod
- * @subpackage scorm
- * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @package    mod_scorm
+ * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
@@ -203,6 +202,55 @@ function xmldb_scorm_upgrade($oldversion) {
         upgrade_mod_savepoint(true, 2013110501, 'scorm');
     }
 
+    if ($oldversion < 2014021700) {
+        // Fix invalid $scorm->launch records that launch an org sco instead of a real sco.
+        $sql = "SELECT s.*, c.identifier
+                 FROM {scorm} s
+            LEFT JOIN {scorm_scoes} c ON s.launch = c.id
+                WHERE ".$DB->sql_isempty('scorm_scoes', 'c.launch', false, true);
+        $scorms = $DB->get_recordset_sql($sql);
+        foreach ($scorms as $scorm) {
+            upgrade_set_timeout(60);  // Increase execution time just in case. (60 sec is minimum but prob excessive here).
+            $originallaunch = $scorm->launch;
+            // Find the first sco using the current identifier as it's parent
+            // we use get records here as we need to pass a limit in the query that works cross db.
+            $firstsco = $DB->get_records('scorm_scoes',
+                                         array('scorm' => $scorm->id, 'parent' => $scorm->identifier), 'sortorder', '*', 0, 1);
+            if (!empty($firstsco)) {
+                $firstsco = reset($firstsco);
+            }
+            if (!empty($firstsco->launch)) {
+                // Usual behavior - this is a valid sco with a launch param so use it.
+                $scorm->launch = $firstsco->id;
+            } else {
+                // The firstsco found is not launchable - find the first launchable sco after this sco.
+                $sqlselect = 'scorm = ? AND sortorder > ? AND '.$DB->sql_isnotempty('scorm_scoes', 'launch', false, true);
+                // We use get_records here as we need to pass a limit in the query that works cross db.
+                $scoes = $DB->get_records_select('scorm_scoes', $sqlselect,
+                                                 array($scorm->id, $firstsco->sortorder), 'sortorder', 'id', 0, 1);
+                if (!empty($scoes)) {
+                    $sco = reset($scoes); // We only care about the first record - the above query only returns one.
+                    $scorm->launch = $sco->id;
+                } else {
+                    // This is an invalid package - it has a default org that doesn't contain a launchable sco.
+                    // Check for any valid sco with a launch param.
+                    $sqlselect = 'scorm = ? AND '.$DB->sql_isnotempty('scorm_scoes', 'launch', false, true);
+                    // We use get_records here as we need to pass a limit in the query that works cross db.
+                    $scoes = $DB->get_records_select('scorm_scoes', $sqlselect, array($scorm->id), 'sortorder', 'id', 0, 1);
+                    if (!empty($scoes)) {
+                        $sco = reset($scoes); // We only care about the first record - the above query only returns one.
+                        $scorm->launch = $sco->id;
+                    }
+                }
+            }
+            if ($originallaunch != $scorm->launch) {
+                $DB->update_record('scorm', $scorm);
+            }
+        }
+        $scorms->close();
+
+        upgrade_mod_savepoint(true, 2014021700, 'scorm');
+    }
     return true;
 }
 
index eb77ac3..bd3bf47 100644 (file)
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
+/**
+ * Library of internal classes and functions for module SCORM
+ *
+ * @package    mod_scorm
+ * @copyright  1999 onwards Roberto Pinna
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
 require_once("$CFG->dirroot/mod/scorm/lib.php");
 require_once("$CFG->libdir/filelib.php");
 
@@ -897,7 +905,7 @@ function scorm_view_display ($user, $scorm, $action, $cm) {
         }
         ?>
               <br />
-              <input type="hidden" name="scoid"/>
+              <input type="hidden" name="scoid" value="<?php echo $scorm->launch ?>" />
               <input type="hidden" name="cm" value="<?php echo $cm->id ?>"/>
               <input type="hidden" name="currentorg" value="<?php echo $orgidentifier ?>" />
               <input type="submit" value="<?php print_string('enter', 'scorm') ?>" />
index 5d370b0..d384c6b 100644 (file)
 /**
  * scorm version information.
  *
- * @package    mod
- * @subpackage scorm
+ * @package    mod_scorm
  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2013110501;       // The current module version (Date: YYYYMMDDXX)
+$plugin->version   = 2014021700;       // The current module version (Date: YYYYMMDDXX)
 $plugin->requires  = 2013110500;    // Requires this Moodle version
 $plugin->component = 'mod_scorm'; // Full name of the plugin (used for diagnostics)
 $plugin->cron      = 300;