2009-11-01 15:24:58 +00:00
< ? php
2011-06-30 14:59:08 +12:00
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
2006-08-10 11:32:48 +00:00
2008-09-09 08:30:00 +00:00
require_once ( " $CFG->dirroot /mod/scorm/lib.php " );
2010-07-03 13:37:13 +00:00
require_once ( " $CFG->libdir /filelib.php " );
2008-09-09 08:30:00 +00:00
2006-09-26 07:56:07 +00:00
/// Constants and settings for module scorm
2012-02-16 12:16:02 +13:00
define ( 'SCORM_UPDATE_NEVER' , '0' );
define ( 'SCORM_UPDATE_EVERYDAY' , '2' );
define ( 'SCORM_UPDATE_EVERYTIME' , '3' );
2007-01-24 10:39:24 +00:00
2006-11-21 16:12:19 +00:00
define ( 'SCO_ALL' , 0 );
define ( 'SCO_DATA' , 1 );
define ( 'SCO_ONLY' , 2 );
2006-09-26 07:56:07 +00:00
define ( 'GRADESCOES' , '0' );
define ( 'GRADEHIGHEST' , '1' );
define ( 'GRADEAVERAGE' , '2' );
define ( 'GRADESUM' , '3' );
define ( 'HIGHESTATTEMPT' , '0' );
define ( 'AVERAGEATTEMPT' , '1' );
define ( 'FIRSTATTEMPT' , '2' );
define ( 'LASTATTEMPT' , '3' );
2011-01-28 22:38:08 +13:00
define ( 'TOCJSLINK' , 1 );
define ( 'TOCFULLURL' , 2 );
2008-09-09 08:30:00 +00:00
/// Local Library of functions for module scorm
2006-09-26 07:56:07 +00:00
2010-07-03 13:37:13 +00:00
/**
* @ 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
*/
class scorm_package_file_info extends file_info_stored {
public function get_parent () {
if ( $this -> lf -> get_filepath () === '/' and $this -> lf -> get_filename () === '.' ) {
return $this -> browser -> get_file_info ( $this -> context );
}
return parent :: get_parent ();
}
public function get_visible_name () {
if ( $this -> lf -> get_filepath () === '/' and $this -> lf -> get_filename () === '.' ) {
return $this -> topvisiblename ;
}
return parent :: get_visible_name ();
}
}
2008-11-11 02:46:20 +00:00
/**
* Returns an array of the popup options for SCORM and each options default value
2008-11-29 17:51:47 +00:00
*
2008-11-11 02:46:20 +00:00
* @ return array an array of popup options as the key and their defaults as the value
*/
2011-06-30 16:55:16 +12:00
function scorm_get_popup_options_array () {
2008-11-11 02:46:20 +00:00
global $CFG ;
$cfg_scorm = get_config ( 'scorm' );
2008-11-29 17:51:47 +00:00
return array ( 'resizable' => isset ( $cfg_scorm -> resizable ) ? $cfg_scorm -> resizable : 0 ,
'scrollbars' => isset ( $cfg_scorm -> scrollbars ) ? $cfg_scorm -> scrollbars : 0 ,
'directories' => isset ( $cfg_scorm -> directories ) ? $cfg_scorm -> directories : 0 ,
2008-11-11 04:45:39 +00:00
'location' => isset ( $cfg_scorm -> location ) ? $cfg_scorm -> location : 0 ,
2008-11-29 17:51:47 +00:00
'menubar' => isset ( $cfg_scorm -> menubar ) ? $cfg_scorm -> menubar : 0 ,
'toolbar' => isset ( $cfg_scorm -> toolbar ) ? $cfg_scorm -> toolbar : 0 ,
'status' => isset ( $cfg_scorm -> status ) ? $cfg_scorm -> status : 0 );
2008-11-11 02:46:20 +00:00
}
/**
* Returns an array of the array of what grade options
2008-11-29 17:51:47 +00:00
*
2008-11-11 02:46:20 +00:00
* @ return array an array of what grade options
*/
2011-06-30 16:55:16 +12:00
function scorm_get_grade_method_array () {
2008-11-11 02:46:20 +00:00
return array ( GRADESCOES => get_string ( 'gradescoes' , 'scorm' ),
GRADEHIGHEST => get_string ( 'gradehighest' , 'scorm' ),
GRADEAVERAGE => get_string ( 'gradeaverage' , 'scorm' ),
2008-11-29 17:51:47 +00:00
GRADESUM => get_string ( 'gradesum' , 'scorm' ));
2008-11-11 02:46:20 +00:00
}
/**
* Returns an array of the array of what grade options
2008-11-29 17:51:47 +00:00
*
2008-11-11 02:46:20 +00:00
* @ return array an array of what grade options
*/
2011-06-30 16:55:16 +12:00
function scorm_get_what_grade_array () {
2008-11-11 02:46:20 +00:00
return array ( HIGHESTATTEMPT => get_string ( 'highestattempt' , 'scorm' ),
AVERAGEATTEMPT => get_string ( 'averageattempt' , 'scorm' ),
FIRSTATTEMPT => get_string ( 'firstattempt' , 'scorm' ),
LASTATTEMPT => get_string ( 'lastattempt' , 'scorm' ));
}
/**
* Returns an array of the array of skip view options
2008-11-29 17:51:47 +00:00
*
2008-11-11 02:46:20 +00:00
* @ return array an array of skip view options
*/
2011-06-30 16:55:16 +12:00
function scorm_get_skip_view_array () {
return array ( 0 => get_string ( 'never' ),
1 => get_string ( 'firstaccess' , 'scorm' ),
2008-11-11 02:46:20 +00:00
2 => get_string ( 'always' ));
}
/**
* Returns an array of the array of hide table of contents options
2008-11-29 17:51:47 +00:00
*
2008-11-11 02:46:20 +00:00
* @ return array an array of hide table of contents options
*/
2011-06-30 16:55:16 +12:00
function scorm_get_hidetoc_array () {
2011-07-19 00:25:13 +10:00
return array ( SCORM_TOC_SIDE => get_string ( 'sided' , 'scorm' ),
2011-07-13 19:00:33 +12:00
SCORM_TOC_HIDDEN => get_string ( 'hidden' , 'scorm' ),
SCORM_TOC_POPUP => get_string ( 'popupmenu' , 'scorm' ),
SCORM_TOC_DISABLED => get_string ( 'disabled' , 'scorm' ));
2008-11-11 02:46:20 +00:00
}
/**
* Returns an array of the array of update frequency options
2008-11-29 17:51:47 +00:00
*
2008-11-11 02:46:20 +00:00
* @ return array an array of update frequency options
*/
2011-06-30 16:55:16 +12:00
function scorm_get_updatefreq_array () {
2012-02-16 12:16:02 +13:00
return array ( SCORM_UPDATE_NEVER => get_string ( 'never' ),
SCORM_UPDATE_EVERYDAY => get_string ( 'everyday' , 'scorm' ),
SCORM_UPDATE_EVERYTIME => get_string ( 'everytime' , 'scorm' ));
2008-11-11 02:46:20 +00:00
}
/**
* Returns an array of the array of popup display options
2008-11-29 17:51:47 +00:00
*
2008-11-11 02:46:20 +00:00
* @ return array an array of popup display options
*/
2011-06-30 16:55:16 +12:00
function scorm_get_popup_display_array () {
2010-07-09 08:40:54 +00:00
return array ( 0 => get_string ( 'currentwindow' , 'scorm' ),
2008-11-11 02:46:20 +00:00
1 => get_string ( 'popup' , 'scorm' ));
}
/**
* Returns an array of the array of attempt options
2008-11-29 17:51:47 +00:00
*
2008-11-11 02:46:20 +00:00
* @ return array an array of attempt options
*/
2011-06-30 16:55:16 +12:00
function scorm_get_attempts_array () {
$attempts = array ( 0 => get_string ( 'nolimit' , 'scorm' ),
1 => get_string ( 'attempt1' , 'scorm' ));
2008-11-29 17:51:47 +00:00
2008-11-11 02:46:20 +00:00
for ( $i = 2 ; $i <= 6 ; $i ++ ) {
2011-06-30 16:55:16 +12:00
$attempts [ $i ] = get_string ( 'attemptsx' , 'scorm' , $i );
2008-11-11 02:46:20 +00:00
}
2008-11-29 17:51:47 +00:00
2008-11-11 02:46:20 +00:00
return $attempts ;
}
2008-09-09 08:30:00 +00:00
/**
* Extracts scrom package , sets up all variables .
* Called whenever scorm changes
* @ param object $scorm instance - fields are updated and changes saved into database
* @ param bool $full force full update if true
* @ return void
*/
function scorm_parse ( $scorm , $full ) {
global $CFG , $DB ;
2008-11-11 02:46:20 +00:00
$cfg_scorm = get_config ( 'scorm' );
2007-01-18 15:54:56 +00:00
2008-09-09 08:30:00 +00:00
if ( ! isset ( $scorm -> cmid )) {
$cm = get_coursemodule_from_instance ( 'scorm' , $scorm -> id );
$scorm -> cmid = $cm -> id ;
}
$context = get_context_instance ( CONTEXT_MODULE , $scorm -> cmid );
$newhash = $scorm -> sha1hash ;
2006-09-26 07:56:07 +00:00
2008-09-09 08:30:00 +00:00
if ( $scorm -> scormtype === SCORM_TYPE_LOCAL or $scorm -> scormtype === SCORM_TYPE_LOCALSYNC ) {
2006-09-26 07:56:07 +00:00
2008-09-09 08:30:00 +00:00
$fs = get_file_storage ();
$packagefile = false ;
2006-08-10 11:32:48 +00:00
2008-09-09 08:30:00 +00:00
if ( $scorm -> scormtype === SCORM_TYPE_LOCAL ) {
2010-07-03 13:37:13 +00:00
if ( $packagefile = $fs -> get_file ( $context -> id , 'mod_scorm' , 'package' , 0 , '/' , $scorm -> reference )) {
2008-09-09 08:30:00 +00:00
$newhash = $packagefile -> get_contenthash ();
} else {
$newhash = null ;
}
} else {
2008-11-11 02:46:20 +00:00
if ( ! $cfg_scorm -> allowtypelocalsync ) {
2008-09-09 08:30:00 +00:00
// sorry - localsync disabled
return ;
}
if ( $scorm -> reference !== '' and ( ! $full or $scorm -> sha1hash !== sha1 ( $scorm -> reference ))) {
2010-07-03 13:37:13 +00:00
$fs -> delete_area_files ( $context -> id , 'mod_scorm' , 'package' );
$file_record = array ( 'contextid' => $context -> id , 'component' => 'mod_scorm' , 'filearea' => 'package' , 'itemid' => 0 , 'filepath' => '/' );
2011-03-28 16:36:42 +08:00
if ( $packagefile = $fs -> create_file_from_url ( $file_record , $scorm -> reference , array ( 'calctimeout' => true ))) {
2008-09-09 08:30:00 +00:00
$newhash = sha1 ( $scorm -> reference );
2006-08-11 12:26:06 +00:00
} else {
2008-09-09 08:30:00 +00:00
$newhash = null ;
2006-08-11 12:26:06 +00:00
}
2006-08-10 11:32:48 +00:00
}
}
2008-09-09 08:30:00 +00:00
if ( $packagefile ) {
if ( ! $full and $packagefile and $scorm -> sha1hash === $newhash ) {
if ( strpos ( $scorm -> version , 'SCORM' ) !== false ) {
2010-07-03 13:37:13 +00:00
if ( $fs -> get_file ( $context -> id , 'mod_scorm' , 'content' , 0 , '/' , 'imsmanifest.xml' )) {
2008-09-09 08:30:00 +00:00
// no need to update
return ;
2006-07-23 23:48:09 +00:00
}
2008-09-09 08:30:00 +00:00
} else if ( strpos ( $scorm -> version , 'AICC' ) !== false ) {
// TODO: add more sanity checks - something really exists in scorm_content area
return ;
}
}
// now extract files
2010-07-03 13:37:13 +00:00
$fs -> delete_area_files ( $context -> id , 'mod_scorm' , 'content' );
2008-09-09 08:30:00 +00:00
$packer = get_file_packer ( 'application/zip' );
2010-07-03 13:37:13 +00:00
$packagefile -> extract_to_storage ( $packer , $context -> id , 'mod_scorm' , 'content' , 0 , '/' );
2008-09-09 08:30:00 +00:00
} else if ( ! $full ) {
return ;
}
2010-07-03 13:37:13 +00:00
if ( $manifest = $fs -> get_file ( $context -> id , 'mod_scorm' , 'content' , 0 , '/' , 'imsmanifest.xml' )) {
2008-09-09 08:30:00 +00:00
require_once ( " $CFG->dirroot /mod/scorm/datamodels/scormlib.php " );
// SCORM
if ( ! scorm_parse_scorm ( $scorm , $manifest )) {
$scorm -> version = 'ERROR' ;
}
} else {
require_once ( " $CFG->dirroot /mod/scorm/datamodels/aicclib.php " );
// AICC
if ( ! scorm_parse_aicc ( $scorm )) {
$scorm -> version = 'ERROR' ;
}
2011-11-05 21:51:24 +13:00
$scorm -> version = 'AICC' ;
2008-09-09 08:30:00 +00:00
}
2008-11-11 02:46:20 +00:00
} else if ( $scorm -> scormtype === SCORM_TYPE_EXTERNAL and $cfg_scorm -> allowtypeexternal ) {
2008-09-09 08:30:00 +00:00
if ( ! $full and $scorm -> sha1hash === sha1 ( $scorm -> reference )) {
return ;
}
require_once ( " $CFG->dirroot /mod/scorm/datamodels/scormlib.php " );
// SCORM only, AICC can not be external
if ( ! scorm_parse_scorm ( $scorm , $scorm -> reference )) {
$scorm -> version = 'ERROR' ;
}
$newhash = sha1 ( $scorm -> reference );
2008-11-11 02:46:20 +00:00
} else if ( $scorm -> scormtype === SCORM_TYPE_IMSREPOSITORY and ! empty ( $CFG -> repositoryactivate ) and $cfg_scorm -> allowtypeimsrepository ) {
2008-09-09 08:30:00 +00:00
if ( ! $full and $scorm -> sha1hash === sha1 ( $scorm -> reference )) {
return ;
}
require_once ( " $CFG->dirroot /mod/scorm/datamodels/scormlib.php " );
2011-06-30 16:55:16 +12:00
if ( ! scorm_parse_scorm ( $scorm , $CFG -> repository . substr ( $scorm -> reference , 1 ) . '/imsmanifest.xml' )) {
2008-09-09 08:30:00 +00:00
$scorm -> version = 'ERROR' ;
}
$newhash = sha1 ( $scorm -> reference );
2011-11-05 21:51:24 +13:00
} else if ( $scorm -> scormtype === SCORM_TYPE_AICCURL and $cfg_scorm -> allowtypeexternalaicc ) {
require_once ( " $CFG->dirroot /mod/scorm/datamodels/aicclib.php " );
// AICC
if ( ! scorm_parse_aicc ( $scorm )) {
$scorm -> version = 'ERROR' ;
}
$scorm -> version = 'AICC' ;
2006-07-23 23:48:09 +00:00
} else {
2008-09-09 08:30:00 +00:00
// sorry, disabled type
return ;
2006-07-23 23:48:09 +00:00
}
2008-09-09 08:30:00 +00:00
$scorm -> revision ++ ;
$scorm -> sha1hash = $newhash ;
$DB -> update_record ( 'scorm' , $scorm );
2006-07-23 23:48:09 +00:00
}
2008-09-09 08:30:00 +00:00
2006-08-31 08:34:13 +00:00
function scorm_array_search ( $item , $needle , $haystacks , $strict = false ) {
if ( ! empty ( $haystacks )) {
foreach ( $haystacks as $key => $element ) {
if ( $strict ) {
if ( $element -> { $item } === $needle ) {
return $key ;
}
} else {
if ( $element -> { $item } == $needle ) {
return $key ;
2006-07-23 23:48:09 +00:00
}
}
}
}
2006-08-31 08:34:13 +00:00
return false ;
2006-07-23 23:48:09 +00:00
}
2006-08-31 08:34:13 +00:00
function scorm_repeater ( $what , $times ) {
if ( $times <= 0 ) {
return null ;
}
$return = '' ;
2011-06-30 16:55:16 +12:00
for ( $i = 0 ; $i < $times ; $i ++ ) {
2006-08-31 08:34:13 +00:00
$return .= $what ;
}
return $return ;
}
2006-07-23 23:48:09 +00:00
2006-08-31 08:34:13 +00:00
function scorm_external_link ( $link ) {
2011-06-30 16:55:16 +12:00
// check if a link is external
2006-08-31 08:34:13 +00:00
$result = false ;
$link = strtolower ( $link );
2011-06-30 16:55:16 +12:00
if ( substr ( $link , 0 , 7 ) == 'http://' ) {
2006-08-31 08:34:13 +00:00
$result = true ;
2011-06-30 16:55:16 +12:00
} else if ( substr ( $link , 0 , 8 ) == 'https://' ) {
2006-08-31 08:34:13 +00:00
$result = true ;
2011-06-30 16:55:16 +12:00
} else if ( substr ( $link , 0 , 4 ) == 'www.' ) {
2006-08-31 08:34:13 +00:00
$result = true ;
}
return $result ;
2006-07-23 23:48:09 +00:00
}
2006-11-21 16:12:19 +00:00
/**
2011-06-30 16:55:16 +12:00
* Returns an object containing all datas relative to the given sco ID
*
* @ param integer $id The sco ID
* @ return mixed ( false if sco id does not exists )
*/
function scorm_get_sco ( $id , $what = SCO_ALL ) {
2008-06-05 10:02:26 +00:00
global $DB ;
if ( $sco = $DB -> get_record ( 'scorm_scoes' , array ( 'id' => $id ))) {
2006-11-21 16:12:19 +00:00
$sco = ( $what == SCO_DATA ) ? new stdClass () : $sco ;
2008-06-05 10:02:26 +00:00
if (( $what != SCO_ONLY ) && ( $scodatas = $DB -> get_records ( 'scorm_scoes_data' , array ( 'scoid' => $id )))) {
2006-11-21 16:12:19 +00:00
foreach ( $scodatas as $scodata ) {
2007-07-23 15:38:31 +00:00
$sco -> { $scodata -> name } = $scodata -> value ;
2006-11-21 16:12:19 +00:00
}
2008-06-05 10:02:26 +00:00
} else if (( $what != SCO_ONLY ) && ( ! ( $scodatas = $DB -> get_records ( 'scorm_scoes_data' , array ( 'scoid' => $id ))))) {
2008-09-09 08:30:00 +00:00
$sco -> parameters = '' ;
2006-11-21 16:12:19 +00:00
}
return $sco ;
} else {
return false ;
}
}
2008-08-07 21:44:42 +00:00
/**
2011-06-30 16:55:16 +12:00
* 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 ) {
2008-08-21 07:32:19 +00:00
global $DB ;
2008-08-07 21:44:42 +00:00
$organizationsql = '' ;
2008-08-21 07:32:19 +00:00
$queryarray = array ( 'scorm' => $id );
2008-08-07 21:44:42 +00:00
if ( ! empty ( $organisation )) {
2008-08-21 07:32:19 +00:00
$queryarray [ 'organization' ] = $organisation ;
2008-08-07 21:44:42 +00:00
}
2008-08-21 07:32:19 +00:00
if ( $scoes = $DB -> get_records ( 'scorm_scoes' , $queryarray , 'id ASC' )) {
2008-08-07 21:44:42 +00:00
// drop keys so that it is a simple array as expected
$scoes = array_values ( $scoes );
foreach ( $scoes as $sco ) {
2011-06-30 16:55:16 +12:00
if ( $scodatas = $DB -> get_records ( 'scorm_scoes_data' , array ( 'scoid' => $sco -> id ))) {
2008-08-07 21:44:42 +00:00
foreach ( $scodatas as $scodata ) {
2008-09-23 21:09:46 +00:00
$sco -> { $scodata -> name } = $scodata -> value ;
2008-08-07 21:44:42 +00:00
}
}
}
return $scoes ;
} else {
return false ;
}
}
2011-06-30 16:55:16 +12:00
function scorm_insert_track ( $userid , $scormid , $scoid , $attempt , $element , $value , $forcecompleted = false ) {
2010-05-06 00:13:54 +00:00
global $DB , $CFG ;
2008-06-05 10:02:26 +00:00
2006-07-23 23:48:09 +00:00
$id = null ;
2008-09-16 20:32:50 +00:00
if ( $forcecompleted ) {
//TODO - this could be broadened to encompass SCORM 2004 in future
if (( $element == 'cmi.core.lesson_status' ) && ( $value == 'incomplete' )) {
2011-06-30 16:55:16 +12:00
if ( $track = $DB -> get_record_select ( 'scorm_scoes_track' , 'userid=? AND scormid=? AND scoid=? AND attempt=? AND element=\'cmi.core.score.raw\'' , array ( $userid , $scormid , $scoid , $attempt ))) {
2008-09-16 20:32:50 +00:00
$value = 'completed' ;
}
}
if ( $element == 'cmi.core.score.raw' ) {
2011-06-30 16:55:16 +12:00
if ( $tracktest = $DB -> get_record_select ( 'scorm_scoes_track' , 'userid=? AND scormid=? AND scoid=? AND attempt=? AND element=\'cmi.core.lesson_status\'' , array ( $userid , $scormid , $scoid , $attempt ))) {
2008-09-16 20:32:50 +00:00
if ( $tracktest -> value == " incomplete " ) {
$tracktest -> value = " completed " ;
2011-06-30 16:55:16 +12:00
$DB -> update_record ( 'scorm_scoes_track' , $tracktest );
2008-09-16 20:32:50 +00:00
}
}
}
}
2011-06-30 16:55:16 +12:00
if ( $track = $DB -> get_record ( 'scorm_scoes_track' , array ( 'userid' => $userid , 'scormid' => $scormid , 'scoid' => $scoid , 'attempt' => $attempt , 'element' => $element ))) {
2010-04-29 08:31:45 +00:00
if ( $element != 'x.start.time' ) { //don't update x.start.time - keep the original value.
2011-03-21 21:13:52 +01:00
$track -> value = $value ;
2010-04-29 08:31:45 +00:00
$track -> timemodified = time ();
2011-06-30 16:55:16 +12:00
$DB -> update_record ( 'scorm_scoes_track' , $track );
2010-09-03 18:01:25 +00:00
$id = $track -> id ;
2010-04-29 08:31:45 +00:00
}
2006-07-23 23:48:09 +00:00
} else {
2012-05-08 08:59:54 +12:00
$track = new stdClass ();
2006-07-23 23:48:09 +00:00
$track -> userid = $userid ;
$track -> scormid = $scormid ;
$track -> scoid = $scoid ;
$track -> attempt = $attempt ;
$track -> element = $element ;
2011-03-21 21:13:52 +01:00
$track -> value = $value ;
2006-07-23 23:48:09 +00:00
$track -> timemodified = time ();
2011-06-30 16:55:16 +12:00
$id = $DB -> insert_record ( 'scorm_scoes_track' , $track );
2006-07-23 23:48:09 +00:00
}
2008-09-09 08:30:00 +00:00
if ( strstr ( $element , '.score.raw' ) ||
2011-06-10 13:26:15 +12:00
( in_array ( $element , array ( 'cmi.completion_status' , 'cmi.core.lesson_status' , 'cmi.success_status' ))
&& in_array ( $track -> value , array ( 'completed' , 'passed' )))) {
2008-08-24 21:10:09 +00:00
$scorm = $DB -> get_record ( 'scorm' , array ( 'id' => $scormid ));
2010-05-06 00:13:54 +00:00
include_once ( $CFG -> dirroot . '/mod/scorm/lib.php' );
2008-11-09 22:27:18 +00:00
scorm_update_grades ( $scorm , $userid );
2007-11-05 07:31:35 +00:00
}
2008-09-09 08:30:00 +00:00
2006-07-23 23:48:09 +00:00
return $id ;
}
2011-06-30 16:55:16 +12:00
function scorm_get_tracks ( $scoid , $userid , $attempt = '' ) {
/// Gets all tracks of specified sco and user
2008-06-05 10:02:26 +00:00
global $CFG , $DB ;
2006-07-23 23:48:09 +00:00
if ( empty ( $attempt )) {
2011-06-30 16:55:16 +12:00
if ( $scormid = $DB -> get_field ( 'scorm_scoes' , 'scorm' , array ( 'id' => $scoid ))) {
$attempt = scorm_get_last_attempt ( $scormid , $userid );
2006-07-23 23:48:09 +00:00
} else {
$attempt = 1 ;
}
}
2011-06-30 16:55:16 +12:00
if ( $tracks = $DB -> get_records ( 'scorm_scoes_track' , array ( 'userid' => $userid , 'scoid' => $scoid , 'attempt' => $attempt ), 'element ASC' )) {
2010-09-21 08:37:36 +00:00
$usertrack = new stdClass ();
2006-07-23 23:48:09 +00:00
$usertrack -> userid = $userid ;
2008-09-09 08:30:00 +00:00
$usertrack -> scoid = $scoid ;
2006-09-26 07:56:07 +00:00
// Defined in order to unify scorm1.2 and scorm2004
2006-07-23 23:48:09 +00:00
$usertrack -> score_raw = '' ;
$usertrack -> status = '' ;
2012-06-28 14:49:47 +08:00
$usertrack -> progress = '' ;
2006-07-23 23:48:09 +00:00
$usertrack -> total_time = '00:00:00' ;
$usertrack -> session_time = '00:00:00' ;
$usertrack -> timemodified = 0 ;
foreach ( $tracks as $track ) {
$element = $track -> element ;
$usertrack -> { $element } = $track -> value ;
switch ( $element ) {
2006-08-10 11:32:48 +00:00
case 'cmi.core.lesson_status' :
case 'cmi.completion_status' :
if ( $track -> value == 'not attempted' ) {
$track -> value = 'notattempted' ;
2008-09-09 08:30:00 +00:00
}
2006-08-10 11:32:48 +00:00
$usertrack -> status = $track -> value ;
2012-06-28 14:49:47 +08:00
break ;
case 'cmi.success_status' :
$usertrack -> progress = $track -> value ;
break ;
case 'cmi.progress_measure' :
2012-06-28 14:53:32 +08:00
if ( ! empty ( $track -> value ) && ( empty ( $usertrack -> progress ) || $usertrack -> progress == 'unknown' ) ) {
2012-06-28 14:49:47 +08:00
$usertrack -> progress = $track -> value ;
}
break ;
2006-07-23 23:48:09 +00:00
case 'cmi.core.score.raw' :
case 'cmi.score.raw' :
2010-07-08 18:22:53 +00:00
$usertrack -> score_raw = ( float ) sprintf ( '%2.2f' , $track -> value );
2012-06-28 11:51:06 +08:00
break ;
case 'cmi.core.score.max' :
case 'cmi.score.max' :
$usertrack -> score_max = ( float ) sprintf ( '%2.2f' , $track -> value );
break ;
case 'cmi.core.score.min' :
case 'cmi.score.min' :
$usertrack -> score_min = ( float ) sprintf ( '%2.2f' , $track -> value );
break ;
2006-07-23 23:48:09 +00:00
case 'cmi.core.session_time' :
case 'cmi.session_time' :
$usertrack -> session_time = $track -> value ;
2012-06-28 11:51:06 +08:00
break ;
2006-07-23 23:48:09 +00:00
case 'cmi.core.total_time' :
case 'cmi.total_time' :
$usertrack -> total_time = $track -> value ;
2012-06-28 11:51:06 +08:00
break ;
2008-09-09 08:30:00 +00:00
}
2006-07-23 23:48:09 +00:00
if ( isset ( $track -> timemodified ) && ( $track -> timemodified > $usertrack -> timemodified )) {
$usertrack -> timemodified = $track -> timemodified ;
2008-09-09 08:30:00 +00:00
}
2008-07-24 23:08:30 +00:00
}
2008-09-09 08:30:00 +00:00
if ( is_array ( $usertrack )) {
2008-07-27 21:19:01 +00:00
ksort ( $usertrack );
}
2006-07-23 23:48:09 +00:00
return $usertrack ;
} else {
return false ;
}
}
2008-12-20 06:20:43 +00:00
/* Find the start and finsh time for a a given SCO attempt
*
* @ param int $scormid SCORM Id
* @ param int $scoid SCO Id
* @ param int $userid User Id
* @ param int $attemt Attempt Id
*
* @ return object start and finsh time EPOC secods
*
*/
function scorm_get_sco_runtime ( $scormid , $scoid , $userid , $attempt = 1 ) {
2009-12-16 22:14:17 +00:00
global $DB ;
2008-12-20 06:20:43 +00:00
2010-09-21 08:37:36 +00:00
$timedata = new stdClass ();
2008-12-20 06:20:43 +00:00
$sql = ! empty ( $scoid ) ? " userid= $userid AND scormid= $scormid AND scoid= $scoid AND attempt= $attempt " : " userid= $userid AND scormid= $scormid AND attempt= $attempt " ;
2011-06-30 16:55:16 +12:00
$tracks = $DB -> get_records_select ( 'scorm_scoes_track' , " $sql ORDER BY timemodified ASC " );
2008-12-20 06:20:43 +00:00
if ( $tracks ) {
$tracks = array_values ( $tracks );
}
2010-02-09 18:43:15 +00:00
if ( $tracks ) {
2008-12-20 06:20:43 +00:00
$timedata -> start = $tracks [ 0 ] -> timemodified ;
2011-06-30 16:55:16 +12:00
} else {
2008-12-20 06:20:43 +00:00
$timedata -> start = false ;
}
if ( $tracks && $track = array_pop ( $tracks )) {
$timedata -> finish = $track -> timemodified ;
2011-06-30 16:55:16 +12:00
} else {
2008-12-20 06:20:43 +00:00
$timedata -> finish = $timedata -> start ;
}
return $timedata ;
}
2006-08-31 08:34:13 +00:00
function scorm_get_user_data ( $userid ) {
2008-06-05 10:02:26 +00:00
global $DB ;
2011-06-30 16:55:16 +12:00
/// Gets user info required to display the table of scorm results
/// for report.php
2006-07-23 23:48:09 +00:00
2011-02-28 12:33:29 +13:00
return $DB -> get_record ( 'user' , array ( 'id' => $userid ), user_picture :: fields ());
2006-08-31 08:34:13 +00:00
}
2006-07-23 23:48:09 +00:00
2010-07-23 08:03:08 +00:00
function scorm_grade_user_attempt ( $scorm , $userid , $attempt = 1 ) {
2008-06-05 10:02:26 +00:00
global $DB ;
2012-05-08 08:59:54 +12:00
$attemptscore = new stdClass ();
2006-09-26 07:56:07 +00:00
$attemptscore -> scoes = 0 ;
$attemptscore -> values = 0 ;
$attemptscore -> max = 0 ;
$attemptscore -> sum = 0 ;
$attemptscore -> lastmodify = 0 ;
2008-09-09 08:30:00 +00:00
2008-06-05 10:02:26 +00:00
if ( ! $scoes = $DB -> get_records ( 'scorm_scoes' , array ( 'scorm' => $scorm -> id ))) {
2011-06-30 16:55:16 +12:00
return null ;
2006-07-23 23:48:09 +00:00
}
2008-09-09 08:30:00 +00:00
foreach ( $scoes as $sco ) {
2011-06-30 16:55:16 +12:00
if ( $userdata = scorm_get_tracks ( $sco -> id , $userid , $attempt )) {
2006-08-31 08:34:13 +00:00
if (( $userdata -> status == 'completed' ) || ( $userdata -> status == 'passed' )) {
2006-09-26 07:56:07 +00:00
$attemptscore -> scoes ++ ;
2008-09-09 08:30:00 +00:00
}
2010-07-22 00:48:06 +00:00
if ( ! empty ( $userdata -> score_raw ) || ( isset ( $scorm -> type ) && $scorm -> type == 'sco' && isset ( $userdata -> score_raw ))) {
2006-09-26 07:56:07 +00:00
$attemptscore -> values ++ ;
$attemptscore -> sum += $userdata -> score_raw ;
$attemptscore -> max = ( $userdata -> score_raw > $attemptscore -> max ) ? $userdata -> score_raw : $attemptscore -> max ;
if ( isset ( $userdata -> timemodified ) && ( $userdata -> timemodified > $attemptscore -> lastmodify )) {
$attemptscore -> lastmodify = $userdata -> timemodified ;
} else {
$attemptscore -> lastmodify = 0 ;
}
2008-09-09 08:30:00 +00:00
}
}
2006-07-23 23:48:09 +00:00
}
2010-07-08 10:40:46 +00:00
switch ( $scorm -> grademethod ) {
2006-09-26 07:56:07 +00:00
case GRADEHIGHEST :
2010-07-08 18:22:53 +00:00
$score = ( float ) $attemptscore -> max ;
2008-09-09 08:30:00 +00:00
break ;
2006-09-26 07:56:07 +00:00
case GRADEAVERAGE :
if ( $attemptscore -> values > 0 ) {
$score = $attemptscore -> sum / $attemptscore -> values ;
2006-08-11 12:26:06 +00:00
} else {
2006-09-26 07:56:07 +00:00
$score = 0 ;
2008-09-09 08:30:00 +00:00
}
break ;
2006-09-26 07:56:07 +00:00
case GRADESUM :
$score = $attemptscore -> sum ;
2008-09-09 08:30:00 +00:00
break ;
2006-09-26 07:56:07 +00:00
case GRADESCOES :
$score = $attemptscore -> scoes ;
2008-08-21 03:12:08 +00:00
break ;
default :
$score = $attemptscore -> max ; // Remote Learner GRADEHIGHEST is default
2006-08-11 12:26:06 +00:00
}
2006-09-26 07:56:07 +00:00
2010-07-23 08:03:08 +00:00
return $score ;
2006-09-26 07:56:07 +00:00
}
2010-07-23 07:59:11 +00:00
function scorm_grade_user ( $scorm , $userid ) {
2006-09-26 07:56:07 +00:00
2010-07-08 10:40:46 +00:00
// ensure we dont grade user beyond $scorm->maxattempt settings
2008-08-22 01:30:28 +00:00
$lastattempt = scorm_get_last_attempt ( $scorm -> id , $userid );
2011-06-30 16:55:16 +12:00
if ( $scorm -> maxattempt != 0 && $lastattempt >= $scorm -> maxattempt ) {
2008-08-22 01:30:28 +00:00
$lastattempt = $scorm -> maxattempt ;
}
2010-07-08 10:40:46 +00:00
switch ( $scorm -> whatgrade ) {
2006-09-26 07:56:07 +00:00
case FIRSTATTEMPT :
2010-07-23 07:59:11 +00:00
return scorm_grade_user_attempt ( $scorm , $userid , 1 );
2008-09-09 08:30:00 +00:00
break ;
2006-09-26 07:56:07 +00:00
case LASTATTEMPT :
2010-07-23 07:59:11 +00:00
return scorm_grade_user_attempt ( $scorm , $userid , scorm_get_last_completed_attempt ( $scorm -> id , $userid ));
2006-09-26 07:56:07 +00:00
break ;
case HIGHESTATTEMPT :
$maxscore = 0 ;
for ( $attempt = 1 ; $attempt <= $lastattempt ; $attempt ++ ) {
2010-07-23 07:59:11 +00:00
$attemptscore = scorm_grade_user_attempt ( $scorm , $userid , $attempt );
$maxscore = $attemptscore > $maxscore ? $attemptscore : $maxscore ;
2006-09-26 07:56:07 +00:00
}
2010-07-23 07:59:11 +00:00
return $maxscore ;
2006-09-26 07:56:07 +00:00
break ;
case AVERAGEATTEMPT :
2010-07-23 09:23:52 +00:00
$attemptcount = scorm_get_attempt_count ( $userid , $scorm , true );
if ( empty ( $attemptcount )) {
return 0 ;
} else {
$attemptcount = count ( $attemptcount );
}
2006-09-26 07:56:07 +00:00
$lastattempt = scorm_get_last_attempt ( $scorm -> id , $userid );
$sumscore = 0 ;
for ( $attempt = 1 ; $attempt <= $lastattempt ; $attempt ++ ) {
2010-07-23 07:59:11 +00:00
$attemptscore = scorm_grade_user_attempt ( $scorm , $userid , $attempt );
$sumscore += $attemptscore ;
2006-09-26 07:56:07 +00:00
}
2010-07-23 09:23:52 +00:00
return round ( $sumscore / $attemptcount );
2006-09-26 07:56:07 +00:00
break ;
}
2006-07-23 23:48:09 +00:00
}
2011-06-30 16:55:16 +12:00
function scorm_count_launchable ( $scormid , $organization = '' ) {
2008-06-05 10:02:26 +00:00
global $DB ;
$sqlorganization = '' ;
$params = array ( $scormid );
2006-09-26 14:40:00 +00:00
if ( ! empty ( $organization )) {
2008-06-05 10:02:26 +00:00
$sqlorganization = " AND organization=? " ;
$params [] = $organization ;
2006-09-26 14:40:00 +00:00
}
2011-06-30 16:55:16 +12:00
return $DB -> count_records_select ( 'scorm_scoes' , " scorm = ? $sqlorganization AND " . $DB -> sql_isnotempty ( 'scorm_scoes' , 'launch' , false , true ), $params );
2006-07-23 23:48:09 +00:00
}
2006-08-31 08:34:13 +00:00
function scorm_get_last_attempt ( $scormid , $userid ) {
2008-06-05 10:02:26 +00:00
global $DB ;
2011-06-30 16:55:16 +12:00
/// Find the last attempt number for the given user id and scorm id
2008-06-05 10:02:26 +00:00
if ( $lastattempt = $DB -> get_record ( 'scorm_scoes_track' , array ( 'userid' => $userid , 'scormid' => $scormid ), 'max(attempt) as a' )) {
2006-08-31 08:34:13 +00:00
if ( empty ( $lastattempt -> a )) {
return '1' ;
} else {
return $lastattempt -> a ;
2006-07-23 23:48:09 +00:00
}
2008-09-16 20:32:50 +00:00
} else {
return false ;
2006-07-23 23:48:09 +00:00
}
}
2010-04-29 09:15:25 +00:00
function scorm_get_last_completed_attempt ( $scormid , $userid ) {
global $DB ;
2011-06-30 16:55:16 +12:00
/// Find the last attempt number for the given user id and scorm id
2010-08-11 23:57:03 +00:00
if ( $lastattempt = $DB -> get_record_select ( 'scorm_scoes_track' , " userid = ? AND scormid = ? AND (value='completed' OR value='passed') " , array ( $userid , $scormid ), 'max(attempt) as a' )) {
2010-04-29 09:15:25 +00:00
if ( empty ( $lastattempt -> a )) {
return '1' ;
} else {
return $lastattempt -> a ;
}
} else {
return false ;
}
}
2011-06-30 16:55:16 +12:00
function scorm_course_format_display ( $user , $course ) {
2009-07-02 11:09:15 +00:00
global $CFG , $DB , $PAGE , $OUTPUT ;
2006-07-23 23:48:09 +00:00
$strupdate = get_string ( 'update' );
2011-06-30 16:55:16 +12:00
$context = get_context_instance ( CONTEXT_COURSE , $course -> id );
2006-07-23 23:48:09 +00:00
echo '<div class="mod-scorm">' ;
if ( $scorms = get_all_instances_in_course ( 'scorm' , $course )) {
2008-09-09 08:30:00 +00:00
// The module SCORM activity with the least id is the course
2006-07-23 23:48:09 +00:00
$scorm = current ( $scorms );
if ( ! $cm = get_coursemodule_from_instance ( 'scorm' , $scorm -> id , $course -> id )) {
2008-06-15 11:00:30 +00:00
print_error ( 'invalidcoursemodule' );
2006-07-23 23:48:09 +00:00
}
2011-07-31 18:51:39 +12:00
$contextmodule = get_context_instance ( CONTEXT_MODULE , $cm -> id );
2011-08-02 17:00:01 +12:00
if (( has_capability ( 'mod/scorm:skipview' , $contextmodule ))) {
2011-08-12 12:44:16 +12:00
scorm_simple_play ( $scorm , $user , $contextmodule , $cm -> id );
2011-07-31 18:51:39 +12:00
}
2006-07-23 23:48:09 +00:00
$colspan = '' ;
$headertext = '<table width="100%"><tr><td class="title">' . get_string ( 'name' ) . ': <b>' . format_string ( $scorm -> name ) . '</b>' ;
2006-08-31 08:34:13 +00:00
if ( has_capability ( 'moodle/course:manageactivities' , $context )) {
2009-05-06 08:59:29 +00:00
if ( $PAGE -> user_is_editing ()) {
2006-07-23 23:48:09 +00:00
// Display update icon
$path = $CFG -> wwwroot . '/course' ;
$headertext .= '<span class="commands">' .
'<a title="' . $strupdate . '" href="' . $path . '/mod.php?update=' . $cm -> id . '&sesskey=' . sesskey () . '">' .
2009-12-16 21:50:45 +00:00
'<img src="' . $OUTPUT -> pix_url ( 't/edit' ) . '" class="iconsmall" alt="' . $strupdate . '" /></a></span>' ;
2006-07-23 23:48:09 +00:00
}
$headertext .= '</td>' ;
// Display report link
2008-06-05 10:02:26 +00:00
$trackedusers = $DB -> get_record ( 'scorm_scoes_track' , array ( 'scormid' => $scorm -> id ), 'count(distinct(userid)) as c' );
2006-07-23 23:48:09 +00:00
if ( $trackedusers -> c > 0 ) {
$headertext .= '<td class="reportlink">' .
2010-02-11 13:27:02 +00:00
'<a href="' . $CFG -> wwwroot . '/mod/scorm/report.php?id=' . $cm -> id . '">' .
2011-06-30 16:55:16 +12:00
get_string ( 'viewallreports' , 'scorm' , $trackedusers -> c ) . '</a>' ;
2006-07-23 23:48:09 +00:00
} else {
2011-06-30 16:55:16 +12:00
$headertext .= '<td class="reportlink">' . get_string ( 'noreports' , 'scorm' );
2006-07-23 23:48:09 +00:00
}
$colspan = ' colspan="2"' ;
2008-09-09 08:30:00 +00:00
}
2009-04-22 05:10:08 +00:00
$headertext .= '</td></tr><tr><td' . $colspan . '>' . get_string ( 'summary' ) . ':<br />' . format_module_intro ( 'scorm' , $scorm , $scorm -> coursemodule ) . '</td></tr></table>' ;
2011-06-30 16:55:16 +12:00
echo $OUTPUT -> box ( $headertext , 'generalbox boxwidthwide' );
2011-01-29 20:16:10 +13:00
scorm_view_display ( $user , $scorm , 'view.php?id=' . $course -> id , $cm );
2006-07-23 23:48:09 +00:00
} else {
2006-08-31 10:29:16 +00:00
if ( has_capability ( 'moodle/course:update' , $context )) {
2006-07-23 23:48:09 +00:00
// Create a new activity
2011-06-29 20:31:19 +12:00
$url = new moodle_url ( '/course/mod.php' , array ( 'id' => $course -> id , 'section' => '0' , 'sesskey' => sesskey (), 'add' => 'scorm' ));
redirect ( $url );
2006-07-23 23:48:09 +00:00
} else {
2009-08-18 05:16:50 +00:00
echo $OUTPUT -> notification ( 'Could not find a scorm course here' );
2006-07-23 23:48:09 +00:00
}
}
echo '</div>' ;
}
2011-01-29 20:16:10 +13:00
function scorm_view_display ( $user , $scorm , $action , $cm ) {
2009-07-28 09:32:23 +00:00
global $CFG , $DB , $PAGE , $OUTPUT ;
2007-01-25 07:20:38 +00:00
2012-02-16 12:16:02 +13:00
if ( $scorm -> scormtype != SCORM_TYPE_LOCAL && $scorm -> updatefreq == SCORM_UPDATE_EVERYTIME ) {
2008-09-09 08:30:00 +00:00
scorm_parse ( $scorm , false );
2007-01-25 07:20:38 +00:00
}
2006-07-23 23:48:09 +00:00
$organization = optional_param ( 'organization' , '' , PARAM_INT );
2011-06-30 16:55:16 +12:00
if ( $scorm -> displaycoursestructure == 1 ) {
2011-01-31 16:53:10 +13:00
echo $OUTPUT -> box_start ( 'generalbox boxaligncenter toc' );
2011-06-30 16:55:16 +12:00
?>
< div class = " structurehead " >< ? php print_string ( 'contents' , 'scorm' ) ?> </div>
< ? php
2008-09-16 20:32:50 +00:00
}
2006-07-23 23:48:09 +00:00
if ( empty ( $organization )) {
$organization = $scorm -> launch ;
}
2011-01-10 11:22:50 +13:00
if ( $orgs = $DB -> get_records_select_menu ( 'scorm_scoes' , 'scorm = ? AND ' .
2010-09-23 08:27:53 +00:00
$DB -> sql_isempty ( 'scorm_scoes' , 'launch' , false , true ) . ' AND ' .
$DB -> sql_isempty ( 'scorm_scoes' , 'organization' , false , false ),
2011-06-30 16:55:16 +12:00
array ( $scorm -> id ), 'id' , 'id,title' )) {
2006-07-23 23:48:09 +00:00
if ( count ( $orgs ) > 1 ) {
2010-02-10 16:20:28 +00:00
$select = new single_select ( new moodle_url ( $action ), 'organization' , $orgs , $organization , null );
2011-06-30 16:55:16 +12:00
$select -> label = get_string ( 'organizations' , 'scorm' );
2010-02-10 16:20:28 +00:00
$select -> class = 'scorm-center' ;
echo $OUTPUT -> render ( $select );
2006-07-23 23:48:09 +00:00
}
}
$orgidentifier = '' ;
2006-11-21 16:12:19 +00:00
if ( $sco = scorm_get_sco ( $organization , SCO_ONLY )) {
if (( $sco -> organization == '' ) && ( $sco -> launch == '' )) {
$orgidentifier = $sco -> identifier ;
2006-07-23 23:48:09 +00:00
} else {
2006-11-21 16:12:19 +00:00
$orgidentifier = $sco -> organization ;
2006-07-23 23:48:09 +00:00
}
}
2007-03-08 12:06:26 +00:00
2006-08-31 08:34:13 +00:00
$scorm -> version = strtolower ( clean_param ( $scorm -> version , PARAM_SAFEDIR )); // Just to be safe
2006-11-28 03:04:50 +00:00
if ( ! file_exists ( $CFG -> dirroot . '/mod/scorm/datamodels/' . $scorm -> version . 'lib.php' )) {
$scorm -> version = 'scorm_12' ;
}
2006-08-31 08:34:13 +00:00
require_once ( $CFG -> dirroot . '/mod/scorm/datamodels/' . $scorm -> version . 'lib.php' );
2011-06-30 16:55:16 +12:00
$result = scorm_get_toc ( $user , $scorm , $cm -> id , TOCFULLURL , $orgidentifier );
2006-07-23 23:48:09 +00:00
$incomplete = $result -> incomplete ;
2007-03-08 12:06:26 +00:00
2008-09-16 20:32:50 +00:00
// do we want the TOC to be displayed?
2011-06-30 16:55:16 +12:00
if ( $scorm -> displaycoursestructure == 1 ) {
2008-09-16 20:32:50 +00:00
echo $result -> toc ;
2009-08-18 05:16:50 +00:00
echo $OUTPUT -> box_end ();
2008-09-16 20:32:50 +00:00
}
2008-11-29 17:51:47 +00:00
2008-09-16 20:32:50 +00:00
// is this the first attempt ?
2010-07-23 09:23:52 +00:00
$attemptcount = scorm_get_attempt_count ( $user -> id , $scorm );
2008-11-29 17:51:47 +00:00
2008-09-16 20:32:50 +00:00
// do not give the player launch FORM if the SCORM object is locked after the final attempt
if ( $scorm -> lastattemptlock == 0 || $result -> attemptleft > 0 ) {
2011-06-30 16:55:16 +12:00
?>
2008-07-29 00:42:28 +00:00
< div class = " scorm-center " >
2012-03-28 14:28:19 +13:00
< form id = " scormviewform " method = " post " action = " <?php echo $CFG->wwwroot ?>/mod/scorm/player.php " >
2011-06-30 16:55:16 +12:00
< ? php
if ( $scorm -> hidebrowse == 0 ) {
print_string ( 'mode' , 'scorm' );
echo ': <input type="radio" id="b" name="mode" value="browse" /><label for="b">' . get_string ( 'browse' , 'scorm' ) . '</label>' . " \n " ;
echo '<input type="radio" id="n" name="mode" value="normal" checked="checked" /><label for="n">' . get_string ( 'normal' , 'scorm' ) . " </label> \n " ;
} else {
echo '<input type="hidden" name="mode" value="normal" />' . " \n " ;
}
if ( $scorm -> forcenewattempt == 1 ) {
if ( $incomplete === false ) {
echo '<input type="hidden" name="newattempt" value="on" />' . " \n " ;
}
} else if ( ! empty ( $attemptcount ) && ( $incomplete === false ) && (( $result -> attemptleft > 0 ) || ( $scorm -> maxattempt == 0 ))) {
?>
2008-09-16 20:32:50 +00:00
< br />
< input type = " checkbox " id = " a " name = " newattempt " />
2011-06-30 16:55:16 +12:00
< label for = " a " >< ? php print_string ( 'newattempt' , 'scorm' ) ?> </label>
< ? php
}
2012-03-28 14:28:19 +13:00
if ( ! empty ( $scorm -> popup )) {
echo '<input type="hidden" name="display" value="popup" />' . " \n " ;
}
2011-06-30 16:55:16 +12:00
?>
2006-07-23 23:48:09 +00:00
< br />
2008-09-08 00:31:15 +00:00
< input type = " hidden " name = " scoid " />
2010-07-09 04:18:15 +00:00
< input type = " hidden " name = " cm " value = " <?php echo $cm->id ?> " />
2006-07-23 23:48:09 +00:00
< input type = " hidden " name = " currentorg " value = " <?php echo $orgidentifier ?> " />
2011-06-30 16:55:16 +12:00
< input type = " submit " value = " <?php print_string('enter', 'scorm') ?> " />
2006-07-23 23:48:09 +00:00
</ form >
</ div >
2011-06-30 16:55:16 +12:00
< ? php
2008-09-16 20:32:50 +00:00
}
2006-07-23 23:48:09 +00:00
}
2008-08-15 03:30:05 +00:00
2011-08-12 12:44:16 +12:00
function scorm_simple_play ( $scorm , $user , $context , $cmid ) {
2008-06-05 10:02:26 +00:00
global $DB ;
2008-12-01 03:32:39 +00:00
$result = false ;
2012-02-16 12:16:02 +13:00
if ( $scorm -> scormtype != SCORM_TYPE_LOCAL && $scorm -> updatefreq == SCORM_UPDATE_EVERYTIME ) {
2008-12-01 03:32:39 +00:00
scorm_parse ( $scorm , false );
}
2010-07-03 13:37:13 +00:00
if ( has_capability ( 'mod/scorm:viewreport' , $context )) { //if this user can view reports, don't skipview so they can see links to reports.
2010-06-25 10:12:29 +00:00
return $result ;
}
2008-12-01 03:32:39 +00:00
2010-09-23 08:27:53 +00:00
$scoes = $DB -> get_records_select ( 'scorm_scoes' , 'scorm = ? AND ' . $DB -> sql_isnotempty ( 'scorm_scoes' , 'launch' , false , true ), array ( $scorm -> id ), 'id' , 'id' );
2008-12-01 03:32:39 +00:00
2008-12-07 21:54:49 +00:00
if ( $scoes ) {
2011-07-04 10:57:16 +12:00
$orgidentifier = '' ;
if ( $sco = scorm_get_sco ( $scorm -> launch , SCO_ONLY )) {
if (( $sco -> organization == '' ) && ( $sco -> launch == '' )) {
$orgidentifier = $sco -> identifier ;
} else {
$orgidentifier = $sco -> organization ;
}
}
2008-12-01 03:32:39 +00:00
if ( $scorm -> skipview >= 1 ) {
$sco = current ( $scoes );
2011-07-31 18:51:39 +12:00
$url = new moodle_url ( '/mod/scorm/player.php' , array ( 'a' => $scorm -> id ,
'currentorg' => $orgidentifier ,
'scoid' => $sco -> id ));
if ( $scorm -> skipview == 2 || scorm_get_tracks ( $sco -> id , $user -> id ) === false ) {
2011-08-12 12:44:16 +12:00
if ( ! empty ( $scorm -> forcenewattempt )) {
$result = scorm_get_toc ( $user , $scorm , $cmid , TOCFULLURL , $orgidentifier );
if ( $result -> incomplete === false ) {
$url -> param ( 'newattempt' , 'on' );
}
}
2011-07-31 18:51:39 +12:00
redirect ( $url );
2008-12-01 03:32:39 +00:00
}
}
}
return $result ;
2007-03-08 12:06:26 +00:00
}
2007-08-28 02:54:37 +00:00
function scorm_get_count_users ( $scormid , $groupingid = null ) {
2008-06-05 10:02:26 +00:00
global $CFG , $DB ;
2008-09-09 08:30:00 +00:00
2010-04-07 07:37:12 +00:00
if ( ! empty ( $groupingid )) {
2007-08-28 02:54:37 +00:00
$sql = " SELECT COUNT(DISTINCT st.userid)
2008-06-05 10:02:26 +00:00
FROM { scorm_scoes_track } st
INNER JOIN { groups_members } gm ON st . userid = gm . userid
2008-09-09 08:30:00 +00:00
INNER JOIN { groupings_groups } gg ON gm . groupid = gg . groupid
2008-06-05 10:02:26 +00:00
WHERE st . scormid = ? AND gg . groupingid = ?
2007-08-28 02:54:37 +00:00
" ;
2008-06-05 10:02:26 +00:00
$params = array ( $scormid , $groupingid );
2007-08-28 02:54:37 +00:00
} else {
$sql = " SELECT COUNT(DISTINCT st.userid)
2008-09-09 08:30:00 +00:00
FROM { scorm_scoes_track } st
2008-06-05 10:02:26 +00:00
WHERE st . scormid = ?
2007-08-28 02:54:37 +00:00
" ;
2008-06-05 10:02:26 +00:00
$params = array ( $scormid );
2007-08-28 02:54:37 +00:00
}
2008-09-09 08:30:00 +00:00
2008-06-05 10:02:26 +00:00
return ( $DB -> count_records_sql ( $sql , $params ));
2007-08-28 02:54:37 +00:00
}
2008-09-08 19:45:50 +00:00
/**
2011-06-30 16:55:16 +12:00
* Build up the JavaScript representation of an array element
*
* @ param string $sversion SCORM API version
* @ param array $userdata User track data
* @ param string $element_name Name of array element to get values for
* @ param array $children list of sub elements of this array element that also need instantiating
* @ return None
*/
2008-09-08 19:45:50 +00:00
function scorm_reconstitute_array_element ( $sversion , $userdata , $element_name , $children ) {
// reconstitute comments_from_learner and comments_from_lms
$current = '' ;
2008-09-24 23:12:09 +00:00
$current_subelement = '' ;
$current_sub = '' ;
2008-09-08 19:45:50 +00:00
$count = 0 ;
2008-09-24 23:12:09 +00:00
$count_sub = 0 ;
2010-04-30 05:45:12 +00:00
$scormseperator = '_' ;
2011-08-15 13:50:06 +12:00
if ( scorm_version_check ( $sversion , SCORM_13 )) { //scorm 1.3 elements use a . instead of an _
2011-06-30 16:55:16 +12:00
$scormseperator = '.' ;
2010-04-30 05:45:12 +00:00
}
2008-09-08 19:45:50 +00:00
// filter out the ones we want
$element_list = array ();
2011-06-30 16:55:16 +12:00
foreach ( $userdata as $element => $value ) {
if ( substr ( $element , 0 , strlen ( $element_name )) == $element_name ) {
2008-09-08 19:45:50 +00:00
$element_list [ $element ] = $value ;
}
}
2008-11-29 17:51:47 +00:00
2008-09-08 19:45:50 +00:00
// sort elements in .n array order
uksort ( $element_list , " scorm_element_cmp " );
2008-11-29 17:51:47 +00:00
2008-09-08 19:45:50 +00:00
// generate JavaScript
2011-06-30 16:55:16 +12:00
foreach ( $element_list as $element => $value ) {
2011-08-15 13:50:06 +12:00
if ( scorm_version_check ( $sversion , SCORM_13 )) {
2008-09-25 23:59:32 +00:00
$element = preg_replace ( '/\.(\d+)\./' , " .N \$ 1. " , $element );
2008-09-08 19:45:50 +00:00
preg_match ( '/\.(N\d+)\./' , $element , $matches );
} else {
2008-09-25 23:59:32 +00:00
$element = preg_replace ( '/\.(\d+)\./' , " _ \$ 1. " , $element );
2008-09-08 19:45:50 +00:00
preg_match ( '/\_(\d+)\./' , $element , $matches );
}
if ( count ( $matches ) > 0 && $current != $matches [ 1 ]) {
2008-09-24 23:12:09 +00:00
if ( $count_sub > 0 ) {
2010-04-30 05:45:12 +00:00
echo ' ' . $element_name . $scormseperator . $current . '.' . $current_subelement . '._count = ' . $count_sub . " ; \n " ;
2008-09-24 23:12:09 +00:00
}
2008-11-29 17:51:47 +00:00
$current = $matches [ 1 ];
2008-09-08 19:45:50 +00:00
$count ++ ;
2008-09-24 23:12:09 +00:00
$current_subelement = '' ;
$current_sub = '' ;
$count_sub = 0 ;
2011-06-30 16:55:16 +12:00
$end = strpos ( $element , $matches [ 1 ]) + strlen ( $matches [ 1 ]);
$subelement = substr ( $element , 0 , $end );
2008-09-08 19:45:50 +00:00
echo ' ' . $subelement . " = new Object(); \n " ;
// now add the children
foreach ( $children as $child ) {
echo ' ' . $subelement . " . " . $child . " = new Object(); \n " ;
echo ' ' . $subelement . " . " . $child . " ._children = " . $child . " _children; \n " ;
}
}
2008-11-29 17:51:47 +00:00
2008-09-24 23:12:09 +00:00
// now - flesh out the second level elements if there are any
2011-08-15 13:50:06 +12:00
if ( scorm_version_check ( $sversion , SCORM_13 )) {
2008-09-25 23:59:32 +00:00
$element = preg_replace ( '/(.*?\.N\d+\..*?)\.(\d+)\./' , " \$ 1.N \$ 2. " , $element );
2008-09-24 23:12:09 +00:00
preg_match ( '/.*?\.N\d+\.(.*?)\.(N\d+)\./' , $element , $matches );
} else {
2008-09-25 23:59:32 +00:00
$element = preg_replace ( '/(.*?\_\d+\..*?)\.(\d+)\./' , " \$ 1_ \$ 2. " , $element );
2008-09-24 23:12:09 +00:00
preg_match ( '/.*?\_\d+\.(.*?)\_(\d+)\./' , $element , $matches );
}
2008-11-29 17:51:47 +00:00
2008-09-24 23:12:09 +00:00
// check the sub element type
if ( count ( $matches ) > 0 && $current_subelement != $matches [ 1 ]) {
if ( $count_sub > 0 ) {
2010-04-30 05:52:56 +00:00
echo ' ' . $element_name . $scormseperator . $current . '.' . $current_subelement . '._count = ' . $count_sub . " ; \n " ;
2008-09-24 23:12:09 +00:00
}
$current_subelement = $matches [ 1 ];
$current_sub = '' ;
$count_sub = 0 ;
2011-06-30 16:55:16 +12:00
$end = strpos ( $element , $matches [ 1 ]) + strlen ( $matches [ 1 ]);
$subelement = substr ( $element , 0 , $end );
2008-09-24 23:12:09 +00:00
echo ' ' . $subelement . " = new Object(); \n " ;
}
2008-11-29 17:51:47 +00:00
2008-09-24 23:12:09 +00:00
// now check the subelement subscript
if ( count ( $matches ) > 0 && $current_sub != $matches [ 2 ]) {
2008-11-29 17:51:47 +00:00
$current_sub = $matches [ 2 ];
2008-09-24 23:12:09 +00:00
$count_sub ++ ;
2011-06-30 16:55:16 +12:00
$end = strrpos ( $element , $matches [ 2 ]) + strlen ( $matches [ 2 ]);
$subelement = substr ( $element , 0 , $end );
2008-09-24 23:12:09 +00:00
echo ' ' . $subelement . " = new Object(); \n " ;
}
2008-11-29 17:51:47 +00:00
2008-09-08 19:45:50 +00:00
echo ' ' . $element . ' = \'' . $value . " '; \n " ;
}
2008-09-24 23:12:09 +00:00
if ( $count_sub > 0 ) {
2010-04-30 05:45:12 +00:00
echo ' ' . $element_name . $scormseperator . $current . '.' . $current_subelement . '._count = ' . $count_sub . " ; \n " ;
2008-09-24 23:12:09 +00:00
}
2008-09-08 19:45:50 +00:00
if ( $count > 0 ) {
echo ' ' . $element_name . '._count = ' . $count . " ; \n " ;
}
}
/**
2011-06-30 16:55:16 +12:00
* Build up the JavaScript representation of an array element
*
* @ param string $a left array element
* @ param string $b right array element
* @ return comparator - 0 , 1 , - 1
*/
2008-09-08 19:45:50 +00:00
function scorm_element_cmp ( $a , $b ) {
2008-09-24 23:12:09 +00:00
preg_match ( '/.*?(\d+)\./' , $a , $matches );
2008-09-08 19:45:50 +00:00
$left = intval ( $matches [ 1 ]);
2008-09-24 23:12:09 +00:00
preg_match ( '/.?(\d+)\./' , $b , $matches );
2008-09-08 19:45:50 +00:00
$right = intval ( $matches [ 1 ]);
if ( $left < $right ) {
return - 1 ; // smaller
2011-06-30 16:55:16 +12:00
} else if ( $left > $right ) {
2008-09-08 19:45:50 +00:00
return 1 ; // bigger
} else {
2008-09-24 23:12:09 +00:00
// look for a second level qualifier eg cmi.interactions_0.correct_responses_0.pattern
if ( preg_match ( '/.*?(\d+)\.(.*?)\.(\d+)\./' , $a , $matches )) {
$leftterm = intval ( $matches [ 2 ]);
$left = intval ( $matches [ 3 ]);
if ( preg_match ( '/.*?(\d+)\.(.*?)\.(\d+)\./' , $b , $matches )) {
$rightterm = intval ( $matches [ 2 ]);
$right = intval ( $matches [ 3 ]);
if ( $leftterm < $rightterm ) {
return - 1 ; // smaller
2011-06-30 16:55:16 +12:00
} else if ( $leftterm > $rightterm ) {
2008-09-24 23:12:09 +00:00
return 1 ; // bigger
} else {
if ( $left < $right ) {
return - 1 ; // smaller
2011-06-30 16:55:16 +12:00
} else if ( $left > $right ) {
2008-09-24 23:12:09 +00:00
return 1 ; // bigger
}
}
}
}
// fall back for no second level matches or second level matches are equal
2008-09-08 19:45:50 +00:00
return 0 ; // equal to
}
}
2008-09-16 20:32:50 +00:00
/**
2011-06-30 16:55:16 +12:00
* Generate the user attempt status string
*
* @ param object $user Current context user
* @ param object $scorm a moodle scrom object - mdl_scorm
* @ return string - Attempt status string
*/
2011-12-02 22:06:35 +13:00
function scorm_get_attempt_status ( $user , $scorm , $cm = '' ) {
global $DB , $PAGE , $OUTPUT ;
2008-11-29 17:51:47 +00:00
2010-07-23 09:23:52 +00:00
$attempts = scorm_get_attempt_count ( $user -> id , $scorm , true );
2011-06-30 16:55:16 +12:00
if ( empty ( $attempts )) {
2008-09-16 20:32:50 +00:00
$attemptcount = 0 ;
} else {
$attemptcount = count ( $attempts );
}
2008-11-29 17:51:47 +00:00
2008-09-16 20:32:50 +00:00
$result = '<p>' . get_string ( 'noattemptsallowed' , 'scorm' ) . ': ' ;
if ( $scorm -> maxattempt > 0 ) {
2011-04-16 19:32:11 +12:00
$result .= $scorm -> maxattempt . '<br />' ;
2008-09-16 20:32:50 +00:00
} else {
2011-04-16 19:32:11 +12:00
$result .= get_string ( 'unlimited' ) . '<br />' ;
2008-09-16 20:32:50 +00:00
}
2011-04-16 19:32:11 +12:00
$result .= get_string ( 'noattemptsmade' , 'scorm' ) . ': ' . $attemptcount . '<br />' ;
2008-09-16 20:32:50 +00:00
2010-07-23 09:23:52 +00:00
if ( $scorm -> maxattempt == 1 ) {
switch ( $scorm -> grademethod ) {
case GRADEHIGHEST :
$grademethod = get_string ( 'gradehighest' , 'scorm' );
break ;
case GRADEAVERAGE :
$grademethod = get_string ( 'gradeaverage' , 'scorm' );
break ;
case GRADESUM :
$grademethod = get_string ( 'gradesum' , 'scorm' );
break ;
case GRADESCOES :
$grademethod = get_string ( 'gradescoes' , 'scorm' );
break ;
}
2011-06-30 16:55:16 +12:00
} else {
switch ( $scorm -> whatgrade ) {
2010-07-23 09:23:52 +00:00
case HIGHESTATTEMPT :
$grademethod = get_string ( 'highestattempt' , 'scorm' );
break ;
case AVERAGEATTEMPT :
$grademethod = get_string ( 'averageattempt' , 'scorm' );
break ;
case FIRSTATTEMPT :
$grademethod = get_string ( 'firstattempt' , 'scorm' );
break ;
case LASTATTEMPT :
$grademethod = get_string ( 'lastattempt' , 'scorm' );
break ;
}
2011-06-30 16:55:16 +12:00
}
2008-11-29 17:51:47 +00:00
2011-06-30 16:55:16 +12:00
if ( ! empty ( $attempts )) {
2010-07-23 09:23:52 +00:00
$i = 1 ;
2011-06-30 16:55:16 +12:00
foreach ( $attempts as $attempt ) {
2008-09-16 20:32:50 +00:00
$gradereported = scorm_grade_user_attempt ( $scorm , $user -> id , $attempt -> attemptnumber );
2011-04-16 19:32:11 +12:00
if ( $scorm -> grademethod !== GRADESCOES && ! empty ( $scorm -> maxgrade )) {
$gradereported = $gradereported / $scorm -> maxgrade ;
$gradereported = number_format ( $gradereported * 100 , 0 ) . '%' ;
}
$result .= get_string ( 'gradeforattempt' , 'scorm' ) . ' ' . $i . ': ' . $gradereported . '<br />' ;
2010-07-23 09:23:52 +00:00
$i ++ ;
2008-09-16 20:32:50 +00:00
}
}
2010-07-23 09:23:52 +00:00
$calculatedgrade = scorm_grade_user ( $scorm , $user -> id );
2011-04-16 19:32:11 +12:00
if ( $scorm -> grademethod !== GRADESCOES && ! empty ( $scorm -> maxgrade )) {
$calculatedgrade = $calculatedgrade / $scorm -> maxgrade ;
$calculatedgrade = number_format ( $calculatedgrade * 100 , 0 ) . '%' ;
}
2008-09-16 20:32:50 +00:00
$result .= get_string ( 'grademethod' , 'scorm' ) . ': ' . $grademethod ;
2011-06-30 16:55:16 +12:00
if ( empty ( $attempts )) {
$result .= '<br />' . get_string ( 'gradereported' , 'scorm' ) . ': ' . get_string ( 'none' ) . '<br />' ;
2008-09-16 20:32:50 +00:00
} else {
2011-06-30 16:55:16 +12:00
$result .= '<br />' . get_string ( 'gradereported' , 'scorm' ) . ': ' . $calculatedgrade . '<br />' ;
2008-09-16 20:32:50 +00:00
}
$result .= '</p>' ;
if ( $attemptcount >= $scorm -> maxattempt and $scorm -> maxattempt > 0 ) {
2011-06-30 16:55:16 +12:00
$result .= '<p><font color="#cc0000">' . get_string ( 'exceededmaxattempts' , 'scorm' ) . '</font></p>' ;
2008-09-16 20:32:50 +00:00
}
2011-12-02 22:06:35 +13:00
if ( ! empty ( $cm )) {
$context = context_module :: instance ( $cm -> id );
2011-12-02 22:18:34 +13:00
if ( has_capability ( 'mod/scorm:deleteownresponses' , $context ) &&
$DB -> record_exists ( 'scorm_scoes_track' , array ( 'userid' => $user -> id , 'scormid' => $scorm -> id ))) {
//check to see if any data is stored for this user:
2011-12-02 22:06:35 +13:00
$deleteurl = new moodle_url ( $PAGE -> url , array ( 'action' => 'delete' , 'sesskey' => sesskey ()));
$result .= $OUTPUT -> single_button ( $deleteurl , get_string ( 'deleteallattempts' , 'scorm' ));
}
}
2008-09-16 20:32:50 +00:00
return $result ;
}
/**
2011-06-30 16:55:16 +12:00
* Get SCORM attempt count
*
* @ param object $user Current context user
* @ param object $scorm a moodle scrom object - mdl_scorm
* @ param bool $attempts return the list of attempts
* @ return int - no . of attempts so far
*/
2010-07-23 09:23:52 +00:00
function scorm_get_attempt_count ( $userid , $scorm , $attempts_only = false ) {
2008-09-16 20:32:50 +00:00
global $DB ;
$attemptcount = 0 ;
$element = 'cmi.core.score.raw' ;
2010-11-10 23:40:00 +00:00
if ( $scorm -> grademethod == GRADESCOES ) {
$element = 'cmi.core.lesson_status' ;
}
2011-08-15 13:50:06 +12:00
if ( scorm_version_check ( $scorm -> version , SCORM_13 )) {
2008-09-16 20:32:50 +00:00
$element = 'cmi.score.raw' ;
}
2011-06-30 16:55:16 +12:00
$attempts = $DB -> get_records_select ( 'scorm_scoes_track' , " element=? AND userid=? AND scormid=? " , array ( $element , $userid , $scorm -> id ), 'attempt' , 'DISTINCT attempt AS attemptnumber' );
2010-07-06 03:13:48 +00:00
if ( $attempts_only ) {
return $attempts ;
}
2011-06-30 16:55:16 +12:00
if ( ! empty ( $attempts )) {
2008-09-16 20:32:50 +00:00
$attemptcount = count ( $attempts );
}
return $attemptcount ;
}
2008-09-16 22:50:16 +00:00
/**
2011-06-30 16:55:16 +12:00
* Figure out with this is a debug situation
*
* @ param object $scorm a moodle scrom object - mdl_scorm
* @ return boolean - debugging true / false
*/
2008-09-16 22:50:16 +00:00
function scorm_debugging ( $scorm ) {
global $CFG , $USER ;
2008-11-11 02:46:20 +00:00
$cfg_scorm = get_config ( 'scorm' );
2008-11-29 17:51:47 +00:00
2008-11-11 02:46:20 +00:00
if ( ! $cfg_scorm -> allowapidebug ) {
2008-09-16 22:50:16 +00:00
return false ;
}
$identifier = $USER -> username . ':' . $scorm -> name ;
2008-11-11 02:46:20 +00:00
$test = $cfg_scorm -> apidebugmask ;
2008-09-16 22:50:16 +00:00
// check the regex is only a short list of safe characters
if ( ! preg_match ( '/^[\w\s\*\.\?\+\:\_\\\]+$/' , $test )) {
return false ;
}
$res = false ;
eval ( '$res = preg_match(\'/^' . $test . '/\', $identifier) ? true : false;' );
return $res ;
}
2008-11-29 17:51:47 +00:00
/**
2011-06-30 16:55:16 +12:00
* Delete Scorm tracks for selected users
*
* @ param array $attemptids list of attempts that need to be deleted
* @ param int $scorm instance
*
* return bool true deleted all responses , false failed deleting an attempt - stopped here
*/
2010-04-27 22:08:22 +00:00
function scorm_delete_responses ( $attemptids , $scorm ) {
2011-06-30 16:55:16 +12:00
if ( ! is_array ( $attemptids ) || empty ( $attemptids )) {
2008-11-29 17:51:47 +00:00
return false ;
}
2011-06-30 16:55:16 +12:00
foreach ( $attemptids as $num => $attemptid ) {
if ( empty ( $attemptid )) {
2008-11-29 17:51:47 +00:00
unset ( $attemptids [ $num ]);
}
}
2011-06-30 16:55:16 +12:00
foreach ( $attemptids as $attempt ) {
2008-11-29 17:51:47 +00:00
$keys = explode ( ':' , $attempt );
if ( count ( $keys ) == 2 ) {
$userid = clean_param ( $keys [ 0 ], PARAM_INT );
$attemptid = clean_param ( $keys [ 1 ], PARAM_INT );
2010-04-27 22:08:22 +00:00
if ( ! $userid || ! $attemptid || ! scorm_delete_attempt ( $userid , $scorm , $attemptid )) {
2008-11-29 17:51:47 +00:00
return false ;
}
} else {
return false ;
}
}
return true ;
}
/**
2011-06-30 16:55:16 +12:00
* Delete Scorm tracks for selected users
*
* @ param int $userid ID of User
* @ param int $scormid ID of Scorm
* @ param int $attemptid user attempt that need to be deleted
*
* return bool true suceeded
*/
2010-04-27 22:08:22 +00:00
function scorm_delete_attempt ( $userid , $scorm , $attemptid ) {
2008-11-29 17:51:47 +00:00
global $DB ;
2010-04-27 22:08:22 +00:00
$DB -> delete_records ( 'scorm_scoes_track' , array ( 'userid' => $userid , 'scormid' => $scorm -> id , 'attempt' => $attemptid ));
include_once ( 'lib.php' );
scorm_update_grades ( $scorm , $userid , true );
2008-11-29 17:51:47 +00:00
return true ;
}
2009-12-18 10:10:04 +00:00
/**
2010-08-30 23:45:53 +00:00
* Converts SCORM duration notation to human - readable format
2009-12-18 10:10:04 +00:00
* The function works with both SCORM 1.2 and SCORM 2004 time formats
2010-08-30 23:45:53 +00:00
* @ param $duration string SCORM duration
2009-12-18 10:10:04 +00:00
* @ return string human - readable date / time
*/
2010-08-30 23:45:53 +00:00
function scorm_format_duration ( $duration ) {
2009-12-18 10:10:04 +00:00
// fetch date/time strings
2010-08-31 00:02:10 +00:00
$stryears = get_string ( 'years' );
2009-12-18 10:10:04 +00:00
$strmonths = get_string ( 'nummonths' );
2010-08-31 00:02:10 +00:00
$strdays = get_string ( 'days' );
$strhours = get_string ( 'hours' );
$strminutes = get_string ( 'minutes' );
$strseconds = get_string ( 'seconds' );
2010-07-03 13:37:13 +00:00
2010-08-30 23:45:53 +00:00
if ( $duration [ 0 ] == 'P' ) {
2009-12-18 10:10:04 +00:00
// if timestamp starts with 'P' - it's a SCORM 2004 format
// this regexp discards empty sections, takes Month/Minute ambiguity into consideration,
// and outputs filled sections, discarding leading zeroes and any format literals
// also saves the only zero before seconds decimals (if there are any) and discards decimals if they are zero
$pattern = array ( '#([A-Z])0+Y#' , '#([A-Z])0+M#' , '#([A-Z])0+D#' , '#P(|\d+Y)0*(\d+)M#' , '#0*(\d+)Y#' , '#0*(\d+)D#' , '#P#' ,
'#([A-Z])0+H#' , '#([A-Z])[0.]+S#' , '#\.0+S#' , '#T(|\d+H)0*(\d+)M#' , '#0*(\d+)H#' , '#0+\.(\d+)S#' , '#0*([\d.]+)S#' , '#T#' );
2010-08-31 00:02:10 +00:00
$replace = array ( '$1' , '$1' , '$1' , '$1$2 ' . $strmonths . ' ' , '$1 ' . $stryears . ' ' , '$1 ' . $strdays . ' ' , '' ,
'$1' , '$1' , 'S' , '$1$2 ' . $strminutes . ' ' , '$1 ' . $strhours . ' ' , '0.$1 ' . $strseconds , '$1 ' . $strseconds , '' );
2009-12-18 10:10:04 +00:00
} else {
// else we have SCORM 1.2 format there
// first convert the timestamp to some SCORM 2004-like format for conveniency
2010-08-30 23:45:53 +00:00
$duration = preg_replace ( '#^(\d+):(\d+):([\d.]+)$#' , 'T$1H$2M$3S' , $duration );
2009-12-18 10:10:04 +00:00
// then convert in the same way as SCORM 2004
$pattern = array ( '#T0+H#' , '#([A-Z])0+M#' , '#([A-Z])[0.]+S#' , '#\.0+S#' , '#0*(\d+)H#' , '#0*(\d+)M#' , '#0+\.(\d+)S#' , '#0*([\d.]+)S#' , '#T#' );
2010-08-31 00:02:10 +00:00
$replace = array ( 'T' , '$1' , '$1' , 'S' , '$1 ' . $strhours . ' ' , '$1 ' . $strminutes . ' ' , '0.$1 ' . $strseconds , '$1 ' . $strseconds , '' );
2009-12-18 10:10:04 +00:00
}
2010-07-03 13:37:13 +00:00
2010-08-30 23:45:53 +00:00
$result = preg_replace ( $pattern , $replace , $duration );
2009-12-18 10:10:04 +00:00
return $result ;
}
2011-07-01 22:31:20 +12:00
function scorm_get_toc ( $user , $scorm , $cmid , $toclink = TOCJSLINK , $currentorg = '' , $scoid = '' , $mode = 'normal' , $attempt = '' , $play = false , $tocheader = false ) {
global $CFG , $DB , $PAGE , $OUTPUT ;
$modestr = '' ;
if ( $mode == 'browse' ) {
$modestr = '&mode=' . $mode ;
}
$result = new stdClass ();
if ( $tocheader ) {
$result -> toc = '<div id="scorm_layout">' ;
$result -> toc .= '<div id="scorm_toc">' ;
$result -> toc .= '<div id="scorm_tree">' ;
}
$result -> toc .= '<ul>' ;
$tocmenus = array ();
$result -> prerequisites = true ;
$incomplete = false ;
//
// Get the current organization infos
//
if ( ! empty ( $currentorg )) {
if (( $organizationtitle = $DB -> get_field ( 'scorm_scoes' , 'title' , array ( 'scorm' => $scorm -> id , 'identifier' => $currentorg ))) != '' ) {
if ( $play ) {
$result -> toctitle = " $organizationtitle " ;
}
else {
$result -> toc .= " \t <li> $organizationtitle </li> \n " ;
}
$tocmenus [] = $organizationtitle ;
}
}
//
// If not specified retrieve the last attempt number
//
if ( empty ( $attempt )) {
$attempt = scorm_get_attempt_count ( $user -> id , $scorm );
}
$result -> attemptleft = $scorm -> maxattempt == 0 ? 1 : $scorm -> maxattempt - $attempt ;
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 -> status == '' ) {
$usertrack -> status = 'notattempted' ;
}
$usertracks [ $sco -> identifier ] = $usertrack ;
}
}
}
$level = 0 ;
$sublist = 1 ;
$previd = 0 ;
$nextid = 0 ;
$findnext = false ;
$parents [ $level ] = '/' ;
2011-08-15 16:59:30 +12:00
$prevsco = '' ;
2011-07-01 22:31:20 +12:00
foreach ( $scoes as $pos => $sco ) {
$isvisible = false ;
$sco -> title = $sco -> title ;
if ( ! isset ( $sco -> isvisible ) || ( isset ( $sco -> isvisible ) && ( $sco -> isvisible == 'true' ))) {
$isvisible = true ;
}
if ( $parents [ $level ] != $sco -> parent ) {
2012-05-22 00:47:01 +02:00
$newlevel = array_search ( $sco -> parent , $parents );
if ( $newlevel !== false ) {
2011-07-01 22:31:20 +12:00
for ( $i = 0 ; $i < ( $level - $newlevel ); $i ++ ) {
$result -> toc .= " \t \t </li></ul></li> \n " ;
}
$level = $newlevel ;
} else {
$i = $level ;
$closelist = '' ;
while (( $i > 0 ) && ( $parents [ $level ] != $sco -> parent )) {
2011-07-02 18:59:31 +12:00
if ( $i === 1 && $level > 1 ) {
2011-07-02 14:51:22 +12:00
$closelist .= " \t \t </ul></li> \n " ;
} else {
$closelist .= " \t </li></ul></li> \n " ;
}
2011-07-01 22:31:20 +12:00
$i -- ;
}
if (( $i == 0 ) && ( $sco -> parent != $currentorg )) {
2011-07-02 14:51:22 +12:00
$result -> toc .= " \n \t <ul> \n " ;
2011-07-01 22:31:20 +12:00
$level ++ ;
} else {
$result -> toc .= $closelist ;
$level = $i ;
}
$parents [ $level ] = $sco -> parent ;
}
}
if ( $isvisible ) {
$result -> toc .= " <li> " ;
}
if ( isset ( $scoes [ $pos + 1 ])) {
$nextsco = $scoes [ $pos + 1 ];
} else {
$nextsco = false ;
}
$nextisvisible = false ;
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 ++ ;
}
if ( empty ( $sco -> title )) {
$sco -> title = $sco -> identifier ;
}
2011-07-02 14:51:22 +12:00
if ( $isvisible ) {
if ( ! empty ( $sco -> launch )) {
2011-07-01 22:31:20 +12:00
$score = '' ;
if ( empty ( $scoid ) && ( $mode != 'normal' )) {
$scoid = $sco -> id ;
}
if ( isset ( $usertracks [ $sco -> identifier ])) {
$usertrack = $usertracks [ $sco -> identifier ];
$strstatus = get_string ( $usertrack -> status , 'scorm' );
if ( $sco -> scormtype == 'sco' ) {
$statusicon = '<img src="' . $OUTPUT -> pix_url ( $usertrack -> status , 'scorm' ) . '" alt="' . $strstatus . '" title="' . $strstatus . '" />' ;
} else {
$statusicon = '<img src="' . $OUTPUT -> pix_url ( 'assetc' , 'scorm' ) . '" alt="' . get_string ( 'assetlaunched' , 'scorm' ) . '" title="' . get_string ( 'assetlaunched' , 'scorm' ) . '" />' ;
}
if (( $usertrack -> status == 'notattempted' ) || ( $usertrack -> status == 'incomplete' ) || ( $usertrack -> status == 'browsed' )) {
$incomplete = true ;
if ( $play && empty ( $scoid )) {
$scoid = $sco -> id ;
}
}
if ( $usertrack -> score_raw != '' && has_capability ( 'mod/scorm:viewscores' , get_context_instance ( CONTEXT_MODULE , $cmid ))) {
$score = '(' . get_string ( 'score' , 'scorm' ) . ': ' . $usertrack -> score_raw . ')' ;
}
$strsuspended = get_string ( 'suspended' , 'scorm' );
$exitvar = 'cmi.core.exit' ;
2011-08-15 13:50:06 +12:00
if ( scorm_version_check ( $scorm -> version , SCORM_13 )) {
2011-07-01 22:31:20 +12:00
$exitvar = 'cmi.exit' ;
}
if ( $incomplete && isset ( $usertrack -> { $exitvar }) && ( $usertrack -> { $exitvar } == 'suspend' )) {
$statusicon = '<img src="' . $OUTPUT -> pix_url ( 'suspend' , 'scorm' ) . '" alt="' . $strstatus . ' - ' . $strsuspended . '" title="' . $strstatus . ' - ' . $strsuspended . '" />' ;
}
} else {
if ( $play && empty ( $scoid )) {
$scoid = $sco -> id ;
}
$incomplete = true ;
if ( $sco -> scormtype == 'sco' ) {
$statusicon = '<img src="' . $OUTPUT -> pix_url ( 'notattempted' , 'scorm' ) . '" alt="' . get_string ( 'notattempted' , 'scorm' ) . '" title="' . get_string ( 'notattempted' , 'scorm' ) . '" />' ;
} else {
$statusicon = '<img src="' . $OUTPUT -> pix_url ( 'asset' , 'scorm' ) . '" alt="' . get_string ( 'asset' , 'scorm' ) . '" title="' . get_string ( 'asset' , 'scorm' ) . '" />' ;
}
}
if ( $sco -> id == $scoid ) {
$findnext = true ;
}
if (( $nextid == 0 ) && ( scorm_count_launchable ( $scorm -> id , $currentorg ) > 1 ) && ( $nextsco !== false ) && ( ! $findnext )) {
if ( ! empty ( $sco -> launch )) {
$previd = $sco -> id ;
}
}
2011-08-15 13:50:06 +12:00
if ( scorm_version_check ( $scorm -> version , SCORM_13 )) {
2011-07-01 22:31:20 +12:00
require_once ( $CFG -> dirroot . '/mod/scorm/datamodels/sequencinglib.php' );
$prereq = scorm_seq_evaluate ( $sco -> id , $usertracks );
} else {
//TODO: split check for sco->prerequisites only for AICC as I think that's the only case it's set.
$prereq = empty ( $sco -> prerequisites ) || scorm_eval_prerequisites ( $sco -> prerequisites , $usertracks );
}
if ( $prereq ) {
if ( $sco -> id == $scoid ) {
$result -> prerequisites = true ;
}
2011-08-15 16:59:30 +12:00
if ( ! empty ( $prevsco ) && scorm_version_check ( $scorm -> version , SCORM_13 ) && ! empty ( $prevsco -> hidecontinue )) {
$result -> toc .= '<span>' . $statusicon . ' ' . format_string ( $sco -> title ) . '</span>' ;
} else if ( $toclink == TOCFULLURL ) { //display toc with urls for structure page
2011-07-01 22:31:20 +12:00
$url = $CFG -> wwwroot . '/mod/scorm/player.php?a=' . $scorm -> id . '&currentorg=' . $currentorg . $modestr . '&scoid=' . $sco -> id ;
$result -> toc .= $statusicon . ' <a href="' . $url . '">' . format_string ( $sco -> title ) . '</a>' . $score . " \n " ;
} else { //display toc for inside scorm player
if ( $sco -> launch ) {
$link = 'a=' . $scorm -> id . '&scoid=' . $sco -> id . '¤torg=' . $currentorg . $modestr . '&attempt=' . $attempt ;
$result -> toc .= '<a title="' . $link . '">' . $statusicon . ' ' . format_string ( $sco -> title ) . ' ' . $score . '</a>' ;
} else {
$result -> toc .= '<span>' . $statusicon . ' ' . format_string ( $sco -> title ) . '</span>' ;
}
}
$tocmenus [ $sco -> id ] = scorm_repeater ( '−' , $level ) . '>' . format_string ( $sco -> title );
} else {
if ( $sco -> id == $scoid ) {
$result -> prerequisites = false ;
}
if ( $play ) {
// should be disabled
$result -> toc .= '<span>' . $statusicon . ' ' . format_string ( $sco -> title ) . '</span>' ;
} else {
$result -> toc .= $statusicon . ' ' . format_string ( $sco -> title ) . " \n " ;
}
}
2011-07-02 14:51:22 +12:00
} else {
$result -> toc .= ' ' . format_string ( $sco -> title );
}
if (( $nextsco === false ) || $nextsco -> parent == $sco -> parent ) {
$result -> toc .= " </li> \n " ;
2011-07-01 22:31:20 +12:00
}
}
if (( $nextsco !== false ) && ( $nextid == 0 ) && ( $findnext )) {
if ( ! empty ( $nextsco -> launch )) {
$nextid = $nextsco -> id ;
}
}
2011-08-15 16:59:30 +12:00
$prevsco = $sco ;
2011-07-01 22:31:20 +12:00
}
for ( $i = 0 ; $i < $level ; $i ++ ) {
$result -> toc .= " \t \t </ul></li> \n " ;
}
if ( $play ) {
2011-08-12 17:15:18 +12:00
// it is possible that $scoid is still not set, in this case we don't want an empty object
if ( $scoid ) {
$sco = scorm_get_sco ( $scoid );
2011-07-02 19:45:08 +12:00
}
2011-07-01 22:31:20 +12:00
$sco -> previd = $previd ;
$sco -> nextid = $nextid ;
$result -> sco = $sco ;
$result -> incomplete = $incomplete ;
} else {
$result -> incomplete = $incomplete ;
}
}
$result -> toc .= '</ul>' ;
// NEW IMS TOC
if ( $tocheader ) {
$result -> toc .= '</div></div></div>' ;
$result -> toc .= '<div id="scorm_navpanel"></div>' ;
}
$url = new moodle_url ( '/mod/scorm/player.php?a=' . $scorm -> id . '¤torg=' . $currentorg . $modestr );
2012-04-11 17:18:58 +12:00
$result -> tocmenu = $OUTPUT -> single_select ( $url , 'scoid' , $tocmenus , $sco -> id , null , " tocmenu " );
2011-07-01 22:31:20 +12:00
return $result ;
2011-07-11 19:47:14 +02:00
}