Moodle
  1. Moodle
  2. MDL-13904

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

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major 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
    • Rank:
      30427

      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.

        Issue Links

          Activity

          Hide
          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
          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
          Dan Marsden added a comment -

          Hi there,

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

          Dan

          Show
          Dan Marsden added a comment - Hi there, what have you set for the "Auto-update frequency" in your scorm object? Dan
          Hide
          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
          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
          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
          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
          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
          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
          Dan Marsden added a comment -

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

          thanks,

          Dan

          Show
          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 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 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 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 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 Harding added a comment -

          Fixed in HEAD, 1.9, and 1.8.

          Show
          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: