From 82605beaae7d41902272ec9cfbb41847ebab3ce8 Mon Sep 17 00:00:00 2001 From: piers Date: Thu, 7 Aug 2008 21:44:42 +0000 Subject: [PATCH] MDL-11188 SCORM module does not respect "prerequisites" like it used to. MDL-12342 & signs in CDATA sections are imported as &. This is a rewrite of the prerequisite handling. --- mod/scorm/datamodels/aicclib.php | 30 +--- mod/scorm/datamodels/scorm_12lib.php | 240 ++++++++++----------------- mod/scorm/datamodels/scorm_13lib.php | 33 +--- mod/scorm/locallib.php | 30 ++++ 4 files changed, 138 insertions(+), 195 deletions(-) diff --git a/mod/scorm/datamodels/aicclib.php b/mod/scorm/datamodels/aicclib.php index a4b55bbe04..908e7e2d5e 100644 --- a/mod/scorm/datamodels/aicclib.php +++ b/mod/scorm/datamodels/aicclib.php @@ -325,13 +325,11 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n // // Get the current organization infos // - $conditions = array(); if (!empty($currentorg)) { if (($organizationtitle = $DB->get_field('scorm_scoes','title', array('scorm'=>$scorm->id,'identifier'=>$currentorg))) != '') { $result->toc .= "\t
  • $organizationtitle
  • \n"; $tocmenus[] = $organizationtitle; } - $conditions['organization'] = $currentorg; } // // If not specified retrieve the last attempt number @@ -340,17 +338,14 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n $attempt = scorm_get_last_attempt($scorm->id, $user->id); } $result->attemptleft = $scorm->maxattempt - $attempt; - $conditions['scorm'] = $scorm->id; - if ($scoes = $DB->get_records('scorm_scoes', $conditions, "id ASC")){ - // drop keys so that we can access array sequentially - $scoes = array_values($scoes); + if ($scoes = scorm_get_scoes($scorm->id, $currentorg)){ // // Retrieve user tracking data for each learning object // $usertracks = array(); foreach ($scoes as $sco) { if (!empty($sco->launch)) { - if ($usertrack=scorm_get_tracks($sco->id,$user->id,$attempt)) { + if ($usertrack = scorm_get_tracks($sco->id,$user->id,$attempt)) { if ($usertrack->status == '') { $usertrack->status = 'notattempted'; } @@ -366,16 +361,12 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n $findnext = false; $parents[$level]='/'; - foreach ($scoes as $pos=>$sco) { + foreach ($scoes as $pos => $sco) { $isvisible = false; $sco->title = $sco->title; - if ($optionaldatas = scorm_get_sco($sco->id, SCO_DATA)) { - if (!isset($optionaldatas->isvisible) || (isset($optionaldatas->isvisible) && ($optionaldatas->isvisible == 'true'))) { - $isvisible = true; - } + if (!isset($sco->isvisible) || (isset($sco->isvisible) && ($sco->isvisible == 'true'))) { + $isvisible = true; } - else - $isvisible = true; if ($parents[$level]!=$sco->parent) { if ($newlevel = array_search($sco->parent,$parents)) { for ($i=0; $i<($level-$newlevel); $i++) { @@ -412,10 +403,8 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n $nextsco = false; } $nextisvisible = false; - if (($nextsco !== false) && ($optionaldatas = scorm_get_sco($nextsco->id, SCO_DATA))) { - if (!isset($optionaldatas->isvisible) || (isset($optionaldatas->isvisible) && ($optionaldatas->isvisible == 'true'))) { - $nextisvisible = true; - } + if (!isset($nextsco->isvisible) || (isset($nextsco->isvisible) && ($nextsco->isvisible == 'true'))) { + $nextisvisible = true; } if ($nextisvisible && ($nextsco !== false) && ($sco->parent != $nextsco->parent) && (($level==0) || (($level>0) && ($nextsco->parent == $sco->identifier)))) { $sublist++; @@ -472,12 +461,11 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n } } if ($sco->id == $scoid) { - $scodata = scorm_get_sco($sco->id, SCO_DATA); $startbold = ''; $endbold = ''; $findnext = true; - $shownext = isset($scodata->next) ? $scodata->next : 0; - $showprev = isset($scodata->previous) ? $scodata->previous : 0; + $shownext = isset($sco->next) ? $sco->next : 0; + $showprev = isset($sco->previous) ? $sco->previous : 0; } if (($nextid == 0) && (scorm_count_launchable($scorm->id,$currentorg) > 1) && ($nextsco!==false) && (!$findnext)) { diff --git a/mod/scorm/datamodels/scorm_12lib.php b/mod/scorm/datamodels/scorm_12lib.php index f6d9fa2901..1fa06728b3 100644 --- a/mod/scorm/datamodels/scorm_12lib.php +++ b/mod/scorm/datamodels/scorm_12lib.php @@ -1,6 +1,17 @@ 'notattempted' ); $i=0; - while ($istatus.'\' == \'completed\') || '. - '(\''.$usertracks[$element]->status.'\' == \'passed\'))'; - } else if (($operator = strpos($element,'=')) !== false) { - $item = trim(substr($element,0,$operator)); - if (!isset($usertracks[$item])) { - return false; - } - - $value = trim(trim(substr($element,$operator+1)),'"'); - if (isset($statuses[$value])) { - $status = $statuses[$value]; - } else { - return false; - } - - $element = '(\''.$usertracks[$item]->status.'\' == \''.$status.'\')'; - } else if (($operator = strpos($element,'<>')) !== false) { - $item = trim(substr($element,0,$operator)); - if (!isset($usertracks[$item])) { - return false; - } - - $value = trim(trim(substr($element,$operator+2)),'"'); - if (isset($statuses[$value])) { - $status = $statuses[$value]; - } else { - return false; - } - - $element = '(\''.$usertracks[$item]->status.'\' != \''.$status.'\')'; - } else if (is_numeric($element)) { - if ($symbol == '*') { - $symbol = ''; - $open = strpos($prerequisites,'{',$i); - $opened = 1; - $closed = 0; - for ($close=$open+1; (($opened > $closed) && ($close= $element) { - $element = 'true'; - } else { - $element = 'false'; - } - } - } else { - return false; - } - - array_push($stack,$element); - $element = ''; + + // expand the amp entities + $prerequisites = preg_replace('/&/', '&', $prerequisites); + // find all my parsable tokens + $prerequisites = preg_replace('/(&|\||\(|\)|\~)/', '\t$1\t', $prerequisites); + // expand operators + $prerequisites = preg_replace('/&/', '&&', $prerequisites); + $prerequisites = preg_replace('/\|/', '||', $prerequisites); + // now - grab all the tokens + $elements = explode('\t', trim($prerequisites)); + + // process each token to build an expression to be evaluated + $stack = array(); + foreach ($elements as $element) { + $element = trim($element); + if (empty($element)) { + continue; + } + if (!preg_match('/^(&&|\|\||\(|\))$/', $element)) { + // create each individual expression + // search for ~ = <> X*{} + + // sets like 3*{S34, S36, S37, S39} + if (preg_match('/^(\d+)\*\{(.+)\}$/', $element, $matches)) { + $repeat = $matches[1]; + $set = explode(',', $matches[2]); + $count = 0; + foreach ($set as $setelement) { + if (isset($usertracks[$setelement]) && + ($usertracks[$setelement]->status == 'completed' || $usertracks[$element]->status == 'passed')) { + $count++; + } } - if ($symbol == '~') { - $symbol = '!'; + if ($count >= $repeat) { + $element = 'true'; + } else { + $element = 'false'; } - if (!empty($symbol)) { - array_push($stack,$symbol); + + // ~ Not + } else if ($element == '~') { + $element = '!'; + + // = | <> + } else if (preg_match('/^(.+)(\=|\<\>)(.+)$/', $element, $matches)) { + $element = trim($matches[1]); + if (isset($usertracks[$element])) { + $value = trim(preg_replace('/(\'|\")/', '', $matches[3])); + if (isset($statuses[$value])) { + $value = $statuses[$value]; + } + if ($matches[2] == '<>') { + $oper = '!='; + } else { + $oper = '=='; + } + $element = '(\''.$usertracks[$element]->status.'\' '.$oper.' \''.$value.'\')'; + } else { + $element = 'false'; } - break; - default: - $element .= $symbol; - break; - } - $i++; - } - if (!empty($element)) { - $element = trim($element); - if (isset($usertracks[$element])) { - $element = '((\''.$usertracks[$element]->status.'\' == \'completed\') || '. - '(\''.$usertracks[$element]->status.'\' == \'passed\'))'; - } else if (($operator = strpos($element,'=')) !== false) { - $item = trim(substr($element,0,$operator)); - if (!isset($usertracks[$item])) { - return false; - } - - $value = trim(trim(substr($element,$operator+1)),'"'); - if (isset($statuses[$value])) { - $status = $statuses[$value]; - } else { - return false; - } - - $element = '(\''.$usertracks[$item]->status.'\' == \''.$status.'\')'; - } else if (($operator = strpos($element,'<>')) !== false) { - $item = trim(substr($element,0,$operator)); - if (!isset($usertracks[$item])) { - return false; - } - - $value = trim(trim(substr($element,$operator+1)),'"'); - if (isset($statuses[$value])) { - $status = $statuses[$value]; + + // everything else must be an element defined like S45 ... } else { - return false; + if (isset($usertracks[$element]) && + ($usertracks[$element]->status == 'completed' || $usertracks[$element]->status == 'passed')) { + $element = 'true'; + } else { + $element = 'false'; + } } - - $element = '(\''.$usertracks[$item]->status.'\' != \''.trim($status).'\')'; - } else { - return false; + } - - array_push($stack,$element); + $stack []= ' '.$element.' '; } return eval('return '.implode($stack).';'); } @@ -173,13 +125,11 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n // // Get the current organization infos // - $conditions = array();; if (!empty($currentorg)) { if (($organizationtitle = $DB->get_field('scorm_scoes','title', array('scorm'=>$scorm->id,'identifier'=>$currentorg))) != '') { $result->toc .= "\t
  • $organizationtitle
  • \n"; $tocmenus[] = $organizationtitle; } - $conditions['organization'] = $currentorg; } // // If not specified retrieve the last attempt number @@ -189,16 +139,14 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n } $result->attemptleft = $scorm->maxattempt - $attempt; $conditions['scorm'] = $scorm->id; - if ($scoes = $DB->get_records('scorm_scoes', $conditions, "id ASC")){ - // drop keys so that we can access array sequentially - $scoes = array_values($scoes); + if ($scoes = scorm_get_scoes($scorm->id, $currentorg)){ // // Retrieve user tracking data for each learning object // $usertracks = array(); foreach ($scoes as $sco) { if (!empty($sco->launch)) { - if ($usertrack=scorm_get_tracks($sco->id,$user->id,$attempt)) { + if ($usertrack = scorm_get_tracks($sco->id,$user->id,$attempt)) { if ($usertrack->status == '') { $usertrack->status = 'notattempted'; } @@ -214,18 +162,13 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n $findnext = false; $parents[$level]='/'; - foreach ($scoes as $pos=>$sco) { + foreach ($scoes as $pos => $sco) { $isvisible = false; $sco->title = $sco->title; - if ($optionaldatas = scorm_get_sco($sco->id, SCO_DATA)) { - if (!isset($optionaldatas->isvisible) || (isset($optionaldatas->isvisible) && ($optionaldatas->isvisible == 'true'))) { - $isvisible = true; - } - } - else{ + if (!isset($sco->isvisible) || (isset($sco->isvisible) && ($sco->isvisible == 'true'))) { $isvisible = true; } - if ($parents[$level]!=$sco->parent) { + if ($parents[$level] != $sco->parent) { if ($newlevel = array_search($sco->parent,$parents)) { for ($i=0; $i<($level-$newlevel); $i++) { $result->toc .= "\t\t\n"; @@ -249,7 +192,7 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n $result->toc .= $closelist; $level = $i; } - $parents[$level]=$sco->parent; + $parents[$level] = $sco->parent; } } if ($isvisible) { @@ -261,10 +204,8 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n $nextsco = false; } $nextisvisible = false; - if (($nextsco !== false) && ($optionaldatas = scorm_get_sco($nextsco->id, SCO_DATA))) { - if (!isset($optionaldatas->isvisible) || (isset($optionaldatas->isvisible) && ($optionaldatas->isvisible == 'true'))) { - $nextisvisible = true; - } + if (($nextsco !== false) && (!isset($nextsco->isvisible) || (isset($nextsco->isvisible) && ($nextsco->isvisible == 'true')))) { + $nextisvisible = true; } if ($nextisvisible && ($nextsco !== false) && ($sco->parent != $nextsco->parent) && (($level==0) || (($level>0) && ($nextsco->parent == $sco->identifier)))) { $sublist++; @@ -321,12 +262,11 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n } } if ($sco->id == $scoid) { - $scodata = scorm_get_sco($sco->id, SCO_DATA); $startbold = ''; $endbold = ''; $findnext = true; - $shownext = isset($scodata->next) ? $scodata->next : 0; - $showprev = isset($scodata->previous) ? $scodata->previous : 0; + $shownext = isset($sco->next) ? $sco->next : 0; + $showprev = isset($sco->previous) ? $sco->previous : 0; } if (($nextid == 0) && (scorm_count_launchable($scorm->id,$currentorg) > 1) && ($nextsco!==false) && (!$findnext)) { diff --git a/mod/scorm/datamodels/scorm_13lib.php b/mod/scorm/datamodels/scorm_13lib.php index 00d0f8b477..d6be35cd49 100644 --- a/mod/scorm/datamodels/scorm_13lib.php +++ b/mod/scorm/datamodels/scorm_13lib.php @@ -19,13 +19,11 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n // // Get the current organization infos // - $conditions = array(); if (!empty($currentorg)) { if (($organizationtitle = $DB->get_field('scorm_scoes', 'title', array('scorm'=>$scorm->id,'identifier'=>$currentorg))) != '') { $result->toc .= "\t
  • $organizationtitle
  • \n"; $tocmenus[] = $organizationtitle; } - $conditions['organization'] = $currentorg; } // // If not specified retrieve the last attempt number @@ -34,27 +32,20 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n $attempt = scorm_get_last_attempt($scorm->id, $user->id); } $result->attemptleft = $scorm->maxattempt - $attempt; - $conditions['scorm'] = $scorm->id; - if ($scoes = $DB->get_records('scorm_scoes', $conditions, "id ASC")){ - // drop keys so that we can access array sequentially - $scoes = array_values($scoes); + if ($scoes = scorm_get_scoes($scorm->id, $currentorg)){ // // Retrieve user tracking data for each learning object // $usertracks = array(); - $optionaldatas = array(); foreach ($scoes as $sco) { if (!empty($sco->launch)) { - if ($usertrack=scorm_get_tracks($sco->id,$user->id,$attempt)) { + if ($usertrack = scorm_get_tracks($sco->id,$user->id,$attempt)) { if ($usertrack->status == '') { $usertrack->status = 'notattempted'; } $usertracks[$sco->identifier] = $usertrack; } - if ($optionaldata = scorm_get_sco($sco->id, SCO_DATA)) { - $optionaldatas[$sco->identifier] = $optionaldata; - } } } @@ -64,14 +55,11 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n $nextid = 0; $findnext = false; $parents[$level]='/'; - foreach ($scoes as $pos=>$sco) { + foreach ($scoes as $pos => $sco) { $isvisible = false; $sco->title = $sco->title; - if (isset($optionaldatas[$sco->identifier])) { - if (!isset($optionaldatas[$sco->identifier]->isvisible) || - (isset($optionaldatas[$sco->identifier]->isvisible) && ($optionaldatas[$sco->identifier]->isvisible == 'true'))) { - $isvisible = true; - } + if (!isset($sco->isvisible) || (isset($sco->isvisible) && ($sco->isvisible == 'true'))) { + $isvisible = true; } if ($parents[$level]!=$sco->parent) { if ($newlevel = array_search($sco->parent,$parents)) { @@ -106,11 +94,8 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n $nextsco = false; } $nextisvisible = false; - if (($nextsco !== false) && (isset($optionaldatas[$nextsco->identifier]))) { - if (!isset($optionaldatas[$nextsco->identifier]->isvisible) || - (isset($optionaldatas[$nextsco->identifier]->isvisible) && ($optionaldatas[$nextsco->identifier]->isvisible == 'true'))) { - $nextisvisible = true; - } + if (!isset($nextsco->isvisible) || (isset($nextsco->isvisible) && ($nextsco->isvisible == 'true'))) { + $nextisvisible = true; } if ($nextisvisible && ($nextsco !== false) && ($sco->parent != $nextsco->parent) && (($level==0) || (($level>0) && ($nextsco->parent == $sco->identifier)))) { @@ -173,8 +158,8 @@ function scorm_get_toc($user,$scorm,$liststyle,$currentorg='',$scoid='',$mode='n $startbold = ''; $endbold = ''; $findnext = true; - $shownext = isset($optionaldatas[$sco->identifier]->next) ? $optionaldatas[$sco->identifier]->next : 0; - $showprev = isset($optionaldatas[$sco->identifier]->prev) ? $optionaldatas[$sco->identifier]->prev : 0; + $shownext = isset($sco->next) ? $sco->next : 0; + $showprev = isset($sco->prev) ? $sco->prev : 0; } if (($nextid == 0) && (scorm_count_launchable($scorm->id,$currentorg) > 1) && ($nextsco!==false) && (!$findnext)) { diff --git a/mod/scorm/locallib.php b/mod/scorm/locallib.php index 6aba694d06..1e2df68e16 100755 --- a/mod/scorm/locallib.php +++ b/mod/scorm/locallib.php @@ -202,6 +202,36 @@ function scorm_get_sco($id,$what=SCO_ALL) { return false; } } + +/** +* Returns an object (array) containing all the scoes data related to the given sco ID +* +* @param integer $id The sco ID +* @param integer $organisation an organisation ID - defaults to false if not required +* @return mixed (false if there are no scoes or an array) +*/ + +function scorm_get_scoes($id,$organisation=false) { + $organizationsql = ''; + if (!empty($organisation)) { + $organizationsql = "AND organization='$organisation'"; + } + if ($scoes = $DB->get_records_select('scorm_scoes',"scorm='$id' $organizationsql order by id ASC")) { + // drop keys so that it is a simple array as expected + $scoes = array_values($scoes); + foreach ($scoes as $sco) { + if ($scodatas = $DB->get_records('scorm_scoes_data','scoid',$sco->id)) { + foreach ($scodatas as $scodata) { + $sco->{$scodata->name} = stripslashes_safe($scodata->value); + } + } + } + return $scoes; + } else { + return false; + } +} + function scorm_insert_track($userid,$scormid,$scoid,$attempt,$element,$value) { global $DB; -- 2.39.5