Uploaded image for project: 'Moodle'
  1. Moodle
  2. MDL-13904

Scorm structure isn't respected after an update of the package

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 1.8.2
    • Fix Version/s: 1.8.7, 1.9.3, 2.0
    • Component/s: SCORM
    • Labels:
      None
    • Environment:
      Windows / Linux, Apache, PHP 4.3.9, MySQL
    • Database:
      Any
    • Affected Branches:
      MOODLE_18_STABLE
    • Fixed Branches:
      MOODLE_18_STABLE, MOODLE_19_STABLE, MOODLE_20_STABLE

      Description

      When a update is done for a Scorm activity with a new package containing a new item inserted in the old structure, this item always appears at the end of the structure list. (see screenshot in attachment)

      This bug is very critic for users of Scorm activities because we must deleted the activity to put the new version (with the desired structure) suppressing the associated tracking...

      I'm looking for an issue to this bug, i think the problem is in the structure list update.

        Gliffy Diagrams

          Issue Links

            Activity

            Hide
            toinoo antoine faget added a comment -

            I tracked down the origin of the bug. Indeed, during the update of Scorm, the new scos see each other attributed one ID in the data base following ID of the last one Sco composing the ancient package. "Structure List" being built according to ID of scoes in the data base thus adds irreparably the scoes new at the end of the arborescence.

            Ideally, the arborescence should be built according to the imsmanifest.xml file of scorm or during an update package, ID should be updated to respect the order of items such as defined in the imsmanifest what involves an update of ID in at least three tables (mdl_scorm_scoes, mdl_scorm_scoes_data and mdl_scorm_scoes_track).

            I'm looking for code modification to assure this functionality. Any suggestion / help will be welcome

            Cordially yours.

            Show
            toinoo antoine faget added a comment - I tracked down the origin of the bug. Indeed, during the update of Scorm, the new scos see each other attributed one ID in the data base following ID of the last one Sco composing the ancient package. "Structure List" being built according to ID of scoes in the data base thus adds irreparably the scoes new at the end of the arborescence. Ideally, the arborescence should be built according to the imsmanifest.xml file of scorm or during an update package, ID should be updated to respect the order of items such as defined in the imsmanifest what involves an update of ID in at least three tables (mdl_scorm_scoes, mdl_scorm_scoes_data and mdl_scorm_scoes_track). I'm looking for code modification to assure this functionality. Any suggestion / help will be welcome Cordially yours.
            Hide
            danmarsden Dan Marsden added a comment -

            Hi there,

            what have you set for the "Auto-update frequency" in your scorm object?

            Dan

            Show
            danmarsden Dan Marsden added a comment - Hi there, what have you set for the "Auto-update frequency" in your scorm object? Dan
            Hide
            toinoo antoine faget added a comment - - edited

            Hi Dan,

            The parameter "Auto-update frequency" is set on "Never", but after some test with this parameter, the result is the same at the difference that the update is automatically done... :o(

            Antoine

            Show
            toinoo antoine faget added a comment - - edited Hi Dan, The parameter "Auto-update frequency" is set on "Never", but after some test with this parameter, the result is the same at the difference that the update is automatically done... :o( Antoine
            Hide
            toinoo antoine faget added a comment - - edited

            Good news,

            I solve a part of this bug, ordering the structure list. To do that i use two functions added in mod/scorm/datamodels/scormlib.php called in the function scorm_get_toc in the mod/scorm/datamodels/scormlib_12.php. This hack solve the bug for scorm 1.2 package only :

            mod/scorm/datamodels/scormlib_12.php :
            line1:
            ++ require_once('scormlib.php');
            == function scorm_eval_prerequisites($prerequisites,$usertracks) {

            in function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='normal',$attempt='',$play=false) near the line 215:
            ++ $ordered_table = list_item_manifest($scorm);
            ++ if(count($ordered_table)!=0)$scoes = reorder_scoes($scoes,$ordered_table);
            == foreach ($scoes as $sco) {
            == $isvisible = false;
            == if ($optionaldatas = scorm_get_sco($sco->id, SCO_DATA)) {

            mod/scorm/datamodels/scormlib.php :
            //insert these 2 functions at the end of the file

            function list_item_manifest($scorm){
            global $CFG;

            $orderedItems = array();

            $manifestfile = $CFG->dataroot.'\\'.$scorm->course.'\\moddata\\scorm
            '.$scorm->id.'/imsmanifest.xml';
            $manifestfile = str_ireplace('
            ','/',$manifestfile);

            if (is_file($manifestfile)) {
            $xmltext = file_get_contents($manifestfile);
            $pattern = '/&(?!\w

            {2,6}

            /';
            $replacement = '&';
            $xmltext = preg_replace($pattern, $replacement, $xmltext);
            $objXML = new xml2Array();
            $manifests = $objXML->parse($xmltext);
            $scoes = new stdClass();
            $scoes->version = '';
            $scoes = scorm_get_manifest($manifests,$scoes);
            foreach ($scoes->elements as $manifest => $organizations) {
            foreach ($organizations as $organization => $items) {
            foreach ($items as $identifier => $item) {
            $newitem = new stdClass();
            $newitem->manifest = $manifest;
            $newitem->organization = $organization;
            $standarddatas = array('parent', 'identifier', 'launch', 'scormtype', 'title');
            foreach ($standarddatas as $standarddata)

            { $newitem->$standarddata = addslashes($item->$standarddata); }

            array_push($orderedItems, $newitem->identifier);
            }
            }
            }
            }
            return $orderedItems;
            }
            function reorder_scoes($scoes, $orderedItems){
            $i=0;
            $scoes_res=array();
            while($i<count($orderedItems)){
            foreach($scoes as $sco){
            if($sco->identifier == $orderedItems[$i])

            { $scoes_res[]=$sco; }

            }
            $i++;
            }
            return $scoes_res;
            }

            This hack doesn't solve all problems due to the bug, for example in the report page, the order is not respected....
            I'm working on this point.

            Cordially

            Antoine

            Show
            toinoo antoine faget added a comment - - edited Good news, I solve a part of this bug, ordering the structure list. To do that i use two functions added in mod/scorm/datamodels/scormlib.php called in the function scorm_get_toc in the mod/scorm/datamodels/scormlib_12.php. This hack solve the bug for scorm 1.2 package only : mod/scorm/datamodels/scormlib_12.php : line1: ++ require_once('scormlib.php'); == function scorm_eval_prerequisites($prerequisites,$usertracks) { in function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='normal',$attempt='',$play=false) near the line 215: ++ $ordered_table = list_item_manifest($scorm); ++ if(count($ordered_table)!=0)$scoes = reorder_scoes($scoes,$ordered_table); == foreach ($scoes as $sco) { == $isvisible = false; == if ($optionaldatas = scorm_get_sco($sco->id, SCO_DATA)) { mod/scorm/datamodels/scormlib.php : //insert these 2 functions at the end of the file function list_item_manifest($scorm){ global $CFG; $orderedItems = array(); $manifestfile = $CFG->dataroot.'\\'.$scorm->course.'\\moddata\\scorm '.$scorm->id.'/imsmanifest.xml'; $manifestfile = str_ireplace(' ','/',$manifestfile); if (is_file($manifestfile)) { $xmltext = file_get_contents($manifestfile); $pattern = '/&(?!\w {2,6} /'; $replacement = '&'; $xmltext = preg_replace($pattern, $replacement, $xmltext); $objXML = new xml2Array(); $manifests = $objXML->parse($xmltext); $scoes = new stdClass(); $scoes->version = ''; $scoes = scorm_get_manifest($manifests,$scoes); foreach ($scoes->elements as $manifest => $organizations) { foreach ($organizations as $organization => $items) { foreach ($items as $identifier => $item) { $newitem = new stdClass(); $newitem->manifest = $manifest; $newitem->organization = $organization; $standarddatas = array('parent', 'identifier', 'launch', 'scormtype', 'title'); foreach ($standarddatas as $standarddata) { $newitem->$standarddata = addslashes($item->$standarddata); } array_push($orderedItems, $newitem->identifier); } } } } return $orderedItems; } function reorder_scoes($scoes, $orderedItems){ $i=0; $scoes_res=array(); while($i<count($orderedItems)){ foreach($scoes as $sco){ if($sco->identifier == $orderedItems [$i] ) { $scoes_res[]=$sco; } } $i++; } return $scoes_res; } This hack doesn't solve all problems due to the bug, for example in the report page, the order is not respected.... I'm working on this point. Cordially Antoine
            Hide
            toinoo antoine faget added a comment -

            To complete this hack, add the require_once('./datamodels/scormlib.php'); instruction at the top of the file and do the call to this 2 function in the moodle/mod/scorm/report.php line 153, after the $scoes implementation:

            == if ($scoes = get_records_select('scorm_scoes',"scorm='$scorm->id' ORDER BY id")) {
            ++ $ordered_table = list_item_manifest($scorm);
            ++ if(count($ordered_table)!=0)$scoes = reorder_scoes($scoes,$ordered_table);

            I think this hack solves completely the bug for scorm 1.2 packages. ;op

            Cordially yours__

            Show
            toinoo antoine faget added a comment - To complete this hack, add the require_once('./datamodels/scormlib.php'); instruction at the top of the file and do the call to this 2 function in the moodle/mod/scorm/report.php line 153, after the $scoes implementation: == if ($scoes = get_records_select('scorm_scoes',"scorm='$scorm->id' ORDER BY id")) { ++ $ordered_table = list_item_manifest($scorm); ++ if(count($ordered_table)!=0)$scoes = reorder_scoes($scoes,$ordered_table); I think this hack solves completely the bug for scorm 1.2 packages. ;op Cordially yours__
            Hide
            danmarsden Dan Marsden added a comment -

            Hi Piers - haven't looked at this, but is this solved with the ksort you added?

            thanks,

            Dan

            Show
            danmarsden Dan Marsden added a comment - Hi Piers - haven't looked at this, but is this solved with the ksort you added? thanks, Dan
            Hide
            piers Piers Harding added a comment -

            There are several things that could be changed with how SCORM package updates work:

            currently SCORM package updates appear to only happen either via the EVERY_TIME check on a launch, or with the EVERY_DAY check via the cron. These require the orriginal package upload location file to change it's MD5 checksum, to work.

            I am not sure that these triggers offer the best flexability (eg. there could be a bulk check button, or an obvious update button in the user config - could do with some user input on this point ).

            Secondly - the update does not preserve track data, so all user interactions are lost.

            I think to improve this situation, what needs to happen on the package update, is the scoids get created a new, but the corresponding user track data gets remapped to these new ids. This will both fix the sequencing issues, and give continuity with user data (and their scoring etc).
            Cheers,
            Piers Harding.

            Show
            piers Piers Harding added a comment - There are several things that could be changed with how SCORM package updates work: currently SCORM package updates appear to only happen either via the EVERY_TIME check on a launch, or with the EVERY_DAY check via the cron. These require the orriginal package upload location file to change it's MD5 checksum, to work. I am not sure that these triggers offer the best flexability (eg. there could be a bulk check button, or an obvious update button in the user config - could do with some user input on this point ). Secondly - the update does not preserve track data, so all user interactions are lost. I think to improve this situation, what needs to happen on the package update, is the scoids get created a new, but the corresponding user track data gets remapped to these new ids. This will both fix the sequencing issues, and give continuity with user data (and their scoring etc). Cheers, Piers Harding.
            Hide
            piers Piers Harding added a comment -

            I have patched HEAD with a change that should simplify the package update process, while attempting to preserve the TRACK data for the component SCOES.
            When a package is updated:

            • all SCOs are issued with new IDs
            • a map of old to new IDs is generated
            • all old IDs are cycled through and if SCORM_SCOES_TRACK records are found then they are remapped to the new ID for the SCO
            • all old ID records are deleted for:
              scorm_scoes
              scorm_scoes_data
              scorm_scoes_track
              scorm_seq_objective
              scorm_seq_mapinfo
              scorm_seq_ruleconds
              scorm_seq_rulecond
              scorm_seq_rolluprule
              scorm_seq_rollupcond

            Cheers,
            Piers Harding.

            Show
            piers Piers Harding added a comment - I have patched HEAD with a change that should simplify the package update process, while attempting to preserve the TRACK data for the component SCOES. When a package is updated: all SCOs are issued with new IDs a map of old to new IDs is generated all old IDs are cycled through and if SCORM_SCOES_TRACK records are found then they are remapped to the new ID for the SCO all old ID records are deleted for: scorm_scoes scorm_scoes_data scorm_scoes_track scorm_seq_objective scorm_seq_mapinfo scorm_seq_ruleconds scorm_seq_rulecond scorm_seq_rolluprule scorm_seq_rollupcond Cheers, Piers Harding.
            Hide
            piers Piers Harding added a comment -

            Fixed in HEAD, 1.9, and 1.8.

            Show
            piers Piers Harding added a comment - Fixed in HEAD, 1.9, and 1.8.

              People

              • Votes:
                1 Vote for this issue
                Watchers:
                3 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:
                  Fix Release Date:
                  15/Oct/08