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

          Attachments

            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